Skip to content

Model routing: the routing-conversation step reads a prompt path that doesn't exist in the agent job #66221

Description

@SivaKesava1

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 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

  1. 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.

    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.txt holds only the workflow's own task.

  2. 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.

  3. Keep the conversation format unchanged. The step still writes
    /tmp/gh-aw/routing-conversation.json as one user message, so AWF needs no change.

  4. 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.

Activity

  1. locked and limited conversation to collaborators on Oct 6, 2026
  2. unlocked this conversation on Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions