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
18 changes: 16 additions & 2 deletions cli/azd/extensions/azure.ai.agents/internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,17 @@ func runRun(ctx context.Context, flags *runFlags) error {
}
projectDir := runCtx.ProjectDir

// Detect project type early — used for both start-command resolution and
// environment setup (e.g., setting ASPNETCORE_URLS for .NET).
pt := detectProjectType(projectDir)

// Resolve start command: --start-command flag > azure.yaml startupCommand > detect
startCmd := flags.startCommand
if startCmd == "" {
startCmd = runCtx.StartupCommand
}

if startCmd == "" {
pt := detectProjectType(projectDir)
if pt.StartCmd != "" {
startCmd = pt.StartCmd
fmt.Printf("Detected %s project. Start command: %s\n", pt.Language, startCmd)
Expand Down Expand Up @@ -135,7 +138,7 @@ func runRun(ctx context.Context, flags *runFlags) error {
cmdParts = resolveVenvCommand(projectDir, cmdParts)

env := os.Environ()
env = append(env, fmt.Sprintf("PORT=%d", flags.port))
env = appendPortEnvVars(env, pt, flags.port)

// Load azd environment variables (e.g., AZURE_AI_PROJECT_ENDPOINT)
// so the agent can reach Azure services during local development.
Expand Down Expand Up @@ -200,6 +203,17 @@ func runRun(ctx context.Context, flags *runFlags) error {
return nil
}

// appendPortEnvVars appends PORT and, for .NET projects, ASPNETCORE_URLS to the
// environment slice so the agent listens on the correct port.
// ASP.NET Core ignores PORT — it uses ASPNETCORE_URLS to configure Kestrel.
func appendPortEnvVars(env []string, pt ProjectType, port int) []string {
env = append(env, fmt.Sprintf("PORT=%d", port))
if pt.Language == "dotnet" {
env = append(env, fmt.Sprintf("ASPNETCORE_URLS=http://localhost:%d", port))
}
return env
}

// --- Dependency installation ---

func installDependencies(projectDir string) error {
Expand Down
75 changes: 75 additions & 0 deletions cli/azd/extensions/azure.ai.agents/internal/cmd/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,78 @@ func TestAppendFoundryEnvVars(t *testing.T) {
}
})
}

func TestAppendPortEnvVars(t *testing.T) {
t.Parallel()

t.Run("dotnet project includes ASPNETCORE_URLS", func(t *testing.T) {
t.Parallel()
pt := ProjectType{Language: "dotnet", StartCmd: "dotnet run"}
env := appendPortEnvVars(nil, pt, 8088)

if !slices.Contains(env, "PORT=8088") {
t.Errorf("expected PORT=8088 in env, got %v", env)
}
if !slices.Contains(env, "ASPNETCORE_URLS=http://localhost:8088") {
t.Errorf("expected ASPNETCORE_URLS=http://localhost:8088 in env, got %v", env)
}
})

t.Run("python project does not include ASPNETCORE_URLS", func(t *testing.T) {
t.Parallel()
pt := ProjectType{Language: "python", StartCmd: "python main.py"}
env := appendPortEnvVars(nil, pt, 8088)

if !slices.Contains(env, "PORT=8088") {
t.Errorf("expected PORT=8088 in env, got %v", env)
}
for _, entry := range env {
if strings.HasPrefix(entry, "ASPNETCORE_URLS=") {
t.Errorf("ASPNETCORE_URLS should not be set for python, got %v", env)
}
}
})

t.Run("node project does not include ASPNETCORE_URLS", func(t *testing.T) {
t.Parallel()
pt := ProjectType{Language: "node", StartCmd: "npm start"}
env := appendPortEnvVars(nil, pt, 9090)

if !slices.Contains(env, "PORT=9090") {
t.Errorf("expected PORT=9090 in env, got %v", env)
}
for _, entry := range env {
if strings.HasPrefix(entry, "ASPNETCORE_URLS=") {
t.Errorf("ASPNETCORE_URLS should not be set for node, got %v", env)
}
}
})

t.Run("dotnet project respects custom port", func(t *testing.T) {
t.Parallel()
pt := ProjectType{Language: "dotnet", StartCmd: "dotnet run"}
env := appendPortEnvVars(nil, pt, 3000)

if !slices.Contains(env, "PORT=3000") {
t.Errorf("expected PORT=3000 in env, got %v", env)
}
expected := "ASPNETCORE_URLS=http://localhost:3000"
if !slices.Contains(env, expected) {
t.Errorf("expected %q in env, got %v", expected, env)
}
})

t.Run("preserves existing env entries", func(t *testing.T) {
t.Parallel()
pt := ProjectType{Language: "dotnet", StartCmd: "dotnet run"}
existing := []string{"HOME=/home/user", "PATH=/usr/bin"}
env := appendPortEnvVars(existing, pt, 8088)

if len(env) != 4 {
t.Errorf("expected 4 entries (2 existing + PORT + ASPNETCORE_URLS), got %d: %v", len(env), env)
}
if env[0] != "HOME=/home/user" || env[1] != "PATH=/usr/bin" {
t.Errorf("existing entries not preserved, got %v", env)
}
})
}
Loading