You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Model routing: the routing-conversation step reads a prompt path that doesn't exist in the agent job #66221
Every routed Copilot workflow (engine.model-routing) fails in the agent job at the
"Prepare model-routing conversation" step, before AWF or the agent starts. The step reads the
rendered prompt from ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt. On GitHub-hosted runners
that file doesn't exist in the agent job. The agent job gets the prompt files from the activation artifact, which it downloads to /tmp/gh-aw.
This is separate from #64838, which is about routing on the task text instead of the whole
prompt. The fix below addresses both.
Evidence
Reproduced on a GitHub-hosted runner, ubuntu-latest, in the private test repository githubnext/gh-aw-routing-sandbox. Run 37395885553 was compiled from main at af1e2fd1ef with --gh-aw-ref and used AWF v0.28.35. The agent job's "Prepare model-routing conversation" step
failed:
GH_AW_ROUTING_PROMPT: /home/runner/work/_temp/gh-aw/aw-prompts/prompt.txt
Error: ENOENT: no such file or directory, open '/home/runner/work/_temp/gh-aw/aw-prompts/prompt.txt'
Where the files actually are: earlier in the same job, "Download activation artifact" used path: /tmp/gh-aw. The artifact contains aw-prompts/prompt.txt (10,794 bytes), aw-prompts/system.txt (10,552 bytes), and aw-prompts/user.txt (242 bytes).
The agent step itself reads its prompt from /tmp/gh-aw/aw-prompts/prompt.txt.
With a local patch that points the routing step at /tmp/gh-aw/aw-prompts/user.txt in the
lock file, routing works end to end. Twelve runs succeeded since 5 Oct, from a one-line question
to a cross-repository design task, and the router selected different models for different tasks.
Cause
generateModelRoutingConversationStep in pkg/workflow/model_routing.go sets GH_AW_ROUTING_PROMPT to constants.AwPromptsFileExpr. That is the host-side ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt path, which only the activation job writes.
The agent's own prompt path is chosen per topology:
buildCopilotBaseCommand in pkg/workflow/copilot_engine_execution.go uses constants.AwPromptsFile (/tmp/gh-aw/aw-prompts/prompt.txt) by default;
it uses constants.AwPromptsFileShell only on ARC/DinD (isArcDindTopology), where the
prompts are copied under ${RUNNER_TEMP}/gh-aw/.
The routing step doesn't make that choice, so it most likely works only on ARC/DinD runners.
No workflow in this repository uses engine.model-routing, so CI doesn't run this step. The
gh-aw-firewall routing smoke test drives AWF directly.
Proposed plan
Read the task-only prompt from the agent job's prompt directory. In generateModelRoutingConversationStep:
point GH_AW_ROUTING_PROMPT at user.txt in the same directory the agent step reads: /tmp/gh-aw/aw-prompts/ by default, and the ${RUNNER_TEMP}/gh-aw/aw-prompts/ form on
ARC/DinD, using the same isArcDindTopology choice as buildCopilotBaseCommand;
add constants for the user.txt paths next to the existing AwPromptsFile* constants, so
both steps share one source of truth.
Fall back safely. If user.txt is missing or blank, for example in a lock file that
predates the prompt split, the step should fall back to prompt.txt in the same directory. It
should fail only when neither has text. Keep the existing error message for the
empty-prompt case.
Keep the conversation format unchanged. The step still writes /tmp/gh-aw/routing-conversation.json as one user message, so AWF needs no change.
Tests.
In pkg/workflow/model_routing_test.go, assert that a routed workflow's step reads the
agent-job path for user.txt on default runners and the RUNNER_TEMP form on ARC/DinD.
Assert that it never uses the activation-only runner.temp path on default runners.
Cover the fallback to prompt.txt and the blank-input case.
Ideally, also add one compiled routed workflow to the repository's own workflows, so CI runs
this step on a hosted runner. A plain workflow_dispatch workflow with a trivial task is
enough.
Summary
Every routed Copilot workflow (
engine.model-routing) fails in the agent job at the"Prepare model-routing conversation" step, before AWF or the agent starts. The step reads the
rendered prompt from
${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt. On GitHub-hosted runnersthat file doesn't exist in the agent job. The agent job gets the prompt files from the
activationartifact, which it downloads to/tmp/gh-aw.This is separate from #64838, which is about routing on the task text instead of the whole
prompt. The fix below addresses both.
Evidence
Reproduced on a GitHub-hosted runner,
ubuntu-latest, in the private test repositorygithubnext/gh-aw-routing-sandbox. Run 37395885553 was compiled frommainataf1e2fd1efwith--gh-aw-refand used AWF v0.28.35. The agent job's "Prepare model-routing conversation" stepfailed:
path: /tmp/gh-aw. The artifact containsaw-prompts/prompt.txt(10,794 bytes),aw-prompts/system.txt(10,552 bytes), andaw-prompts/user.txt(242 bytes)./tmp/gh-aw/aw-prompts/prompt.txt./tmp/gh-aw/aw-prompts/user.txtin thelock file, routing works end to end. Twelve runs succeeded since 5 Oct, from a one-line question
to a cross-repository design task, and the router selected different models for different tasks.
Cause
generateModelRoutingConversationStepinpkg/workflow/model_routing.gosetsGH_AW_ROUTING_PROMPTtoconstants.AwPromptsFileExpr. That is the host-side${{ runner.temp }}/gh-aw/aw-prompts/prompt.txtpath, which only the activation job writes.buildCopilotBaseCommandinpkg/workflow/copilot_engine_execution.gousesconstants.AwPromptsFile(/tmp/gh-aw/aw-prompts/prompt.txt) by default;constants.AwPromptsFileShellonly on ARC/DinD (isArcDindTopology), where theprompts are copied under
${RUNNER_TEMP}/gh-aw/.engine.model-routing, so CI doesn't run this step. Thegh-aw-firewall routing smoke test drives AWF directly.
Proposed plan
Read the task-only prompt from the agent job's prompt directory. In
generateModelRoutingConversationStep:GH_AW_ROUTING_PROMPTatuser.txtin the same directory the agent step reads:/tmp/gh-aw/aw-prompts/by default, and the${RUNNER_TEMP}/gh-aw/aw-prompts/form onARC/DinD, using the same
isArcDindTopologychoice asbuildCopilotBaseCommand;user.txtpaths next to the existingAwPromptsFile*constants, soboth steps share one source of truth.
This also resolves Model routing: classify only the workflow task, not the whole rendered prompt #64838: since Separate system and user prompts in activation artifacts #64949,
user.txtholds only the workflow's own task.Fall back safely. If
user.txtis missing or blank, for example in a lock file thatpredates the prompt split, the step should fall back to
prompt.txtin the same directory. Itshould fail only when neither has text. Keep the existing error message for the
empty-prompt case.
Keep the conversation format unchanged. The step still writes
/tmp/gh-aw/routing-conversation.jsonas one user message, so AWF needs no change.Tests.
pkg/workflow/model_routing_test.go, assert that a routed workflow's step reads theagent-job path for
user.txton default runners and theRUNNER_TEMPform on ARC/DinD.runner.temppath on default runners.prompt.txtand the blank-input case.this step on a hosted runner. A plain
workflow_dispatchworkflow with a trivial task isenough.