Repository navigation
Resolve Copilot sub-agent models in the harness (CLI and SDK) and fail closed - #70389
Conversation
Co-authored-by: SivaKesava1 <11771739+SivaKesava1@users.noreply.github.com>
Co-authored-by: SivaKesava1 <11771739+SivaKesava1@users.noreply.github.com>
|
🔬 Test Quality Sentinel is analyzing test quality on this pull request... |
|
✅ PR Code Quality Reviewer completed the code quality review. Warning threat detection engine error What happenedThe threat detection engine failed to produce results. Review the workflow run logs for details.
|
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ Warning threat detection engine error What happenedThe threat detection engine failed to produce results. Review the workflow run logs for details.
|
|
✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft. Warning threat detection engine error What happenedThe threat detection engine failed to produce results. Review the workflow run logs for details. Design Decision Gate 🏗️Outcome: The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible. Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.
|
|
✅ Ponytail Reviewer completed successfully! Ponytail ReviewerOutcome: The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible. Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.
|
There was a problem hiding this comment.
Warning
threat detection engine error
The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.
What happened
The threat detection engine failed to produce results.
Review the workflow run logs for details.
Request changes
The preflight introduces two correctness regressions: CLI discovery is broader than the actual custom-agent loader and can reject unrelated .md files, and model resolution runs before the noop short-circuit, so completed/no-op workflows can fail on an agent model they would never use. Both should be fixed before merge.
Findings
- Restrict CLI discovery to
.agent.mdfiles, matching the SDK loader. - Move CLI sub-agent resolution after the noop safe-output check.
The advisory first-pass reviewer did not return parseable findings; this review is based on independent inspection of the changed lines.
🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · 4.17 AIC · ⊞ 1.6K
Comment /review to run again
There was a problem hiding this comment.
Warning
threat detection engine error
The threat detection engine encountered an error and could not complete analysis. This is a tooling failure, not a security finding.
What happened
The threat detection engine failed to produce results.
Review the workflow run logs for details.
Skills-Based Review 🧠
Applied /codebase-design and /tdd to the new sub-agent model resolution logic. The overall approach (collect all failures before throwing, fail-closed instead of silent fallback) is solid and well-tested with ~15 new test cases, but two issues should be addressed before merge.
📋 Key Themes & Highlights
Key Findings
- Inconsistent agent-file filter (
/codebase-design):listCopilotAgentFiles(CLI mode,copilot_harness.cjs:677) matches any*.md, whileloadCopilotSDKCustomAgents(SDK mode) and the docs both treat*.agent.mdas the canonical extension. This repo's own.github/agents/directory already contains non-agent.mdfiles (developer.instructions.md,agentic-workflows.md) that would be swept up by the CLI-mode path but ignored by SDK mode — a real behavioral divergence introduced by this PR. - Untested fail-closed branch (
/tdd):hideTrackedAgentFileRewrite's failure path (git command errors) drives the restore-and-exit(1) safety guarantee inapplyCopilotCLISubagentModels, but only the success path is covered by tests ("case 6, CLI, tracked file"). Given this is explicitly called out in the PR description as a safety guarantee, the failure branch deserves direct coverage.
Positive Highlights
- ✅
resolveCopilotSubagentModelscorrectly collects every failing sub-agent'smodel.resolutionrecord before throwing the first failure — matches the PR's stated goal of full diagnostics on fail-closed exit. - ✅ The SDK-mode throw-on-unresolvable-model change is properly caught by
runWithCopilotSDK's existing try/catch and converted toexitCode: 1, verified against the new test's expectations. - ✅ Strong test coverage overall: alias resolution, dead models, refresh behavior, SDK qualification, and git skip-worktree protection are all exercised.
- ✅ Docs (
engines.md) accurately describe the new fail-closed behavior.
Inline comments posted on both findings with suggested fixes.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 174.3 AIC · ⊞ 10.2K
Comment /matt to run again
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved correctness defects affect model selection, startup validation, and preservation of repository changes.
9 open issues
Replace complete multiline YAML model scalar · New Preserve inherited model sentinel semantics · New Preserve provider scope during model qualification · New Record qualification exceptions as resolution failures · New Refresh SDK provider configuration after catalogue updates · New Discover agents from the effective engine working directory · New Preserve tracked agent edits after skip-worktree use · New Distinguish Git tracking failures from untracked files · New Verify skip-worktree was successfully applied · New
What changed in this PR
Moves Copilot sub-agent model resolution into the gh-aw harness, enabling startup validation and recorded model decisions in CLI and SDK modes.
Changes:
- Resolves aliases and checks live model availability, including routed runs.
- Rewrites CLI model fields and passes resolved SDK models without silent fallback.
- Adds catalogue fixtures, regression coverage, and documentation.
| File | Description |
|---|---|
| docs/src/content/docs/reference/engines.md | Documents resolution and fail-closed behavior. |
| actions/setup/js/fixtures/awf-reflect-copilot-sub-agents-39304573724.json | Adds recorded model catalogue. |
| actions/setup/js/fixtures/awf-config-models-copilot-sub-agents-39304573724.json | Adds recorded alias configuration. |
| actions/setup/js/copilot_sdk_session.test.cjs | Supplies harness-resolved test models. |
| actions/setup/js/copilot_sdk_session.cjs | Consumes resolved models and removes fallback. |
| actions/setup/js/copilot_sdk_driver.test.cjs | Tests resolved models and startup rejection. |
| actions/setup/js/copilot_sdk_driver.cjs | Documents the model-handoff environment variable. |
| actions/setup/js/copilot_harness.test.cjs | Covers resolution, rewriting, and startup behavior. |
| actions/setup/js/copilot_harness.cjs | Implements sub-agent validation and model handoff. |
Review effort: Max
|
@copilot address the following outstanding work in one pass:
Push the necessary fixes, reply to each listed review thread and resolve it when addressed. Ignore feedback already answered or resolved. Use the pr-finisher skill and stop when only human review or CI remains; do not trigger CI. Sous-chef state: a78ac41f377c4917ec6ac2c621f496cdb22cd3fb707d550007467f7a31bd0d12
|
…ub-agent-models Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Review of
|
…ub-agent-models Co-authored-by: SivaKesava1 <11771739+SivaKesava1@users.noreply.github.com>
…te CLI personal-agent copies Co-authored-by: SivaKesava1 <11771739+SivaKesava1@users.noreply.github.com>
Addressed in b9f7f48 (after
New tests use the run 39304573724 fixtures:
Checks run: The end-to-end check that Copilot CLI 1.0.98 under AWF loads the personal copy instead of the repository file still needs a maintainer to dispatch a CLI smoke run on this branch. |
Verified at
|
| role | configured | resolved | status |
|---|---|---|---|
| main | gpt-5.3-codex | gpt-5.3-codex | exact |
| haiku-whoami | claude-haiku-4.5 | claude-haiku-4.5 | exact |
| mini-whoami | gpt-5-mini | null | failed / model_unavailable |
| mini54-whoami | gpt-5.4-mini | null | failed / model_unavailable |
Each dead pin gets its own failed record and the shared "The requested model is not supported" message. gpt-5-mini has also left the catalogue since 19 Oct, so it now fails as well (tracked with the other pins in #70367).
2. SDK mode, routed: smoke-copilot-sdk-routed-claude 39499464895
It stopped before the driver started. mini-whoami (gpt-5.4-mini) is recorded as failed / model_unavailable. There is no main record, because the main model comes from the router, as intended.
3. CLI mode: private sandbox run, compiled with --gh-aw-ref b9f7f48a3b
The workflow had:
- an inline
quick-checkerwithmodel: small; - an inline
file-summarizerwithmodel: claude-haiku-4.5; - a repository
.github/agents/conventions-helper.agent.mdwithmodel: GPT-5.4 (copilot), a VS Code display name.
The harness log shows:
warning: repository agent 'conventions-helper' (.../.github/agents/conventions-helper.agent.md) declares model 'GPT-5.4 (copilot)', which could not be resolved (cause: model_unavailable); Copilot CLI uses the agent file unchanged.
copilot sub-agent 'file-summarizer': model 'claude-haiku-4.5' -> 'claude-haiku-4.5'
copilot sub-agent 'quick-checker': model 'small' -> 'claude-haiku-5.5'
copilot sub-agent 'quick-checker': wrote model 'claude-haiku-5.5' to personal agent /home/runner/.copilot/agents/quick-checker.agent.md
The records are quick-checker small → claude-haiku-5.5 resolved, file-summarizer exact, conventions-helper failed / model_unavailable and main exact. The run succeeded.
- The personal-agent override works in Copilot CLI 1.0.98. The session's
subagent.startedforquick-checkershowsmodel: claude-haiku-5.5withtaskModelSource: custom_agent_definition. Copilot CLI loaded the resolved copy, not the workspace file withsmall. The checkout was not modified. - The repository agent no longer blocks the run. Before this round it would have stopped startup.
Unrelated failure in run 3. Both Claude sub-agents then failed with AWF's 400 Cannot translate Copilot request feature 'include' between Responses and Chat Completions. The main model gpt-5.6-luna is on /responses, and Copilot CLI sends one wire API for the whole session. This is the existing cross-family sub-agent limitation of Copilot CLI's BYOK mode, not caused by this PR: file-summarizer, whose model this PR doesn't change, fails the same way.
Review state
- The 13 earlier review threads are resolved. Each point is either still fixed at this head or no longer applies after the redesign.
- The two
github-actionsCHANGES_REQUESTED reviews from7f35145678are dismissed.
Before merge
- Merge Resolve experiment references in inline sub-agent frontmatter before writing the agent file; fail smoke-copilot when
file-summarizerdoesn't run #70387 first. On this branch,smoke-copilot'sfile-summarizerstill declares the unexpanded${{ experiments.subagent_model }}, so it now stops at startup. - Six production SDK workflows change behaviour. The PR body lists their sub-agents moving from the main model to
claude-haiku-5.5(small) orclaude-sonnet-5.5(large). - Scope question. @pelikhan, please confirm the declared/repository split from the earlier review comment: only workflow-declared sub-agents fail closed, and other repository agent files warn and record
failed.

gh-aw resolves the main
model:, but not Copilot sub-agent models. An alias or a retired id (gpt-5.4-mini) can silently run on the main model in SDK mode. In CLI mode, AWF rewrites it at request time or the request fails mid-run. Nothing records which model the sub-agent was meant to use.This PR makes gh-aw resolve sub-agent models before Copilot starts, record the result, and fail closed when a model can't be resolved.
Resolution (
copilot_harness.cjs)resolveCopilotSubagentModels. For each sub-agent that declaresmodel:, it callsresolveEngineModelwithengine: copilot,role: <agent name>, Copilot provider scope, the AWFapiProxy.modelsalias map, andnormalizeForCopilotCLI./reflectcatalogue, the same check the main SDK model uses. One/reflectrefresh is shared across all sub-agents.## agent:blocks and.github/agents/*.agent.md.model.resolutionrecord. When several sub-agents share a dead model, each gets its ownfailedrecord.status: failed, the cause (model_unavailableor the resolver's cause) andresolved_model: null.ModelAliasResolutionErrormessage, and the harness exits 1 before Copilot starts.model:. The sub-agent inherits the main model, as before, and gets no record.CLI mode
$GITHUB_WORKSPACE/.github/agents/<file>asmodel: "<id>". Only that line changes, and only when the resolved id differs from the declared one.git update-index --skip-worktree, so the rewrite can't reach the agent's commits orcreate-pull-request/push-to-pull-request-branchpatches.SDK mode
qualifyModelForMultiProvider). For example,smallbecomescopilot-<wire>/claude-haiku-5.5.GH_AW_COPILOT_SDK_SUBAGENT_MODELS, a JSON map keyed by agent name.copilot_sdk_session.cjs:small/medium/large→ session-model mapping.subagent.model_unavailabledriver event. Go audit still reads that event from older runs.mediumis not an alias in gh-aw or AWF, so it is treated as a literal model id and fails unless that model is live.Unchanged
applyCopilotModelAliasResolutionandresolveCopilotSDKMultiProvider.fallback-modelsandallowed-models.extract_inline_sub_agents.cjsand experiment interpolation.Behaviour changes for reviewers
These SDK sub-agents ran on the main model. They now run on the alias's model, as resolved against the catalogue of run 39304573724:
model:copilot/gpt-5Now fail at startup with
model_unavailable. These sub-agents are pinned to the deadgpt-5.4-mini; the pins are tracked in #70367:run-analyzermini-whoamimini54-whoamismoke-copilot / #70387. Until #70387 lands,
file-summarizerstill declares the unexpanded${{ experiments.subagent_model }}. It now fails at startup instead of failing mid-run with HTTP 400.Follow-up. Claude and Codex sub-agents have the same gap: gh-aw doesn't resolve their models. They need a separate issue.
Tests and fixtures
fixtures/awf-reflect-copilot-sub-agents-39304573724.json: 38 Copilot models, nogpt-5.4-minifixtures/awf-config-models-copilot-sub-agents-39304573724.json: the run'sapiProxy.modelsskip-worktreeprotection.Needs maintainer dispatch on this branch
The agent can't trigger workflow runs, so these smokes haven't run yet:
smoke-copilot-sub-agentsandsmoke-copilot-sdk-routed-claude: expected to fail at startup withmodel_unavailable.resolvedorexactsub-agent records.