Skip to content

Comments

Fix: engine.agent propagates to threat detection job causing "No such agent" failure#17949

Merged
pelikhan merged 6 commits intomainfrom
copilot/fix-engine-agent-propagation
Feb 23, 2026
Merged

Fix: engine.agent propagates to threat detection job causing "No such agent" failure#17949
pelikhan merged 6 commits intomainfrom
copilot/fix-engine-agent-propagation

Conversation

Copy link
Contributor

Copilot AI commented Feb 23, 2026

When engine.agent is set alongside an explicit model, the threat detection job inherits the --agent flag via a pointer copy of EngineConfig. Since the detection job never checks out the repo, the agent file is missing and the job fails immediately with No such agent: <name>, available:.

Changes

  • pkg/workflow/threat_detection.go — In buildEngineSteps(), the two-branch logic is collapsed into a single minimal-copy pattern. The detection engine config now inherits only ID, Model, Version, Env, Config, and Args from the main engine config. MaxTurns, Concurrency, UserAgent, Firewall, and Agent are intentionally omitted — the detection job is a simple threat-analysis invocation and must never run as a custom agent.

  • pkg/workflow/threat_detection_test.go — Added TestBuildEngineStepsStripsAgentField covering both the model-configured and non-model-configured paths, asserting --agent never appears in detection steps and that the original EngineConfig is not mutated.

// Before — pointer copy; Agent and other fields leak through
if modelExplicitlyConfigured {
    detectionEngineConfig = engineConfig  // includes Agent: "my-agent"
}

// After — minimal copy: only ID, Model, Version, Env, Config, Args are inherited
detectionEngineConfig = &EngineConfig{
    ID:      detectionEngineConfig.ID,
    Model:   detectionEngineConfig.Model,
    Version: detectionEngineConfig.Version,
    Env:     detectionEngineConfig.Env,
    Config:  detectionEngineConfig.Config,
    Args:    detectionEngineConfig.Args,
    // MaxTurns, Concurrency, UserAgent, Firewall, Agent intentionally omitted
}
Original prompt

This section details on the original issue you should resolve

<issue_title>Bug: engine.agent propagates to threat detection job, causing "No such agent" failure</issue_title>
<issue_description>🤖 AI Assisted Bug Report

Summary

When engine.agent is set in a workflow's frontmatter along with an explicit model, the --agent flag is propagated to the threat detection job's Copilot CLI invocation. The detection job does not check out the repository, so the agent file is unavailable, causing an immediate failure: No such agent: <name>, available: (empty list).

Reproduction

  1. Create a workflow .md with engine.agent and an explicit model:
engine:
  id: copilot
  agent: my-agent
  model: claude-opus-4.6
  1. Place a matching agent file at .github/agents/my-agent.agent.md
  2. Configure safe-outputs (which enables threat detection)
  3. Compile with gh aw compile and run via workflow_dispatch

Expected: All jobs succeed — the agent job uses --agent my-agent, the detection job runs threat analysis without the --agent flag.

Actual: The agent job succeeds, but the detection job fails with:

No such agent: my-agent, available:
Process completed with exit code 1

Safe outputs are skipped because detection failed.

Root Cause

In pkg/workflow/threat_detection.go buildEngineSteps(), the detectionEngineConfig is set differently depending on whether a model is explicitly configured:

When model IS configured (modelExplicitlyConfigured == true):

detectionEngineConfig = engineConfig  // Full reference — includes Agent field

This passes the entire EngineConfig (including Agent: "my-agent") to the threat detection WorkflowData, which causes GetExecutionSteps() in copilot_engine_execution.go to emit --agent my-agent.

When model is NOT configured, the code creates a manual copy that happens to omit Agent:

detectionEngineConfig = &EngineConfig{
    ID:          detectionEngineConfig.ID,
    Model:       "",
    Version:     detectionEngineConfig.Version,
    MaxTurns:    detectionEngineConfig.MaxTurns,
    Concurrency: detectionEngineConfig.Concurrency,
    UserAgent:   detectionEngineConfig.UserAgent,
    Env:         detectionEngineConfig.Env,
    Config:      detectionEngineConfig.Config,
    Args:        detectionEngineConfig.Args,
    Firewall:    detectionEngineConfig.Firewall,
    // Agent is NOT copied — accidentally correct for detection
}

The detection job also doesn't check out the repository (no actions/checkout step) and doesn't add $GITHUB_WORKSPACE to --add-dir, so even if --agent is passed, the agent file can't be found.

Suggested Fix

Always strip the Agent field from the detection engine config, similar to how Model is already handled. The threat detection job has its own purpose (analyzing agent output for threats) and should never run as a custom agent.

In the modelExplicitlyConfigured branch, create a copy that excludes Agent:

if modelExplicitlyConfigured {
    detectionEngineConfig = &EngineConfig{
        ID:          engineConfig.ID,
        Model:       engineConfig.Model,
        Version:     engineConfig.Version,
        MaxTurns:    engineConfig.MaxTurns,
        Concurrency: engineConfig.Concurrency,
        UserAgent:   engineConfig.UserAgent,
        Env:         engineConfig.Env,
        Config:      engineConfig.Config,
        Args:        engineConfig.Args,
        Firewall:    engineConfig.Firewall,
        // Agent intentionally omitted — detection should not use custom agents
    }
}

Or alternatively, strip Agent after the config is determined:

// Threat detection should never run as a custom agent
if detectionEngineConfig != nil {
    detectionEngineConfig.Agent = ""
}

Environment

Workaround

Remove engine.agent from the workflow frontmatter and instead use {{#runtime-import}} to pull the agent file's content inline, avoiding the --agent flag entirely.</issue_description>

Comments on the Issue (you are @copilot in this section)

@pelikhan Detection should not use agent.

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


Changeset

  • Type: patch
  • Description: Strip the custom agent flag from the threat detection engine config so the detection job can run without needing an agent file.

Generated by Changeset Generator for issue #17949

Warning

⚠️ Firewall blocked 2 domains

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

  • codeload.github.com
  • github.com


✨ PR Review Safe Output Test - Run 22319427382

💥 [THE END] — Illustrated by Smoke Claude

Copilot AI and others added 2 commits February 23, 2026 16:57
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
When engine.agent is set along with an explicit model, the
modelExplicitlyConfigured branch was assigning detectionEngineConfig
= engineConfig (a pointer copy), propagating the Agent field to the
threat detection job. The detection job has no repo checkout, so the
agent file can't be found, causing "No such agent" failures.

Fix: create a struct copy that excludes Agent in the
modelExplicitlyConfigured branch, matching the existing pattern in
the else-branch.

Add TestBuildEngineStepsStripsAgentField to verify --agent never
appears in detection steps for both code paths.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix propagation of engine.agent to threat detection job Fix: engine.agent propagates to threat detection job causing "No such agent" failure Feb 23, 2026
Per review feedback, the detection engine config should only carry
ID and Model — all other fields (Version, MaxTurns, Concurrency,
UserAgent, Env, Config, Args, Firewall, Agent) are intentionally
stripped. This collapses the two-branch logic into a single
minimal-copy pattern.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Per review feedback, the detection engine config now inherits ID,
Model, Version, Env, Config, and Args. MaxTurns, Concurrency,
UserAgent, Firewall, and Agent remain intentionally omitted.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review February 23, 2026 18:28
Copilot AI review requested due to automatic review settings February 23, 2026 18:28
@github-actions
Copy link
Contributor

📰 DEVELOPING STORY: Smoke Copilot reports was cancelled. Our correspondents are investigating the incident...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

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

@github-actions
Copy link
Contributor

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes a bug where the engine.agent field from the main workflow configuration was being propagated to the threat detection job, causing it to fail with "No such agent" errors. The threat detection job runs without repository checkout, making agent files unavailable.

Changes:

  • Refactored buildEngineSteps() in pkg/workflow/threat_detection.go to explicitly copy only necessary fields (ID, Model, Version, Env, Config, Args) to the detection engine config, intentionally omitting Agent, MaxTurns, Concurrency, UserAgent, and Firewall
  • Added comprehensive test coverage in TestBuildEngineStepsStripsAgentField to verify the Agent field is never propagated
  • Updated auto-generated .lock.yml workflow files to reflect the removal of --max-turns flags and addition of storage.googleapis.com to allowed domains

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.

File Description
pkg/workflow/threat_detection.go Replaced pointer copy with explicit field copying to prevent Agent field propagation to detection job
pkg/workflow/threat_detection_test.go Added test verifying Agent field is stripped in both model-configured and non-configured scenarios
.github/workflows/*.lock.yml Auto-generated workflow files reflecting MaxTurns removal and domain additions

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

@github-actions
Copy link
Contributor

Smoke test results:
PRs: #17951 Add missing permission scopes to schema and handle all meta-key in scope converter; #17950 Align MCP observability pipeline: treat rpc-messages.jsonl as canonical telemetry fallback
GitHub MCP: ✅
Serena MCP: ✅
Playwright: ✅
Web Fetch: ✅
File write+read: ✅
Build: ✅
Overall: PASS

🔮 The oracle has spoken through Smoke Codex

@github-actions
Copy link
Contributor

Commit pushed: bddd575

@github-actions
Copy link
Contributor

🤖 Smoke test §22319427353 results for @pelikhan:

Test
GitHub MCP
Safe Inputs GH CLI
Playwright
Web Fetch
File Writing + Bash
Discussion Interaction
Build gh-aw
Discussion Creation
Workflow Dispatch
PR Review

Overall: PASS ✅

📰 BREAKING: Report filed by Smoke Copilot

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Good fix for the Agent field leak into the threat detection job. The minimal-copy approach is cleaner than the previous two-branch pattern. Left two inline comments — one on a potential simplification and one suggesting a clarifying comment on the intentionally omitted fields.

📰 BREAKING: Report filed by Smoke Copilot

@@ -330,34 +330,20 @@ func (c *Compiler) buildEngineSteps(data *WorkflowData) []string {
// 3. Default detection model from the engine (as environment variable fallback)
detectionEngineConfig := engineConfig
Copy link
Contributor

Choose a reason for hiding this comment

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

The initial detectionEngineConfig := engineConfig assignment (which sets a full reference) is immediately replaced in the if/else below, so it's a no-op. Could simplify to var detectionEngineConfig *EngineConfig to make the intent clearer from the start.

@pelikhan pelikhan merged commit a93e36e into main Feb 23, 2026
@pelikhan pelikhan deleted the copilot/fix-engine-agent-propagation branch February 23, 2026 18:38
@github-actions
Copy link
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

💥 Automated smoke test review - all systems nominal!

💥 [THE END] — Illustrated by Smoke Claude

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.

Bug: engine.agent propagates to threat detection job, causing "No such agent" failure

2 participants