Skip to content

fix(agents): make deployed agent inference URL container-reachable#899

Merged
benmccown merged 1 commit into
mainfrom
agent-deployment-url-fix
Jul 25, 2026
Merged

fix(agents): make deployed agent inference URL container-reachable#899
benmccown merged 1 commit into
mainfrom
agent-deployment-url-fix

Conversation

@benmccown

@benmccown benmccown commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Deployed agents were calling the wrong URL for inference. Fixed by only ever handing an agent a URL we know is reachable from inside its container.

The bug

inject_gateway_url() bakes the API pod's own base URL into each agent's llms.*.base_url at create time. That URL is wrong from inside an agent container:

  • k8s + embedded-PDP auth: the API pod's NMP_BASE_URL is http://localhost:8080 (correct for its own PDP self-call). Baked into an agent, localhost is the agent itself → calls never reach the platform.
  • Envoy front door: if the base URL pointed at the Envoy auth proxy, agents looped forever on 503s (OpenAI client retry) and took down Envoy + Studio.

The one mode-aware rewrite that existed only wrote NMP_GATEWAY_BASE_URL — a dead env var nothing reads — so it never reached the config the agent runs.

The fix

Enforce one invariant: an agent is only ever handed a known-good, container-reachable URL — never the raw platform base URL.

  • resolve_agent_gateway_url() emits only known-good values per mode:
    • k8s → the in-cluster API Service DNS (NMP_INTERNAL_BASE_URL, set by Helm), or an explicit override. No internal URL → fail fast instead of propagating something unverified.
    • docker → loopback rewritten to host.docker.internal; other hosts pass through.
  • Rebases the agent's llms.*.base_url onto that URL (preserving the IGW path).
  • Adds NEMO_INTERNAL_BASE_URL / NMP_INTERNAL_BASE_URL (and agents.deployments.k8s_internal_base_url); Helm sets it on the api + controller pods.
  • Deletes the dead NMP_GATEWAY_BASE_URL.

Verify

helm template --set platformConfig.auth.enabled=true on the API pod:

NMP_BASE_URL:          http://localhost:8080                 # loopback — was leaking into agents
NMP_INTERNAL_BASE_URL: http://<release>-nemo-platform-api:8080  # correct target now used

ruff + ty + make docs-check clean; unit tests for docker/k8s resolution, the fail-fast path, and config rebasing all pass.

Notes

  • Native-Linux docker may still need gateway_url_override (documented).
  • Pre-existing unrelated test failures in the nemo-agents suite (missing nemo_fabric, CLI table assertions) reproduce on main.

Summary by CodeRabbit

  • New Features

    • Improved deployed-agent connectivity across Docker and Kubernetes environments.
    • Kubernetes deployments now use an in-cluster API address when available.
    • Added automatic inference endpoint adjustment for container-reachable URLs.
    • Deployments now fail with a clear error when Kubernetes connectivity cannot be determined.
  • Documentation

    • Expanded guidance for Docker and Linux networking, including configuration examples and troubleshooting steps.

@benmccown
benmccown requested review from a team as code owners July 24, 2026 22:26
@github-actions github-actions Bot added the fix label Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5ee467bf-ed27-4232-9295-df2305811159

📥 Commits

Reviewing files that changed from the base of the PR and between 407d787 and 663e76d.

📒 Files selected for processing (8)
  • docs/agents/deploy-agents.mdx
  • k8s/helm/templates/api/api-deployment.yaml
  • k8s/helm/templates/core/controller-deployment.yaml
  • plugins/nemo-agents/src/nemo_agents_plugin/config.py
  • plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py
  • plugins/nemo-agents/src/nemo_agents_plugin/utils.py
  • plugins/nemo-agents/tests/unit/test_runner_deployments.py
  • plugins/nemo-agents/tests/unit/test_utils.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • k8s/helm/templates/api/api-deployment.yaml
  • plugins/nemo-agents/src/nemo_agents_plugin/utils.py
  • plugins/nemo-agents/src/nemo_agents_plugin/config.py
  • k8s/helm/templates/core/controller-deployment.yaml
  • plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py

📝 Walkthrough

Walkthrough

Agent deployments now resolve container-reachable gateway URLs, rewrite embedded NAT model URLs, expose Kubernetes internal URLs, and fail fast for unreachable targets. Documentation and tests cover Docker, Kubernetes, overrides, validation, and environment precedence.

Changes

Container-Reachable Agent Deployments

Layer / File(s) Summary
Gateway resolution and internal URL sources
plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py, plugins/nemo-agents/src/nemo_agents_plugin/utils.py, plugins/nemo-agents/src/nemo_agents_plugin/config.py, k8s/helm/templates/*, plugins/nemo-agents/tests/unit/test_runner_deployments.py, plugins/nemo-agents/tests/unit/test_utils.py
Docker and Kubernetes gateway resolution now supports overrides, internal URL environment variables, validation, and corresponding unit coverage.
Deployment configuration and NAT URL baking
plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py, plugins/nemo-agents/tests/unit/test_runner_deployments.py
Deployment creation rewrites inference-gateway NAT URLs, builds configuration from the rewritten data, removes gateway environment injection, and fails before entity creation when Kubernetes resolution is unavailable.
Container reachability guidance
docs/agents/deploy-agents.mdx
Documentation describes Docker Linux bridge addressing, Kubernetes internal URLs, and use of gateway_url_override when containers cannot reach the platform.

Sequence Diagram(s)

sequenceDiagram
  participant DeploymentsRunnerBackend
  participant resolve_agent_gateway_url
  participant rewrite_config_base_urls
  participant build_deployment_config
  DeploymentsRunnerBackend->>resolve_agent_gateway_url: resolve container-reachable gateway
  resolve_agent_gateway_url-->>DeploymentsRunnerBackend: return URL or fail
  DeploymentsRunnerBackend->>rewrite_config_base_urls: rewrite inference-gateway NAT URLs
  DeploymentsRunnerBackend->>build_deployment_config: build configuration from rewritten NAT data
  build_deployment_config-->>DeploymentsRunnerBackend: deployment configuration
Loading

Possibly related PRs

Suggested labels: docs, test

Suggested reviewers: tylersbray, mckornfield

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly matches the main change: making deployed agent inference URLs reachable from inside containers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent-deployment-url-fix

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py`:
- Around line 103-140: The docker branch of container_gateway_url must rewrite
bracketed IPv6 loopback URLs such as http://[::1]:8080. Replace the raw
host-string substitution with parsed URL reconstruction that preserves the
scheme, port, path, query, and fragment while setting the hostname to
host.docker.internal; add coverage for the ::1 case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a26e4eb5-8eb8-4478-8bc8-afaa3f627a59

📥 Commits

Reviewing files that changed from the base of the PR and between 574831b and ec0b8ef.

📒 Files selected for processing (8)
  • docs/agents/deploy-agents.mdx
  • k8s/helm/templates/api/api-deployment.yaml
  • k8s/helm/templates/core/controller-deployment.yaml
  • plugins/nemo-agents/src/nemo_agents_plugin/config.py
  • plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py
  • plugins/nemo-agents/src/nemo_agents_plugin/utils.py
  • plugins/nemo-agents/tests/unit/test_runner_deployments.py
  • plugins/nemo-agents/tests/unit/test_utils.py

Comment thread plugins/nemo-agents/src/nemo_agents_plugin/runner/deployments_backend.py Outdated
@benmccown
benmccown force-pushed the agent-deployment-url-fix branch from ec0b8ef to 407d787 Compare July 24, 2026 22:33
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 27158/34869 77.9% 62.2%
Integration Tests 15966/33581 47.5% 20.0%

Deployed agents baked the API pod's own base URL into their NAT config
llms.*.base_url via inject_gateway_url() at API-create time. Under
embedded-PDP auth the API pod's NMP_BASE_URL is a loopback address
(http://localhost:8080), and in k8s an agent pod resolves loopback to
itself, so agent model calls never reach the platform. If the platform
base URL instead pointed at an auth front-door proxy, agents looped
forever on 503s and could DoS it (and everything behind it).

The only mode-aware rewrite (container_gateway_url) fed a dead
NMP_GATEWAY_BASE_URL env var that nothing reads, so neither the docker
loopback rewrite nor any k8s fix ever reached the config the agent runs.

This fix hands an agent only a base URL we know is container-reachable,
never the raw platform base URL.

- resolve_agent_gateway_url() returns a known-good target per mode:
  k8s uses the in-cluster API Service DNS; docker rewrites loopback
  (including IPv6 [::1]) to host.docker.internal and passes other hosts
  through. It raises for unsupported modes or when k8s has no internal
  URL, rather than deploying an agent that cannot reach the platform.
- rewrite_config_base_urls() rebases each Inference Gateway
  llms.*.base_url onto that reachable address, preserving the path.
- get_internal_base_url() reads NEMO_INTERNAL_BASE_URL then
  NMP_INTERNAL_BASE_URL; also agents.deployments.k8s_internal_base_url.
- Removes the dead NMP_GATEWAY_BASE_URL env var.
- Helm sets NMP_INTERNAL_BASE_URL to the internal API Service DNS on the
  api and controller pods.
- Updates deploy-agents docs; adds unit tests for docker/k8s resolution,
  the fail-fast path, and config rebasing.

Signed-off-by: Ben McCown <[email protected]>
@benmccown
benmccown force-pushed the agent-deployment-url-fix branch from 407d787 to 663e76d Compare July 24, 2026 22:57
@benmccown benmccown self-assigned this Jul 24, 2026
Comment thread plugins/nemo-agents/src/nemo_agents_plugin/config.py
@tylersbray

Copy link
Copy Markdown
Contributor

Reviewed and satisfied with the fix — approving. Root cause and the "only ever hand a container-reachable URL" invariant look right, fail-fast + no orphaned config is clean, and the [::1] case is handled via urlsplit.

Not blockers for the release, just some adjacent edge cases worth tracking as follow-ups:

  1. Reachability vs. authorization. This bug only manifested with auth enabled, and this PR fixes connectivity only. The deployed agent's LLM api_key is "not-used" and build_deployment_config injects no principal/bearer token into the agent container. Worth confirming end-to-end that a deployed agent's IGW call via the internal Service DNS is actually authorized (200), not just reachable, on k8s + embedded-PDP auth — i.e. that the internal DNS path bypasses the front-door PDP. That's the exact gap the e2e tests missed.

  2. Only llms are rewritten. Both inject_gateway_url and rewrite_config_base_urls touch only config["llms"] with _type in (openai, nim). An embedders/retrievers block manually pointed at a loopback IGW URL would keep localhost and be unreachable — same class of bug, out of scope here but worth a follow-up issue.

  3. gateway_url_override is origin-only. rewrite_config_base_urls uses only the resolved gateway's scheme+netloc and re-applies each LLM's own path, so an override that includes a path prefix (e.g. a reverse proxy at /nemo) would be silently dropped. Minor, but worth a one-line note on the config field.

@benmccown
benmccown added this pull request to the merge queue Jul 25, 2026
Merged via the queue into main with commit dae9035 Jul 25, 2026
62 checks passed
@benmccown
benmccown deleted the agent-deployment-url-fix branch July 25, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants