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-finish
No 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
Summary
When
OPENAI_BASE_URLorANTHROPIC_BASE_URLinengine.envcontains 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 tohttps://host/v1/chat/completionsinstead ofhttps://host/serving-endpoints/v1/chat/completions, returning 404.The AWF firewall already supports
--openai-api-base-pathand--anthropic-api-base-pathflags (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_URLorANTHROPIC_BASE_URLwith a required path prefix silently fails:/serving-endpoints)/openai/deployments/<name>)Root Cause
extractAPITargetHost()inpkg/workflow/awf_helpers.go:344-347intentionally strips the path: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:
2. Pass base path flags in
BuildAWFArgs()(pkg/workflow/awf_helpers.go)After the existing
--openai-api-targetand--anthropic-api-targetlines (~L213-223), add:3. Add tests (
pkg/workflow/awf_helpers_test.go)Add tests for
extractAPIBasePath:Add integration test for
BuildAWFArgs:4. Recompile workflows
No new frontmatter needed
This fix uses the existing
engine.envfrontmatter. Workflow authors already configure custom endpoints via env vars:The compiler will automatically extract and pass the path component — no new frontmatter fields required.
Checklist
extractAPIBasePath()function toawf_helpers.goBuildAWFArgs()for both OpenAI and Anthropic URLsextractAPIBasePath()BuildAWFArgswith path-containing URLsmake build && make recompile && make agent-finish