-
Notifications
You must be signed in to change notification settings - Fork 316
Description
Summary
When OPENAI_BASE_URL or ANTHROPIC_BASE_URL in engine.env contains a path prefix (e.g., https://host.com/serving-endpoints), the compiler strips the path and only passes the hostname via --openai-api-target. This causes API requests to go to https://host/v1/chat/completions instead of https://host/serving-endpoints/v1/chat/completions, returning 404.
The AWF firewall already supports --openai-api-base-path and --anthropic-api-base-path flags (added in a recent release). The compiler just needs to extract the path component and pass it.
Upstream tracking: /issues/21320#issuecomment-4131507565
Impact
Any OPENAI_BASE_URL or ANTHROPIC_BASE_URL with a required path prefix silently fails:
- Databricks serving endpoints (
/serving-endpoints) - Azure OpenAI deployments (
/openai/deployments/<name>) - Corporate LLM routers with path-based routing
Root Cause
extractAPITargetHost() in pkg/workflow/awf_helpers.go:344-347 intentionally strips the path:
// Remove path suffix if present (everything after first /)
if idx := strings.Index(host, "/"); idx != -1 {
host = host[:idx]
}This only returns the hostname for --openai-api-target. The path component is discarded and never passed to AWF.
Solution
1. Add extractAPIBasePath() function (pkg/workflow/awf_helpers.go)
Add a new function that extracts the path component from the URL:
// extractAPIBasePath extracts the path component from a custom API base URL in engine.env.
// Returns the path prefix (e.g., "/serving-endpoints") or empty string if no path is present.
func extractAPIBasePath(workflowData *WorkflowData, envVar string) string {
if workflowData == nil || workflowData.EngineConfig == nil || workflowData.EngineConfig.Env == nil {
return ""
}
baseURL, exists := workflowData.EngineConfig.Env[envVar]
if !exists || baseURL == "" {
return ""
}
// Remove protocol prefix
host := baseURL
if idx := strings.Index(host, "://"); idx != -1 {
host = host[idx+3:]
}
// Extract path (everything after first /)
if idx := strings.Index(host, "/"); idx != -1 {
path := host[idx:] // e.g., "/serving-endpoints"
// Remove trailing slash if present
path = strings.TrimRight(path, "/")
if path != "" {
return path
}
}
return ""
}2. Pass base path flags in BuildAWFArgs() (pkg/workflow/awf_helpers.go)
After the existing --openai-api-target and --anthropic-api-target lines (~L213-223), add:
// Pass base path if URL contains a path component
openaiBasePath := extractAPIBasePath(config.WorkflowData, "OPENAI_BASE_URL")
if openaiBasePath != "" {
awfArgs = append(awfArgs, "--openai-api-base-path", openaiBasePath)
awfHelpersLog.Printf("Added --openai-api-base-path=%s", openaiBasePath)
}
anthropicBasePath := extractAPIBasePath(config.WorkflowData, "ANTHROPIC_BASE_URL")
if anthropicBasePath != "" {
awfArgs = append(awfArgs, "--anthropic-api-base-path", anthropicBasePath)
awfHelpersLog.Printf("Added --anthropic-api-base-path=%s", anthropicBasePath)
}3. Add tests (pkg/workflow/awf_helpers_test.go)
Add tests for extractAPIBasePath:
func TestExtractAPIBasePath(t *testing.T) {
tests := []struct {
name string
url string
expected string
}{
{"databricks serving endpoint", "https://host.com/serving-endpoints", "/serving-endpoints"},
{"azure openai deployment", "https://host.com/openai/deployments/gpt-4", "/openai/deployments/gpt-4"},
{"simple path", "https://host.com/v1", "/v1"},
{"trailing slash stripped", "https://host.com/api/", "/api"},
{"no path", "https://host.com", ""},
{"bare hostname", "host.com", ""},
{"root path only", "https://host.com/", ""},
}
// ... table-driven test body
}Add integration test for BuildAWFArgs:
t.Run("includes openai-api-base-path when URL has path component", func(t *testing.T) {
// Set OPENAI_BASE_URL to "https://host.com/serving-endpoints"
// Verify args contain both --openai-api-target and --openai-api-base-path
})4. Recompile workflows
make build && make recompile && make agent-finishNo new frontmatter needed
This fix uses the existing engine.env frontmatter. Workflow authors already configure custom endpoints via env vars:
engine:
id: codex
env:
OPENAI_BASE_URL: "https://stone-dataplatform-production.cloud.databricks.com/serving-endpoints"
OPENAI_API_KEY: ${{ secrets.DATABRICKS_KEY }}The compiler will automatically extract and pass the path component — no new frontmatter fields required.
Checklist
- Add
extractAPIBasePath()function toawf_helpers.go - Call it in
BuildAWFArgs()for both OpenAI and Anthropic URLs - Add unit tests for
extractAPIBasePath() - Add integration test for
BuildAWFArgswith path-containing URLs -
make build && make recompile && make agent-finish