Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/azd/cmd/auto_install_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ func containsNoPromptFalse(args []string) bool {
// This ensures tests are isolated from the ambient environment.
func clearAgentEnvVarsForTest(t *testing.T) {
envVarsToUnset := []string{
// GitHub Copilot App
"AI_AGENT",
// Claude Code
"CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT",
// GitHub Copilot CLI
Expand Down
31 changes: 21 additions & 10 deletions cli/azd/internal/runcontext/agentdetect/detect_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ import (

// envVarPattern maps environment variables to agent types.
type envVarPattern struct {
envVar string
agentType AgentType
envVar string
expectedValue string
agentType AgentType
}

// knownEnvVarPatterns defines environment variables that indicate known AI agents.
// These are checked in order, so more specific patterns should come first.
var knownEnvVarPatterns = []envVarPattern{
// GitHub Copilot App can expose Copilot CLI markers, so check its host-specific marker first.
{
envVar: "AI_AGENT",
expectedValue: "github_copilot_app_agent",
Comment thread
qinezh marked this conversation as resolved.
agentType: AgentTypeGitHubCopilotApp,
},

// Claude Code - Anthropic's coding agent
{envVar: "CLAUDE_CODE", agentType: AgentTypeClaudeCode},
{envVar: "CLAUDE_CODE_ENTRYPOINT", agentType: AgentTypeClaudeCode},
Expand All @@ -39,14 +47,17 @@ var knownEnvVarPatterns = []envVarPattern{
// detectFromEnvVars checks for known AI agent environment variables.
func detectFromEnvVars() AgentInfo {
for _, pattern := range knownEnvVarPatterns {
if _, exists := os.LookupEnv(pattern.envVar); exists {
return AgentInfo{
Type: pattern.agentType,
Name: pattern.agentType.DisplayName(),
Source: DetectionSourceEnvVar,
Detected: true,
Details: pattern.envVar,
}
value, exists := os.LookupEnv(pattern.envVar)
if !exists || (pattern.expectedValue != "" && value != pattern.expectedValue) {
continue
}

return AgentInfo{
Type: pattern.agentType,
Name: pattern.agentType.DisplayName(),
Source: DetectionSourceEnvVar,
Detected: true,
Details: pattern.envVar,
}
}

Expand Down
18 changes: 18 additions & 0 deletions cli/azd/internal/runcontext/agentdetect/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func TestAgentType_DisplayName(t *testing.T) {
}{
{AgentTypeClaudeCode, "Claude Code"},
{AgentTypeGitHubCopilotCLI, "GitHub Copilot CLI"},
{AgentTypeGitHubCopilotApp, "GitHub Copilot App"},
{AgentTypeVSCodeCopilot, "VS Code GitHub Copilot"},
{AgentTypeGemini, "Gemini"},
{AgentTypeOpenCode, "OpenCode"},
Expand Down Expand Up @@ -53,6 +54,21 @@ func TestDetectFromEnvVars(t *testing.T) {
expectedAgent: AgentTypeUnknown,
detected: false,
},
{
name: "GitHub Copilot App takes precedence over Copilot CLI",
envVars: map[string]string{
"AI_AGENT": "github_copilot_app_agent",
"COPILOT_CLI": "1",
},
expectedAgent: AgentTypeGitHubCopilotApp,
detected: true,
},
{
name: "Unrecognized AI_AGENT value",
envVars: map[string]string{"AI_AGENT": "another_agent"},
expectedAgent: AgentTypeUnknown,
detected: false,
},
{
name: "Claude Code via CLAUDE_CODE",
envVars: map[string]string{"CLAUDE_CODE": "1"},
Expand Down Expand Up @@ -327,6 +343,8 @@ func TestDisableAgentDetect(t *testing.T) {
// This list must be kept in sync with knownEnvVarPatterns in detect_env.go.
func clearAgentEnvVars(t *testing.T) {
envVarsToUnset := []string{
// GitHub Copilot App
"AI_AGENT",
// Claude Code
"CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT",
// GitHub Copilot CLI
Expand Down
4 changes: 4 additions & 0 deletions cli/azd/internal/runcontext/agentdetect/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const (
AgentTypeClaudeCode AgentType = "claude-code"
// AgentTypeGitHubCopilotCLI is GitHub's Copilot CLI agent.
AgentTypeGitHubCopilotCLI AgentType = "github-copilot-cli"
// AgentTypeGitHubCopilotApp is GitHub's Copilot App agent.
AgentTypeGitHubCopilotApp AgentType = "github-copilot-app"
// AgentTypeVSCodeCopilot is VS Code GitHub Copilot extension.
AgentTypeVSCodeCopilot AgentType = "vscode-copilot"
// AgentTypeGemini is Google's Gemini CLI.
Expand All @@ -36,6 +38,8 @@ func (a AgentType) DisplayName() string {
return "Claude Code"
case AgentTypeGitHubCopilotCLI:
return "GitHub Copilot CLI"
case AgentTypeGitHubCopilotApp:
return "GitHub Copilot App"
case AgentTypeVSCodeCopilot:
return "VS Code GitHub Copilot"
case AgentTypeGemini:
Expand Down
1 change: 1 addition & 0 deletions cli/azd/internal/terminal/terminal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func clearTestEnvVars(t *testing.T) {
envVarsToUnset := []string{
"AZD_FORCE_TTY",
// Agent env vars
"AI_AGENT",
"CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT",
"GITHUB_COPILOT_CLI", "GH_COPILOT", "COPILOT_CLI",
"GEMINI_CLI", "GEMINI_CLI_NO_RELAUNCH",
Expand Down
1 change: 1 addition & 0 deletions cli/azd/internal/tracing/fields/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ const (
// AI Coding Agent environments
EnvClaudeCode = "Claude Code"
EnvGitHubCopilotCLI = "GitHub Copilot CLI"
EnvGitHubCopilotApp = "GitHub Copilot App"
Comment thread
qinezh marked this conversation as resolved.
EnvGemini = "Gemini"
EnvOpenCode = "OpenCode"

Expand Down
2 changes: 2 additions & 0 deletions cli/azd/internal/tracing/resource/exec_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ func execEnvFromAgent() string {
return fields.EnvClaudeCode
case agentdetect.AgentTypeGitHubCopilotCLI:
return fields.EnvGitHubCopilotCLI
case agentdetect.AgentTypeGitHubCopilotApp:
return fields.EnvGitHubCopilotApp
Comment thread
qinezh marked this conversation as resolved.
case agentdetect.AgentTypeVSCodeCopilot:
return fields.EnvVSCodeAzureCopilot
case agentdetect.AgentTypeGemini:
Expand Down
1 change: 1 addition & 0 deletions docs/reference/telemetry-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ The `execution.environment` field identifies where azd is running. Format: `<env
| `Azure CloudShell` | Azure Cloud Shell |
| `Claude Code` | Claude Code AI agent |
| `GitHub Copilot CLI` | GitHub Copilot CLI |
| `GitHub Copilot App` | GitHub Copilot App |
| `Gemini` | Gemini AI agent |
| `OpenCode` | OpenCode AI agent |
| `GitHub Actions` | GitHub Actions CI |
Expand Down
Loading