Skip to content

Wire task-level model routing into the host workflow - #8985

Merged
lpcox merged 7 commits into
mainfrom
copilot/feat-routing-wire-host-workflow
Sep 25, 2026
Merged

lpcox merged 7 commits into
mainfrom
copilot/feat-routing-wire-host-workflow

Conversation

Copilot AI commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Task-level routing existed inside the API proxy, but the host workflow never staged the routing input, launched the router, or waited for a trusted selection before starting the agent. This wires the host side so routed runs fail closed instead of silently running unrouted.

  • Host routing bootstrap

    • Stages a validated conversation into a private per-run routing directory.
    • Rejects unsupported host modes: non-Linux, non-runc, disabled API proxy, DinD/split filesystems, Docker-socket exposure, or unpinned router image.
    • Reads proxy result records and returns routing failures with exit code 78.
  • Compose/runtime wiring

    • Adds an internal awf-routing network shared only by api-proxy and the router.
    • Adds the router sidecar with no environment, no published ports, and no bind mounts.
    • Mounts routing input/output only into api-proxy.
    • Keeps unrouted configs unchanged: no router service, routing network, or routing mounts.
  • API-proxy routing env

    • Moves AWF_ROUTING_CONFIG out of model policy env generation.
    • Emits it only after host staging and rewrites the conversation file to the proxy container path.
{
  "objective": { "goal": "cost", "mode": "balanced" },
  "task": { "conversationFile": "/run/awf-routing/input/conversation.json" }
}
  • Workflow ordering

    • Stages routing before Compose generation.
    • Starts infrastructure first, waits for selection.json, then starts the agent.
    • Verifies clean routing completion after proxy shutdown and cleans private routing state.
  • Coverage

    • Adds focused tests for bootstrap validation, result verification, env exclusion, routed Compose generation, and workflow readiness ordering.

Copilot AI changed the title [WIP] Wire routing into the host workflow Wire task-level model routing into the host workflow Sep 24, 2026
Copilot AI requested a review from lpcox September 24, 2026 23:24
@lpcox
lpcox marked this pull request as ready for review September 25, 2026 02:04
Copilot AI balanced review requested due to automatic review settings September 25, 2026 02:04

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.

Copilot review overview

🟡 Changes recommended

Routing error propagation and keep-container cleanup are incorrect, and the required real-container integration coverage is absent.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity · 1 Low severity

Open (4)
What changed in this PR

Wires task-level model routing into the host workflow with private staging, isolated router infrastructure, and fail-closed lifecycle checks.

Changes:

  • Adds routing bootstrap, validation, result polling, and cleanup.
  • Adds the isolated router service and API-proxy routing mounts/network.
  • Updates workflow ordering and focused unit tests.
File Description
src/​types/​index.ts Exports routing bootstrap state.
src/​types/​api-proxy-routing-options.ts Defines internal routing state.
src/​services/​router-service.ts Defines the router sidecar.
src/​services/​optional-services.ts Adds router assembly.
src/​services/​api-proxy-service-config.ts Adds routing mounts and networking.
src/​services/​api-proxy-env-config.ts Emits staged routing configuration.
src/​services/​api-proxy-env-config.test.ts Tests routing environment generation.
src/​services/​agent-environment/​excluded-vars.ts Blocks routing configuration passthrough.
src/​services/​agent-environment-options.test.ts Tests routing variable exclusion.
src/​routing/​bootstrap.ts Implements host routing lifecycle.
src/​routing/​bootstrap.test.ts Tests staging and result validation.
src/​image-tag.ts Adds router image digest handling.
src/​image-resolver.ts Exposes digest-reference validation.
src/​container-lifecycle.ts Includes router conflict cleanup.
src/​constants.ts Defines the router container name.
src/​compose-generator.ts Adds the private routing network.
src/​compose-generator.test.ts Tests routed Compose output.
src/​commands/​main-action.ts Wires routing dependencies and exit codes.
src/​cli-workflow.ts Adds routing startup and completion gates.
src/​cli-workflow.test.ts Tests routing workflow order.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/cli-workflow.ts
throw new Error('Model routing is enabled but no selection wait implementation was provided');
}
logger.info('Waiting for model routing selection...');
await dependencies.waitForRoutingSelection(routingState);
Comment thread src/cli-workflow.ts
Comment on lines +331 to +336
if (config.modelRouting) {
if (!dependencies.verifyRoutingCompletion) {
throw new Error('Model routing is enabled but no completion verification implementation was provided');
}
try {
await dependencies.verifyRoutingCompletion(routingState);
Comment on lines +500 to +503
prepareRouting: async (routingConfig) => stageRoutingConversation(routingConfig),
waitForRoutingSelection,
verifyRoutingCompletion: async (routingState) => verifyRoutingCompletion(routingState),
cleanupRouting: async (routingConfig) => cleanupRoutingState(routingConfig),
Comment on lines +24 to +29
healthcheck: {
test: ['CMD', 'curl', '-fsS', `http://localhost:${ROUTER_PORT}/healthz`],
interval: '2s',
timeout: '3s',
retries: 15,
start_period: '10s',
github-actions Bot added a commit that referenced this pull request Sep 25, 2026
Section 13a said the routing candidate-pool foundation was present but not
called by the running proxy. PR #8966 (merged) wired the routing controller
and request enforcement into the live API proxy server: a routing session
now starts after key validation/model discovery and screens every inference
request against the selected model/effort. Clarify that host-side staging
and validation of apiProxy.routing input (PR #8985) is still open, so the
feature is not yet end-to-end functional despite the proxy-side wiring
being shipped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@lpcox

lpcox commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

@github-actions

Copy link
Copy Markdown
Contributor

✅ Copilot review passed with no inline comments.

@copilot Add the ready-for-aw label to this PR to trigger agentic CI smoke tests.

Copilot AI commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed the routing review findings in b058eb6, a0cde97, and 98ccddc. Added failure-code preservation, signal cleanup, keep-container rejection, a valid router health probe, and real-container proxy/router coverage.

@lpcox
lpcox enabled auto-merge (squash) September 25, 2026 04:37
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

📡 Smoke OTel Tracing completed. All tracing scenarios validated. ✅

Warning

Firewall blocked 2 domains

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

  • o205451.ingest.us.sentry.io
  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "o205451.ingest.us.sentry.io"
    - "registry.npmjs.org"

See Network Configuration for more information.

📡 OTel tracing validated by Smoke OTel Tracing

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🛡️ Smoke Copilot Network Isolation confirmed the egress allowlist is enforced. ✅

Warning

Firewall blocked 2 domains

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

  • api.github.com
  • example.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "api.github.com"
    - "example.com"

See Network Configuration for more information.

🛡️ Egress verdict from Smoke Copilot Network Isolation

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Smoke Claude passed

Warning

Firewall blocked 1 domain

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

  • api.anthropic.com

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

network:
  allowed:
    - defaults
    - "api.anthropic.com"

See Network Configuration for more information.

Generated by Smoke Claude for #8985

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

Warning

Firewall blocked 2 domains

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

  • ab.chatgpt.com
  • msfeed25.pkgs.visualstudio.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"
    - "msfeed25.pkgs.visualstudio.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Build Test Suite completed successfully!

Warning

Firewall blocked 8 domains

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

  • api.nuget.org
  • bun.sh
  • dc.services.visualstudio.com
  • deno.land
  • dl.deno.land
  • github.com
  • releaseassets.githubusercontent.com
  • repo.maven.apache.org

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

network:
  allowed:
    - defaults
    - "api.nuget.org"
    - "bun.sh"
    - "dc.services.visualstudio.com"
    - "deno.land"
    - "dl.deno.land"
    - "github.com"
    - "releaseassets.githubusercontent.com"
    - "repo.maven.apache.org"

See Network Configuration for more information.

Generated by Build Test Suite for #8985

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox Network isolation smoke test results:

EGRESS_RESULT allow=pass deny=pass

✅ Allowed domain (github.com): allowed=200
✅ Denied domain (example.com): blocked (SSL error, denied=000)

Overall: PASS

Warning

Firewall blocked 2 domains

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

  • api.github.com
  • example.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "api.github.com"
    - "example.com"

See Network Configuration for more information.

🛡️ Egress verdict from Smoke Copilot Network Isolation
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Claude Engine Validation

Check Status
API ✅ PASS
gh CLI ✅ PASS
File ✅ PASS

Overall result: PASS

Warning

Firewall blocked 1 domain

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

  • api.anthropic.com

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

network:
  allowed:
    - defaults
    - "api.anthropic.com"

See Network Configuration for more information.

Generated by Smoke Claude for #8985 · claude · haiku45 · 30 AIC · ⊞ 4.7K · ◷
Add label ready-for-aw to run again

@github-actions github-actions Bot added smoke-copilot-network-isolation Copilot network-isolation egress smoke test smoke-claude labels Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot BYOK (Direct Mode) ✅ PASS

✅ MCP connectivity verified
✅ GitHub.com HTTP 200
✅ File write/read test passed
✅ Direct BYOK inference active (api-proxy → api.githubcopilot.com)

Mode: Direct BYOK (COPILOT_PROVIDER_API_KEY) via api-proxy sidecar
Status: All tests passed

🔑 BYOK report filed by Smoke Copilot BYOK
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Cloud Hypervisor + Copilot Smoke Test

  1. list_pull_requests (merged/closed, limit 1): PASS — PR Extract dynamic enclave launch test fixture #8987 returned
  2. curl https://github.com: PASS (200)
  3. Write/read temp file in /tmp/gh-aw/agent/: PASS
  4. curl (example.com/redacted) blocked: PASS (000)

All checks passed.

Warning

Firewall blocked 2 domains

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

  • example.com
  • github.com

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

network:
  allowed:
    - defaults
    - "example.com"
    - "github.com"

See Network Configuration for more information.

Cloud Hypervisor + Copilot smoke test by Smoke Cloud Hypervisor
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot Engine — @lpcox

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results:

  • Redis PING: ✅ (PONG)
  • Postgres pg_isready: ✅ (accepting connections)
  • Postgres SELECT 1: ✅ (1)

Overall: PASS

🔌 Service connectivity validated by Smoke Services
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Gemini Engine Validation Smoke Test Results

Overall Status: PASS

Warning

Firewall blocked 2 domains

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

  • github.com
  • play.googleapis.com

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

network:
  allowed:
    - defaults
    - "github.com"
    - "play.googleapis.com"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.14 Python 3.12.14 ✅ YES
Node.js v24.21.0 v22.23.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: FAILED — Node.js version mismatch between host (v24.21.0) and chroot (v22.23.2) environments. Python and Go versions match correctly. The smoke-chroot label was not added since not all tests passed.

Tested by Smoke Chroot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Reviewed PR titles:

Warning

Firewall blocked 2 domains

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

  • ab.chatgpt.com
  • msfeed25.pkgs.visualstudio.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"
    - "msfeed25.pkgs.visualstudio.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

📡 OTel Tracing Smoke Test Results

# Scenario Result
1 Module Loading (otel.js) ✅ Loaded successfully. isEnabled: true. Exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled, _provider, _ProxyAwareOtlpExporter, _FileSpanExporter, _FanOutSpanExporter, _parseEndpoints, _parseOtlpHeaders, _buildResourceSpans, _createOtlpWorkloadIdentity
2 Test Suite (otel*.test.js) ✅ 68/68 tests passed across 3 suites (otel.test.js, otel-fanout.test.js, otel-workload-identity.test.js) — covers span creation/attributes, gen_ai.usage.* conventions, parent-trace propagation, OTLP/JSON serialization, fan-out & workload-identity exporters, and file-based fallback
3 Env Var Forwarding ✅ GITHUB_AW_OTEL_TRACE_ID / GITHUB_AW_OTEL_PARENT_SPAN_ID present in src/services/agent-environment/env-passthrough.ts; GH_AW_OTLP_ENDPOINTS, OTEL_EXPORTER_OTLP_ENDPOINT, and both trace-context vars present in src/services/api-proxy-env-config.ts
4 Token Tracker Integration ✅ onUsage callback confirmed in containers/api-proxy/token-tracker-http.js (OTEL hook point)
5 OTEL Diagnostics ✅ Live api-proxy sidecar ran during this session — 19 token-usage records were recorded (token-usage.jsonl), confirming the proxy path is active. No local otel.jsonl file was produced, which is expected: this workflow configures a real observability.otlp.endpoint (Sentry), so the exporter uses ProxyAwareOtlpExporter/FanOutSpanExporter to ship spans directly via OTLP rather than falling back to FileSpanExporter (local JSONL is only used when no OTLP endpoint is configured)

Overall: ✅ All 5 scenarios passed. No regressions detected in OTEL tracing integration for the api-proxy sidecar.

Warning

Firewall blocked 2 domains

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

  • o205451.ingest.us.sentry.io
  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "o205451.ingest.us.sentry.io"
    - "registry.npmjs.org"

See Network Configuration for more information.

📡 OTel tracing validated by Smoke OTel Tracing
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia ✅ 1/1 passed ✅ PASS
Bun hono ✅ 1/1 passed ✅ PASS
C++ fmt ✅ N/A ✅ PASS
C++ json ✅ N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world ✅ N/A (ran) ✅ PASS
.NET json-parse ✅ N/A (ran) ✅ PASS
Go color ✅ ok ✅ PASS
Go env ✅ ok ✅ PASS
Go uuid ✅ ok ✅ PASS
Java gson ✅ 1/1 passed ✅ PASS
Java caffeine ✅ 1/1 passed ✅ PASS
Node.js clsx ✅ passed ✅ PASS
Node.js execa ✅ passed ✅ PASS
Node.js p-limit ✅ passed ✅ PASS
Rust fd ✅ 1/1 passed ✅ PASS
Rust zoxide ✅ 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — PASS

Notes:

  • Java: Maven's default ~/.m2 directory was root-owned and not writable by the runner user in this environment, so localRepository was overridden to a writable path (/tmp/gh-aw/agent/m2repo) in settings.xml alongside the required Squid proxy settings. All builds and tests then succeeded normally through the firewall proxy.
  • All other ecosystems installed/built/tested with no errors and no firewall-related network issues observed.

Warning

Firewall blocked 8 domains

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

  • api.nuget.org
  • bun.sh
  • dc.services.visualstudio.com
  • deno.land
  • dl.deno.land
  • github.com
  • releaseassets.githubusercontent.com
  • repo.maven.apache.org

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

network:
  allowed:
    - defaults
    - "api.nuget.org"
    - "bun.sh"
    - "dc.services.visualstudio.com"
    - "deno.land"
    - "dl.deno.land"
    - "github.com"
    - "releaseassets.githubusercontent.com"
    - "repo.maven.apache.org"

See Network Configuration for more information.

Generated by Build Test Suite for #8985 · copilot · auto · 39.5 AIC · ⊞ 11.8K · ◷
Add label ready-for-aw to run again

@lpcox
lpcox merged commit 6d7096d into main Sep 25, 2026
147 of 151 checks passed
@lpcox
lpcox deleted the copilot/feat-routing-wire-host-workflow branch September 25, 2026 04:49
lpcox pushed a commit that referenced this pull request Sep 25, 2026
Section 13a said the routing candidate-pool foundation was present but not
called by the running proxy. PR #8966 (merged) wired the routing controller
and request enforcement into the live API proxy server: a routing session
now starts after key validation/model discovery and screens every inference
request against the selected model/effort. Clarify that host-side staging
and validation of apiProxy.routing input (PR #8985) is still open, so the
feature is not yet end-to-end functional despite the proxy-side wiring
being shipped.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions Bot added a commit that referenced this pull request Sep 26, 2026
PR #8985 (host-side routing bootstrap) merged 2026-09-25 and is fully wired
into src/cli-workflow.ts and src/routing/bootstrap.ts on main. The spec
still described host staging/validation as not-yet-merged; update it to
reflect that both the proxy-side (PR #8966) and host-side (PR #8985)
halves of task-level routing are shipped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
aoai-model — 98ccddc3 Deployed Sep 25, 2026 by lpcox via conclusion #1764
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.

feat(routing): wire routing into the host workflow

3 participants