Skip to content

fix: resolve COPILOT_MODEL aliases at runtime before spawning Copilot CLI#44975

Open
pelikhan with Copilot wants to merge 9 commits into
mainfrom
copilot/fix-issue-44260
Open

fix: resolve COPILOT_MODEL aliases at runtime before spawning Copilot CLI#44975
pelikhan with Copilot wants to merge 9 commits into
mainfrom
copilot/fix-issue-44260

Conversation

Copilot AI commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

engine.model aliases (e.g. small, sonnet, copilot, opus?effort=high) compiled correctly but were passed as-is to COPILOT_MODEL, which the Copilot CLI rejected — it only accepts concrete model ids.

Changes

  • resolve_model_alias.cjs (new) — fallback resolution algorithm: loads alias map from awf-config.json (apiProxy.models), builds a concrete catalog from AWF /reflect endpoint data, resolves multi-hop chains with query-param inheritance, and strips the copilot/ prefix for the CLI:

    small → mini → haiku → copilot/claude-haiku-4.5 → claude-haiku-4.5
    
  • copilot_harness.cjs — calls applyCopilotModelAliasResolution() after AWF reflect data is fetched, rewriting process.env.COPILOT_MODEL from alias to concrete id before the CLI is spawned. No-ops when COPILOT_MODEL is already a concrete id.

  • resolve_model_alias.test.cjs (new) — 7 unit tests covering glob matching, version selection, chain resolution, CLI normalization, and end-to-end flow.


Generated by 👨‍🍳 PR Sous Chef · 4.65 AIC · ⌖ 7.58 AIC · ⊞ 7.5K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · 6.21 AIC · ⌖ 8.01 AIC · ⊞ 7.5K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · 11.1 AIC · ⌖ 6.4 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 11, 2026 15:31
… CLI (#44260)

- Add resolve_model_alias.cjs with fallback resolution algorithm
- Add resolve_model_alias.test.cjs with 7 passing tests
- In copilot_harness.cjs: add AWF_CONFIG_PATH, loadAwfConfigData(),
  applyCopilotModelAliasResolution(), and call it in main() after
  AWF reflect data fetch so aliases like 'small' resolve to concrete
  model ids before COPILOT_MODEL is consumed by the CLI

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Remove duplicate aliasMap check in resolveAliasEntry()
- Use __dirname from import.meta.url for robust path resolution in tests

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI requested a review from pelikhan July 11, 2026 15:33
@pelikhan pelikhan marked this pull request as ready for review July 11, 2026 15:57
Copilot AI review requested due to automatic review settings July 11, 2026 15:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Copilot CLI failures by resolving engine.model aliases (e.g. small, sonnet, opus?effort=high) into concrete model IDs at runtime before spawning the Copilot CLI, ensuring COPILOT_MODEL is always a CLI-accepted value.

Changes:

  • Adds a new runtime alias resolution module that loads the alias map, builds a catalog from AWF /reflect, resolves multi-hop alias chains, and normalizes results for the Copilot CLI.
  • Wires alias resolution into copilot_harness.cjs after AWF reflect data is fetched so process.env.COPILOT_MODEL is rewritten before the CLI starts.
  • Adds Vitest unit tests covering glob matching, version selection, alias chain resolution, CLI normalization, and reflect-catalog building.
Show a summary per file
File Description
actions/setup/js/resolve_model_alias.cjs Implements the runtime alias→concrete resolution algorithm and CLI normalization.
actions/setup/js/resolve_model_alias.test.cjs Adds unit tests for the alias resolution and catalog-building logic.
actions/setup/js/copilot_harness.cjs Applies alias resolution to COPILOT_MODEL after AWF reflect data is available, before spawning Copilot CLI.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment thread actions/setup/js/resolve_model_alias.cjs
Comment thread actions/setup/js/resolve_model_alias.test.cjs
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #44975 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

@github-actions github-actions Bot mentioned this pull request Jul 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 83/100 — Excellent

Analyzed 7 test(s): 7 design, 0 implementation, 0 violation(s).

📊 Metrics (7 tests)
Metric Value
Analyzed 7 (Go: 0, JS: 7)
✅ Design 7 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 3 (43%)
Duplicate clusters 0
Inflation No (73 test lines / 309 prod lines = 0.24:1)
🚨 Violations 0
Test File Classification Issues
matches provider-scoped glob patterns case-insensitively resolve_model_alias.test.cjs:16 design_test / high_value Edge: false-branch covered
selects the highest-version glob match resolve_model_alias.test.cjs:21 design_test / high_value Happy-path only
resolves small -> mini -> haiku glob chain resolve_model_alias.test.cjs:26 design_test / high_value Happy-path; no unresolvable alias test
strips copilot/ prefix for native CLI env var resolve_model_alias.test.cjs:31 design_test / high_value Happy-path only
resolveConfiguredCopilotModel rewrites alias when reflect catalog is available resolve_model_alias.test.cjs:35 design_test / high_value Happy-path only
leaves concrete configured models unchanged resolve_model_alias.test.cjs:54 design_test / high_value Edge: pass-through behaviour
buildCatalogFromReflect includes provider-scoped entries resolve_model_alias.test.cjs:66 design_test / high_value Happy-path only

Verdict

Passed. 0% implementation tests (threshold: 30%). No guideline violations. Minor gap: no tests for unresolvable aliases, empty catalogs, or null reflectData — consider adding for robustness.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 30.5 AIC · ⌖ 13.2 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 83/100. 0% implementation tests (threshold: 30%).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — requesting changes on three items.

📋 Key Themes & Highlights

Issues

  • Silent error swallowing (loadAwfConfigData): JSON parse errors on a malformed config file are swallowed with no log output, making debugging very hard.
  • globMatch bare-wildcard gap: single-segment wildcard patterns (no /) are treated as exact equality. All current aliases use provider/*...* so this is latent, but it is a correctness gap.
  • Missing opusplan test: the query-param inheritance chain (opusplan → opus?effort=high → copilot/*opus*) is the most complex path and is not covered.

Positive Highlights

  • ✅ Multi-hop alias resolution algorithm is well-structured and correctly handles circular reference detection
  • mergeParams correctly gives caller params priority over entry params (spec §8.3 step 2b ii)
  • resolveConfiguredCopilotModel is a clean, deep module: simple entry point, rich behaviour inside
  • ✅ Good use of early-return no-ops when the model is already concrete

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 48.6 AIC · ⌖ 4.82 AIC · ⊞ 6.6K
Comment /matt to run again

Comment thread actions/setup/js/resolve_model_alias.cjs
Comment thread actions/setup/js/resolve_model_alias.cjs
Comment thread actions/setup/js/resolve_model_alias.test.cjs
Comment thread actions/setup/js/resolve_model_alias.test.cjs

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: resolve COPILOT_MODEL aliases at runtime

Good implementation overall — the multi-hop alias chain, query-param inheritance, and Copilot CLI normalization are all handled cleanly, and the harness integration is minimal and well-placed.

One correctness gap (non-blocking): globMatch silently degrades to exact equality for single-segment patterns that contain *. All current alias entries have provider prefixes so nothing breaks today, but bare-wildcard entries would fail silently. See inline comment for a suggested fix.

All other logic looks correct — circular-alias guard, catalog-empty early exit, and resolveAliasEntry fallback ordering are all sound.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 30.2 AIC · ⌖ 4.47 AIC · ⊞ 4.8K

Comment thread actions/setup/js/resolve_model_alias.cjs

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — 4 correctness bugs + broken test suite

The logic is well-structured and the overall design is sound, but there are four issues that must be fixed before merge.

Blocking issues (in priority order)
  1. Test file is unparseable (resolve_model_alias.test.cjs): ES module import syntax in a .cjs file is a SyntaxError — all 7 tests fail before any test runs. Rename to .test.mjs or convert to require().

  2. globMatch bare patterns never wildcard (resolve_model_alias.cjs line 145): single-segment patterns fall through to exact string equality, so any alias entry without a / (e.g. claude-*) silently fails to match anything.

  3. Date-stamped model version ordering is inverted (resolve_model_alias.cjs line 175): extractVersionTuple takes the last numeric run, so gpt-4o-2024-08-06[6] ranks lower than gpt-4o-2024-05-13[13], selecting an older model as "latest".

  4. Diamond alias graphs fail with a false circular-reference error (resolve_model_alias.cjs line 265): the visited Set is shared across all recursive branches; a second path converging on a previously-visited alias key is incorrectly rejected. Fix: clone the set when passing to each sibling entry.

Non-blocking: loadAwfConfigData should distinguish ENOENT (expected) from malformed JSON (unexpected, should log).

🔎 Code quality review by PR Code Quality Reviewer · 57.7 AIC · ⌖ 5.12 AIC · ⊞ 5.4K
Comment /review to run again

Comments that could not be inline-anchored

actions/setup/js/resolve_model_alias.test.cjs:1

All 7 tests are dead on arrival: .cjs files are always parsed as CommonJS by Node.js, and ES module import declarations are a SyntaxError in that context — the entire suite will fail to parse.

<details>
<summary>💡 Fix</summary>

Either rename to .test.mjs (or .test.js if the package is already &quot;type&quot;: &quot;module&quot;), or replace all ESM imports with CommonJS require():

const { describe, it, expect } = require(&#39;vitest&#39;);
const fs = require(&#39;fs&#39;);
const path = require(&#39;path&#39;);


</details>

<details><summary>actions/setup/js/resolve_model_alias.cjs:145</summary>

**`globMatch` never wildcards a bare (non-scoped) pattern**: when `pattern` contains no `/`, the function falls through to a plain string equality check — wildcard characters in the pattern are never expanded.

&lt;details&gt;
&lt;summary&gt;💡 Detail + fix&lt;/summary&gt;

Current code (line 144–145):
```js
if (patternParts.length === 1) {
  return pattern.toLowerCase() === entry.toLowerCase();  // ← exact match, no glob
}

An alias entry like &quot;claude-*&quot; or &quot;*haiku*&quot; will never match any catalog entry, …

actions/setup/js/resolve_model_alias.cjs:175

Date-stamped model names sort in wrong recency order: extractVersionTuple takes the last numeric run, so gpt-4o-2024-08-06[6] while gpt-4o-2024-05-13[13], making the May snapshot sort higher than the August one.

<details>
<summary>💡 Detail + fix</summary>

The regex /(\d+(?:\.\d+)*)/g collects runs of digits separated by .; the hyphens in a date like 2024-08-06 are not dots, so it produces four separate single-number matches: [&#39;4&#39;,&#39;2024&#39;,&#39;08&#39;,&#39;06&#39;]. Taking the la…

actions/setup/js/resolve_model_alias.cjs:265

Diamond alias graphs silently fail: the shared visited Set causes a second convergent path to the same alias key to be misidentified as a circular reference and return null.

<details>
<summary>💡 Detail + fix</summary>

visited is allocated once per top-level resolveModelAlias call (line 256) and passed by reference through all recursion. Consider an alias map:

{ &quot;small&quot;: [&quot;mini&quot;], &quot;mini&quot;: [&quot;haiku&quot;], &quot;tiny&quot;: [&quot;mini&quot;] }

If smallmini succeeds, mini is added to …

actions/setup/js/copilot_harness.cjs:27

Malformed awf-config.json silently skips alias resolution with no diagnostic: the catch block returns null for any error, including JSON.SyntaxError, making a corrupted config file invisible to operators.

<details>
<summary>💡 Fix</summary>

function loadAwfConfigData() {
  try {
    return JSON.parse(fs.readFileSync(AWF_CONFIG_PATH, &#39;utf8&#39;));
  } catch (err) {
    if (err.code !== &#39;ENOENT&#39;) {
      // File exists but is unreadable or malformed — surface the problem
      log(`

</details>

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the unresolved review feedback below, and rerun checks when done.

Unresolved review feedback to address:

Generated by 👨‍🍳 PR Sous Chef · 22.6 AIC · ⌖ 7.57 AIC · ⊞ 4.2K ·
Comment /souschef to run again

…fix glob wildcards, log config errors, add tests

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address the unresolved review feedback below, and rerun checks when done.

Unresolved review feedback to address:...

All 7 unresolved review threads addressed in commit fix: address all review feedback...:

  • r3564537564 / r3564537592resolveConfiguredCopilotModel now applies normalizeForCopilotCLI in both early-return paths (no alias map, and not an alias key), so provider-qualified ids like copilot/claude-haiku-4.5 are always stripped to bare claude-haiku-4.5 before reaching the CLI. Two new end-to-end tests cover this.
  • r3564594989 / r3564596252globMatch single-segment branch now applies glob regex for patterns containing *; exact equality only for literal patterns.
  • r3564594993loadAwfConfigData logs a warning (awf-config load error: <msg>) for non-ENOENT parse failures so operators can debug malformed configs.
  • r3564594995 — Test file imports converted from import fs/path/url to require("fs")/require("path")/require("url"), matching the action_input_utils.test.cjs style.
  • r3564594999 — Added test asserting resolveModelAlias("opusplan", ...) resolves to copilot/claude-opus-4.5?effort=high.

All 214 JS tests pass locally.

Copilot AI requested a review from gh-aw-bot July 11, 2026 17:18
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smoke test review: inline comment flow exercised.

Warning

Firewall blocked 5 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · 120.7 AIC · ⌖ 4.96 AIC · ⊞ 19.8K
Comment /smoke-copilot to run again
Add label smoke to run again

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot fix must be applied to detection harness as well

https://github.com/github/gh-aw/actions/runs/29186015811/job/86632400530#step:17:1

The threat detection job ran on a separate fresh runner with its own
minimal awf-config.json that was missing the apiProxy.models alias map.
When copilot_harness.cjs tried to resolve `COPILOT_MODEL=small`, the
alias map was null so normalizeForCopilotCLI returned "small" unchanged,
causing the CLI to reject it as unsupported.

Fix: propagate data.ModelMappings into the threatDetectionData struct
so BuildAWFConfigJSON includes the full model alias map in the detection
step's awf-config.json, matching what the agent step already emits.

Also:
- Update outdated workflow_data.go comment (ModelMappings IS emitted)
- Add regression test TestBuildDetectionEngineExecutionStepPropagatesModelMappings

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix must be applied to detection harness as well

https://github.com/github/gh-aw/actions/runs/29186015811/job/86632400530#step:17:1

Fixed in the latest commit.

Root cause: threatDetectionData in threat_detection_inline_engine.go was constructed without ModelMappings: data.ModelMappings. Since BuildAWFConfigJSON only adds apiProxy.models when WorkflowData.ModelMappings is non-empty, the detection step's awf-config.json had no models section. When copilot_harness.cjs loaded that config, aliasMap was null, so resolveConfiguredCopilotModel("small", ...) couldn't resolve the alias chain and returned "small" unchanged — causing the CLI rejection you saw.

Fix: Added ModelMappings: data.ModelMappings to the threatDetectionData struct so both agent and detection steps emit the full alias map in their awf-config.json. Also added a regression test (TestBuildDetectionEngineExecutionStepPropagatesModelMappings) and updated an outdated comment in workflow_data.go.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29187567992

Generated by 👨‍🍳 PR Sous Chef · 6.21 AIC · ⌖ 8.01 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29187567992...

Branch merged with main (resolved 162 lock file conflicts by taking main's versions and recompiling). Local validation passes:

  • make fmt
  • make lint ✅ (0 errors, 52 alias chains validated)
  • make test-unit ✅ (all Go + JS tests pass)
  • make recompile ✅ (256/256 workflows compiled)

All 7 review threads remain resolved. CI needs to be re-triggered by a maintainer.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback still open on this PR, and rerun checks once the branch is ready.

Run: https://github.com/github/gh-aw/actions/runs/29190625506

Generated by 👨‍🍳 PR Sous Chef · 13 AIC · ⌖ 6.51 AIC · ⊞ 4.2K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback still open on this PR, and rerun checks once the branch is ready.

Run: https://github.com/github/gh-aw/actions/runs...

Branch is up to date with main (merged in the previous session). All 7 review threads are resolved. Local validation passes: make fmt ✅, make lint ✅ (0 errors, 52 alias chains validated), make test-unit ✅. CI smoke check is currently running on HEAD 03ef0d0.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29192100649

Generated by 👨‍🍳 PR Sous Chef · 7.72 AIC · ⌖ 5.14 AIC · ⊞ 4.2K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29192100649...

Branch is up to date with main, all 7 review threads remain resolved, and local validation passes: make fmt ✅, make lint ✅ (0 issues, 52 alias chains validated), make test-unit ✅. A smoke check is currently in_progress on HEAD 03ef0d0 (run 29192321383); the previous smoke run (29190873355) concluded success. No file changes were needed this pass.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category bug
Risk 🔴 High
Score 78/100 (impact: 40, urgency: 25, quality: 13)
Action fast_track

COPILOT_MODEL alias resolution fix. Large change (+706/-165). CI passed ✅. High-priority runtime bug — fast track.

Generated by 🔧 PR Triage Agent · 48.3 AIC · ⌖ 7.99 AIC · ⊞ 5.6K ·

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address these unresolved review comments:

All 7 review threads are already resolved (is_resolved: true per the GitHub API). Branch is up to date with main and local validation passes: make fmt ✅, make lint ✅, make test-unit ✅. No changes were needed this pass — CI needs a human re-trigger to confirm green on HEAD 03ef0d0.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29199165277

Generated by 👨‍🍳 PR Sous Chef · 4.72 AIC · ⌖ 4.27 AIC · ⊞ 4.2K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29199165277...

All 7 review threads remain resolved. Branch is up to date with main. CI smoke checks are green: runs 29192321383 and 29197646421 both concluded success. A new smoke run (29199434032) is currently in_progress. No changes needed — PR is ready for merge once that run completes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants