From b64283265261dee162acf9f2047d6d1b0436af4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 4 May 2026 04:36:29 +0000 Subject: [PATCH 1/3] Initial plan From 1bef1f29516fdc7413f531ce0b9f9106ec267078 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 4 May 2026 04:41:32 +0000 Subject: [PATCH 2/3] chore: initial plan for billing multipliers addition Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5d448e96-d4d8-42fd-bf37-addb06bb931f Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/actionpins/data/action_pins.json | 15 +++++++++++++++ pkg/workflow/data/action_pins.json | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/pkg/actionpins/data/action_pins.json b/pkg/actionpins/data/action_pins.json index 8a76c8303d5..1c1d3e4cd89 100644 --- a/pkg/actionpins/data/action_pins.json +++ b/pkg/actionpins/data/action_pins.json @@ -38,6 +38,11 @@ "version": "v5.0.5", "sha": "27d5ce7f107fe9357f9df03efb73ab90386fccae" }, + "actions/cache/save@v4": { + "repo": "actions/cache/save", + "version": "v4", + "sha": "0057852bfaa89a56745cba8c7296529d2fc39830" + }, "actions/cache/save@v5.0.5": { "repo": "actions/cache/save", "version": "v5.0.5", @@ -48,6 +53,11 @@ "version": "v5.0.5", "sha": "27d5ce7f107fe9357f9df03efb73ab90386fccae" }, + "actions/checkout@v4": { + "repo": "actions/checkout", + "version": "v4", + "sha": "34e114876b0b11c390a56381ad16ebd13914f8d5" + }, "actions/checkout@v6.0.2": { "repo": "actions/checkout", "version": "v6.0.2", @@ -88,6 +98,11 @@ "version": "v6.4.0", "sha": "48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" }, + "actions/setup-python@v5": { + "repo": "actions/setup-python", + "version": "v5", + "sha": "a26af69be951a213d495a4c3e4e4022e16d87065" + }, "actions/setup-python@v6.2.0": { "repo": "actions/setup-python", "version": "v6.2.0", diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index 8a76c8303d5..1c1d3e4cd89 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -38,6 +38,11 @@ "version": "v5.0.5", "sha": "27d5ce7f107fe9357f9df03efb73ab90386fccae" }, + "actions/cache/save@v4": { + "repo": "actions/cache/save", + "version": "v4", + "sha": "0057852bfaa89a56745cba8c7296529d2fc39830" + }, "actions/cache/save@v5.0.5": { "repo": "actions/cache/save", "version": "v5.0.5", @@ -48,6 +53,11 @@ "version": "v5.0.5", "sha": "27d5ce7f107fe9357f9df03efb73ab90386fccae" }, + "actions/checkout@v4": { + "repo": "actions/checkout", + "version": "v4", + "sha": "34e114876b0b11c390a56381ad16ebd13914f8d5" + }, "actions/checkout@v6.0.2": { "repo": "actions/checkout", "version": "v6.0.2", @@ -88,6 +98,11 @@ "version": "v6.4.0", "sha": "48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" }, + "actions/setup-python@v5": { + "repo": "actions/setup-python", + "version": "v5", + "sha": "a26af69be951a213d495a4c3e4e4022e16d87065" + }, "actions/setup-python@v6.2.0": { "repo": "actions/setup-python", "version": "v6.2.0", From 786e0132aeb4776643e9018a7e4520c599a05505 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 4 May 2026 04:48:47 +0000 Subject: [PATCH 3/3] feat: add collect_copilot_billing_multipliers job to daily-model-inventory workflow Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5d448e96-d4d8-42fd-bf37-addb06bb931f Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../workflows/daily-model-inventory.lock.yml | 146 ++++++++++++++++-- .github/workflows/daily-model-inventory.md | 119 +++++++++++++- 2 files changed, 245 insertions(+), 20 deletions(-) diff --git a/.github/workflows/daily-model-inventory.lock.yml b/.github/workflows/daily-model-inventory.lock.yml index 17dea9dd303..44b63278c67 100644 --- a/.github/workflows/daily-model-inventory.lock.yml +++ b/.github/workflows/daily-model-inventory.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"f21ab11a6327065b578fd5bc3d793f8ef9c65897ce0ad098ee2ef79aa89dd831","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"02091f9aef207d6856329f85921dba158a2db7dc2d1014ce3d88d7eaea4beb39","strict":true,"agent_id":"copilot"} # gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","COPILOT_GITHUB_TOKEN","GEMINI_API_KEY","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_ENDPOINT","GH_AW_OTEL_HEADERS","GITHUB_TOKEN","OPENAI_API_KEY"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.35"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.35"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.35"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.3"},{"image":"ghcr.io/github/github-mcp-server:v1.0.3","digest":"sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.3@sha256:2ac27ef03461ef2b877031b838a7d1fd7f12b12d4ace7796d8cad91446d55959"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) @@ -196,20 +196,21 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_4a6ca60e30f7d81d_EOF' + cat << 'GH_AW_PROMPT_d4e4560568e99794_EOF' - GH_AW_PROMPT_4a6ca60e30f7d81d_EOF + GH_AW_PROMPT_d4e4560568e99794_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/playwright_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_4a6ca60e30f7d81d_EOF' + cat << 'GH_AW_PROMPT_d4e4560568e99794_EOF' Tools: create_issue, missing_tool, missing_data, noop - GH_AW_PROMPT_4a6ca60e30f7d81d_EOF + GH_AW_PROMPT_d4e4560568e99794_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_4a6ca60e30f7d81d_EOF' + cat << 'GH_AW_PROMPT_d4e4560568e99794_EOF' The following GitHub context information is available for this workflow: {{#if __GH_AW_GITHUB_ACTOR__ }} @@ -238,15 +239,15 @@ jobs: {{/if}} - GH_AW_PROMPT_4a6ca60e30f7d81d_EOF + GH_AW_PROMPT_d4e4560568e99794_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_4a6ca60e30f7d81d_EOF' + cat << 'GH_AW_PROMPT_d4e4560568e99794_EOF' {{#runtime-import .github/workflows/shared/otel.md}} {{#runtime-import .github/workflows/shared/observability-otlp.md}} {{#runtime-import .github/workflows/shared/noop-reminder.md}} {{#runtime-import .github/workflows/daily-model-inventory.md}} - GH_AW_PROMPT_4a6ca60e30f7d81d_EOF + GH_AW_PROMPT_d4e4560568e99794_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -323,6 +324,7 @@ jobs: needs: - activation - collect_anthropic_models + - collect_copilot_billing_multipliers - collect_copilot_models - collect_gemini_models - collect_openai_models @@ -435,6 +437,10 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.35 + - name: Install Playwright CLI + run: npm install -g @playwright/cli@0.1.11 + - name: Install Playwright CLI skills + run: playwright-cli install --skills - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 @@ -463,9 +469,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_69cda9a2cf8d5ae3_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_ff5f5cdf0faea0b8_EOF' {"create_issue":{"close_older_issues":true,"expires":168,"labels":["automation","models"],"max":1,"title_prefix":"[model-inventory] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_69cda9a2cf8d5ae3_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_ff5f5cdf0faea0b8_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -667,7 +673,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_b6996925c5de5be4_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_9505bace89d8359e_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { @@ -714,7 +720,7 @@ jobs: } } } - GH_AW_MCP_CONFIG_b6996925c5de5be4_EOF + GH_AW_MCP_CONFIG_9505bace89d8359e_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -741,6 +747,7 @@ jobs: # Copilot CLI tool arguments (sorted): # --allow-tool github # --allow-tool safeoutputs + # --allow-tool shell(cat /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json) # --allow-tool shell(cat /tmp/gh-aw/model-inventory/inventory.json) # --allow-tool shell(cat pkg/cli/data/model_multipliers.json) # --allow-tool shell(cat pkg/workflow/model_aliases.go) @@ -752,6 +759,7 @@ jobs: # --allow-tool shell(head) # --allow-tool shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/models.json) # --allow-tool shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/raw.json) + # --allow-tool shell(jq . /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json) # --allow-tool shell(jq . /tmp/gh-aw/model-inventory/inventory.json) # --allow-tool shell(jq) # --allow-tool shell(ls) @@ -770,10 +778,10 @@ jobs: GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) export GH_AW_NODE_BIN (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.35/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.35"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.35/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","cdn.playwright.dev","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","playwright.download.prss.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true},"container":{"imageTag":"0.25.35"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json # shellcheck disable=SC1003 sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat /tmp/gh-aw/model-inventory/inventory.json)'\'' --allow-tool '\''shell(cat pkg/cli/data/model_multipliers.json)'\'' --allow-tool '\''shell(cat pkg/workflow/model_aliases.go)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find /tmp/gh-aw/model-inventory -type f)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/models.json)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/raw.json)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/inventory.json)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || echo node)"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json)'\'' --allow-tool '\''shell(cat /tmp/gh-aw/model-inventory/inventory.json)'\'' --allow-tool '\''shell(cat pkg/cli/data/model_multipliers.json)'\'' --allow-tool '\''shell(cat pkg/workflow/model_aliases.go)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find /tmp/gh-aw/model-inventory -type f)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/models.json)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/artifacts/*/raw.json)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json)'\'' --allow-tool '\''shell(jq . /tmp/gh-aw/model-inventory/inventory.json)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_API_KEY: dummy-byok-key-for-offline-mode @@ -860,7 +868,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -1030,6 +1038,109 @@ jobs: /tmp/gh-aw/model-inventory/anthropic/raw.json retention-days: 7 + collect_copilot_billing_multipliers: + needs: activation + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash + run: | + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Fetch Copilot billing multipliers + id: fetch + run: | + set -euo pipefail + OUT="/tmp/gh-aw/model-inventory/copilot-billing" + mkdir -p "$OUT" + python3 - <<'PYEOF' + import json, sys, urllib.request, html.parser + + # NOTE: If GitHub's documentation URL structure changes, this URL must be updated manually. + URL = "https://docs.github.com/en/copilot/reference/copilot-billing/model-multipliers-for-annual-plans" + + class TableParser(html.parser.HTMLParser): + def __init__(self): + super().__init__() + self.in_table = False + self.headers = [] + self.rows = [] + self.current_row = [] + self.current_cell = None + self.cell_text = [] + + def handle_starttag(self, tag, attrs): + if tag == "table": + self.in_table = True + elif self.in_table and tag in ("th", "td"): + self.current_cell = tag + self.cell_text = [] + elif self.in_table and tag == "tr": + self.current_row = [] + + def handle_endtag(self, tag): + if tag == "table": + self.in_table = False + elif self.in_table and tag in ("th", "td"): + text = "".join(self.cell_text).strip() + if self.current_cell == "th": + self.headers.append(text) + else: + self.current_row.append(text) + self.current_cell = None + elif self.in_table and tag == "tr": + if self.current_row: + self.rows.append(self.current_row) + + def handle_data(self, data): + if self.current_cell is not None: + self.cell_text.append(data) + + req = urllib.request.Request(URL, headers={"User-Agent": "Mozilla/5.0"}) + try: + with urllib.request.urlopen(req, timeout=30) as resp: + html_content = resp.read().decode("utf-8", errors="replace") + except Exception as e: + result = {"source": URL, "error": str(e), "headers": [], "models": []} + with open("/tmp/gh-aw/model-inventory/copilot-billing/multipliers.json", "w") as f: + json.dump(result, f, indent=2) + print(f"Error fetching page: {e}", file=sys.stderr) + sys.exit(0) + + parser = TableParser() + parser.feed(html_content) + + models = [] + if parser.headers and parser.rows: + for row in parser.rows: + if len(row) == len(parser.headers): + entry = {parser.headers[i]: row[i] for i in range(len(parser.headers))} + models.append(entry) + + result = {"source": URL, "headers": parser.headers, "models": models} + out_path = "/tmp/gh-aw/model-inventory/copilot-billing/multipliers.json" + with open(out_path, "w") as f: + json.dump(result, f, indent=2) + print(f"Extracted {len(models)} model multiplier entries", file=sys.stderr) + PYEOF + echo "status=ok" >> "$GITHUB_OUTPUT" + shell: bash + - name: Upload Copilot billing multipliers artifact + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + if-no-files-found: error + name: copilot-billing-multipliers + path: /tmp/gh-aw/model-inventory/copilot-billing/multipliers.json + retention-days: 7 + collect_copilot_models: needs: activation runs-on: ubuntu-latest @@ -1225,6 +1336,7 @@ jobs: - activation - agent - collect_anthropic_models + - collect_copilot_billing_multipliers - collect_copilot_models - collect_gemini_models - collect_openai_models @@ -1651,7 +1763,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"expires\":168,\"labels\":[\"automation\",\"models\"],\"max\":1,\"title_prefix\":\"[model-inventory] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" diff --git a/.github/workflows/daily-model-inventory.md b/.github/workflows/daily-model-inventory.md index 9cd2e79c2d4..6116d3d935f 100644 --- a/.github/workflows/daily-model-inventory.md +++ b/.github/workflows/daily-model-inventory.md @@ -234,6 +234,100 @@ jobs: if-no-files-found: error retention-days: 7 + collect_copilot_billing_multipliers: + runs-on: ubuntu-latest + needs: [activation] + permissions: + contents: read + steps: + - name: Fetch Copilot billing multipliers + id: fetch + shell: bash + run: | + set -euo pipefail + OUT="/tmp/gh-aw/model-inventory/copilot-billing" + mkdir -p "$OUT" + python3 - <<'PYEOF' + import json, sys, urllib.request, html.parser + + # NOTE: If GitHub's documentation URL structure changes, this URL must be updated manually. + URL = "https://docs.github.com/en/copilot/reference/copilot-billing/model-multipliers-for-annual-plans" + + class TableParser(html.parser.HTMLParser): + def __init__(self): + super().__init__() + self.in_table = False + self.headers = [] + self.rows = [] + self.current_row = [] + self.current_cell = None + self.cell_text = [] + + def handle_starttag(self, tag, attrs): + if tag == "table": + self.in_table = True + elif self.in_table and tag in ("th", "td"): + self.current_cell = tag + self.cell_text = [] + elif self.in_table and tag == "tr": + self.current_row = [] + + def handle_endtag(self, tag): + if tag == "table": + self.in_table = False + elif self.in_table and tag in ("th", "td"): + text = "".join(self.cell_text).strip() + if self.current_cell == "th": + self.headers.append(text) + else: + self.current_row.append(text) + self.current_cell = None + elif self.in_table and tag == "tr": + if self.current_row: + self.rows.append(self.current_row) + + def handle_data(self, data): + if self.current_cell is not None: + self.cell_text.append(data) + + req = urllib.request.Request(URL, headers={"User-Agent": "Mozilla/5.0"}) + try: + with urllib.request.urlopen(req, timeout=30) as resp: + html_content = resp.read().decode("utf-8", errors="replace") + except Exception as e: + result = {"source": URL, "error": str(e), "headers": [], "models": []} + with open("/tmp/gh-aw/model-inventory/copilot-billing/multipliers.json", "w") as f: + json.dump(result, f, indent=2) + print(f"Error fetching page: {e}", file=sys.stderr) + sys.exit(0) + + parser = TableParser() + parser.feed(html_content) + + models = [] + if parser.headers and parser.rows: + for row in parser.rows: + if len(row) == len(parser.headers): + entry = {parser.headers[i]: row[i] for i in range(len(parser.headers))} + models.append(entry) + + result = {"source": URL, "headers": parser.headers, "models": models} + out_path = "/tmp/gh-aw/model-inventory/copilot-billing/multipliers.json" + with open(out_path, "w") as f: + json.dump(result, f, indent=2) + print(f"Extracted {len(models)} model multiplier entries", file=sys.stderr) + PYEOF + echo "status=ok" >> "$GITHUB_OUTPUT" + + - name: Upload Copilot billing multipliers artifact + if: always() + uses: actions/upload-artifact@v7.0.1 + with: + name: copilot-billing-multipliers + path: /tmp/gh-aw/model-inventory/copilot-billing/multipliers.json + if-no-files-found: error + retention-days: 7 + steps: - name: Download all model artifacts uses: actions/download-artifact@v8.0.1 @@ -250,6 +344,8 @@ steps: tools: cli-proxy: true + playwright: + mode: cli bash: - "cat /tmp/gh-aw/model-inventory/inventory.json" - "jq . /tmp/gh-aw/model-inventory/inventory.json" @@ -262,6 +358,9 @@ tools: - "jq '[.data[] | .capabilities | keys] | add | unique' /tmp/gh-aw/model-inventory/artifacts/copilot-models/raw.json" - "jq '[.data[] | select(.billing != null)] | length' /tmp/gh-aw/model-inventory/artifacts/copilot-models/raw.json" - "jq '.data[] | {id, billing}' /tmp/gh-aw/model-inventory/artifacts/copilot-models/raw.json" + - "cat /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json" + - "jq . /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json" + - "jq '.models[]' /tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json" - "find /tmp/gh-aw/model-inventory -type f" - "cat pkg/workflow/model_aliases.go" - "cat pkg/cli/data/model_multipliers.json" @@ -368,11 +467,25 @@ inventories. Read the current built-in multiplier table from `pkg/cli/data/model_multipliers.json`. +The pre-job step has also fetched the **official GitHub Copilot billing multipliers** from the +documentation page and stored them as: + +- `/tmp/gh-aw/model-inventory/artifacts/copilot-billing-multipliers/multipliers.json` + +This file contains the authoritative ET multipliers per model extracted from +`https://docs.github.com/en/copilot/reference/copilot-billing/model-multipliers-for-annual-plans`, +with columns `Model`, `Current multiplier`, and `New multiplier`. + +**Use the docs table as the primary (authoritative) source of ET multipliers.** Prefer the +**New multiplier** column for upcoming billing schedule comparisons. If the docs table fetch +failed or returned an empty model list, fall back to the heuristics below. + For each provider's enriched data, attempt to infer or validate the ET multiplier for each model: -1. **Copilot API** — if `billing.multiplier` (or a similar field) is present in the raw response, - use it directly. Compare against the matching entry in `model_multipliers.json`. List any - discrepancies or missing models. +1. **Copilot API** — match model names/IDs against the official docs table first. If a match is + found, use the `New multiplier` as the authoritative value. Also check `billing.multiplier` + (or a similar field) in the raw Copilot API response as a secondary source. Compare both + against the matching entry in `model_multipliers.json`. List any discrepancies or missing models. 2. **Gemini API** — use `inputTokenLimit` / `outputTokenLimit` as an approximate proxy for model complexity (this is an inference heuristic, not a definitive billing mapping).