Skip to content

feat: always listen on all api-proxy ports regardless of configured credentials #2382

@lpcox

Description

@lpcox

Problem

Currently, the api-proxy sidecar only starts listeners on ports where the corresponding API key is configured:

  • Port 10000 (OpenAI) — only if OPENAI_API_KEY is set
  • Port 10001 (Anthropic) — only if ANTHROPIC_API_KEY is set
  • Port 10002 (Copilot) — only if COPILOT_GITHUB_TOKEN or COPILOT_API_KEY is set
  • Port 10003 (Gemini) — only if GEMINI_API_KEY is set
  • Port 10004 (OpenCode) — only if any credential is present + AWF_ENABLE_OPENCODE

Similarly, the AWF CLI only sets *_BASE_URL environment variables in the agent container when the matching key is present (src/docker-manager.ts:1854-1940), and iptables rules may only allow traffic to ports that are actively configured.

This creates problems:

  1. Model aliasing breaks across providers — if a workflow configures apiProxy.models to alias a model name to a different provider's model, the target port may not be listening because that provider's key wasn't explicitly configured.
  2. Dynamic routing is impossible — the model-resolver can resolve "fast"claude-haiku-4.5 but if only OPENAI_API_KEY was provided, port 10001 isn't running.
  3. Credential discovery at runtime — tools like Copilot CLI may dynamically acquire tokens (e.g., via OAuth) and attempt to use a provider port that was never started.
  4. Startup complexity — the server has complex conditional logic tracking which listeners to expect for healthcheck readiness (expectedListeners at line 1610).

Proposal

1. Always start all port listeners in api-proxy

All five ports (10000–10004) should always be listening when --enable-api-proxy is active:

Port 10000 — OpenAI-compatible API (always listening)
Port 10001 — Anthropic API (always listening)
Port 10002 — Copilot API (always listening)
Port 10003 — Gemini API (always listening)
Port 10004 — OpenCode/generic (always listening)

When a request arrives on a port without a configured credential, the proxy should return a clear error (e.g., 503 Service Unavailable with body {"error": "No API key configured for this provider"}) rather than refusing the TCP connection.

2. Always set all *_BASE_URL env vars in agent

Remove the conditional if (config.openaiApiKey) / if (config.anthropicApiKey) / etc. guards in src/docker-manager.ts:1854-1940. Always point all provider base URLs at the sidecar:

OPENAI_BASE_URL=http://172.30.0.30:10000
ANTHROPIC_BASE_URL=http://172.30.0.30:10001
COPILOT_API_URL=http://172.30.0.30:10002
GEMINI_API_BASE_URL=http://172.30.0.30:10003

3. Allow all api-proxy ports in iptables

Ensure setup-iptables.sh allows agent→api-proxy traffic on all ports (10000–10004), not just ports for configured providers. Currently AWF_API_PROXY_IP is used — verify traffic to all ports on that IP is permitted.

4. Simplify healthcheck

With all ports always listening, the healthcheck can simply hit port 10000 /health without the expectedListeners counting logic.

Files to Change

File Change
containers/api-proxy/server.js Remove conditional listener startup; always bind all ports; return 503 for unconfigured providers
src/docker-manager.ts:1854-1940 Remove if (config.*Key) guards; always set all *_BASE_URL vars
containers/agent/setup-iptables.sh Verify all api-proxy ports are allowed (likely already covered by IP-based rule)
src/types.ts No change needed (ports already defined)

Benefits

  • Model aliasing works across providers — resolver can route to any port
  • Simpler startup logic — no conditional listener counting
  • Future-proof — new providers/credentials can be added at runtime without restart
  • Better error messages — 503 with explanation vs TCP connection refused
  • Credential placeholder simplification — always set placeholders for all providers

Backward Compatibility

  • Agent tools that check for *_BASE_URL to detect provider availability may need updating if they use presence of the env var as a "provider is configured" signal
  • Placeholder API keys should still be set for all providers to satisfy CLI credential validation

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions