Skip to content

chore: learn deployment guidelines and resolve console links dynamically#240

Closed
sheepdestroyer wants to merge 13 commits into
masterfrom
chore/learn-deployment-guidelines
Closed

chore: learn deployment guidelines and resolve console links dynamically#240
sheepdestroyer wants to merge 13 commits into
masterfrom
chore/learn-deployment-guidelines

Conversation

@sheepdestroyer

@sheepdestroyer sheepdestroyer commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Pivotal changes made during production deployment: 1. Updated AGENTS.md with firewall prerequisites and sudo password trailing space warnings. 2. Resolved dashboard console links dynamically using BASEURL / BASE_URL env vars or HTTP request host headers.

Summary by Sourcery

Document production deployment steps and make dashboard console links resolve against the external host instead of hardcoded localhost.

Enhancements:

  • Make dashboard observability and admin console links use a configurable external host derived from environment variables or the incoming request rather than localhost.

Documentation:

  • Add a production deployment checklist with host prerequisites, firewall requirements, and sudo password handling notes to the agents guide.

Summary by CodeRabbit

  • New Features
    • Dashboard now generates “Open” and “Quick Console Links” using the current external host and scheme, so shortcuts work correctly outside localhost.
    • Updated startup messaging to show externally reachable HTTPS endpoints and dashboard/admin URLs.
  • Bug Fixes
    • Adjusted gateway health check endpoints to align with the new routing path.
  • Documentation
    • Updated the Notebook reference name and added a production deployment checklist (prerequisites, fresh deploy steps, and verification notes).

@sourcery-ai

sourcery-ai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Documents the production deployment process for the 'boy' host and makes the dashboard’s external console links resolve dynamically from environment or request host instead of being hardcoded to localhost.

File-Level Changes

Change Details Files
Add detailed production deployment checklist and notes for the 'boy' host to the agents documentation.
  • Document one-time host prerequisites including firewall, sysctl, SSH alias, mounts, and HAProxy paths.
  • Add ordered fresh deploy steps covering repo cleanup, clone, stack startup, HAProxy podman run, and host-side daemon startup.
  • Clarify operational notes about systemd limitations, sudo password file whitespace handling, and when to use full image rebuilds.
.agents/AGENTS.md
Resolve dashboard console links dynamically using BASEURL/BASE_URL or the incoming request host header.
  • Change the /dashboard handler to accept the Request object and derive an external_host from BASEURL/BASE_URL env vars or request.base_url.host, with hostname parsing when a full URL is provided.
  • Replace hardcoded http://localhost:* links in the dashboard HTML template with http://{external_host}:* for Langfuse, LiteLLM, and Llama.cpp UIs.
router/main.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@sheepdestroyer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3177c087-b6c6-425d-bc0e-bbc51ef5cc22

📥 Commits

Reviewing files that changed from the base of the PR and between 49b4f3a and 86442b5.

📒 Files selected for processing (5)
  • .agents/AGENTS.md
  • litellm/config.yaml
  • pod.yaml
  • router/free_models_roster.json
  • router/main.py
📝 Walkthrough

Walkthrough

The dashboard now builds external UI links from request/env host data, the Litellm gateway is mounted under /llm-routing/litellm, deployment output prints routed HTTPS endpoints, and AGENTS.md adds a production deployment checklist.

Changes

Dashboard and deployment routing

Layer / File(s) Summary
Dashboard host resolution and links
router/main.py
/dashboard now derives and validates an external host and renders Langfuse, LiteLLM, and router links from computed URLs instead of hardcoded localhost targets.
Gateway root path and probes
pod.yaml
litellm-gateway is configured with SERVER_ROOT_PATH=/llm-routing/litellm, and its liveness/readiness probes target the routed paths.
Deployment output URLs
start-stack.sh
Success messages print routed HTTPS dashboard/admin URLs for existing-pod and first-deploy paths, while leaving the local entry URL unchanged.
Deployment checklist notes
.agents/AGENTS.md
The notebook reference name is updated and a production deployment checklist is added with prerequisites, deploy steps, and operational notes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the two main changes: deployment guidance updates and dynamic console link resolution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/learn-deployment-guidelines

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request adds a comprehensive production deployment checklist to the agent documentation and updates the /dashboard endpoint in router/main.py to dynamically resolve the external host for external service links (Langfuse, LiteLLM, and Llama.cpp) instead of hardcoding localhost. However, a critical runtime error was identified in the host resolution logic where request.base_url.host is accessed; this should be corrected to request.base_url.hostname to prevent an AttributeError.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread router/main.py Outdated
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

@sourcery-ai sourcery-ai 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.

Hey - I've found 1 issue, and left some high level feedback:

  • When deriving external_host, using only request.base_url.host and stripping BASEURL/BASE_URL down to hostname loses any custom port or scheme; consider keeping the full netloc (and matching the request scheme) so links work correctly behind non-standard ports or HTTPS proxies.
  • The urllib.parse import inside get_dashboard runs on every request; it would be cleaner and slightly more efficient to move this import to the module level.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When deriving `external_host`, using only `request.base_url.host` and stripping `BASEURL`/`BASE_URL` down to `hostname` loses any custom port or scheme; consider keeping the full netloc (and matching the request scheme) so links work correctly behind non-standard ports or HTTPS proxies.
- The `urllib.parse` import inside `get_dashboard` runs on every request; it would be cleaner and slightly more efficient to move this import to the module level.

## Individual Comments

### Comment 1
<location path="router/main.py" line_range="3072-3083" />
<code_context>
-async def get_dashboard():
+async def get_dashboard(request: Request):
     """Render the router main dashboard HTML showing system metrics, health checks, and recent token usage."""
+    external_host = os.getenv("BASEURL") or os.getenv("BASE_URL")
+    if not external_host:
+        external_host = request.base_url.host or "localhost"
+    else:
+        if "://" in external_host:
+            from urllib.parse import urlparse
+            external_host = urlparse(external_host).hostname or "localhost"
+
     data = await get_dashboard_data()
</code_context>
<issue_to_address>
**suggestion (bug_risk):** External host parsing can mis-handle values without scheme or with trailing slashes

Because normalization only happens when `external_host` contains `"://"`, values like `"example.com/"` or ones with a path but no scheme can be used as-is, producing invalid hosts. It would be safer to always parse non-empty env values (e.g., with `urlparse`) or at least strip paths and trailing slashes so `external_host` is always a bare hostname.

```suggestion
@app.get("/dashboard", response_class=HTMLResponse)
async def get_dashboard(request: Request):
    """Render the router main dashboard HTML showing system metrics, health checks, and recent token usage."""
    external_host_env = os.getenv("BASEURL") or os.getenv("BASE_URL")

    if external_host_env:
        from urllib.parse import urlparse

        # Normalize env value to a bare hostname
        value = external_host_env.strip()

        if "://" in value:
            # Treat as URL and extract hostname only
            parsed = urlparse(value)
            external_host = parsed.hostname
        else:
            # Strip any path component and trailing slashes, then drop any port
            value = value.strip().strip("/")
            if "/" in value:
                value = value.split("/", 1)[0]
            # At this point value is like "host" or "host:port"
            external_host = value.split(":", 1)[0] or None

        if not external_host:
            # Fallback to request host, then localhost
            external_host = request.base_url.host or "localhost"
    else:
        external_host = request.base_url.host or "localhost"

    data = await get_dashboard_data()
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread router/main.py
Comment on lines 3072 to 3083
@app.get("/dashboard", response_class=HTMLResponse)
async def get_dashboard():
async def get_dashboard(request: Request):
"""Render the router main dashboard HTML showing system metrics, health checks, and recent token usage."""
external_host = os.getenv("BASEURL") or os.getenv("BASE_URL")
if not external_host:
external_host = request.base_url.host or "localhost"
else:
if "://" in external_host:
from urllib.parse import urlparse
external_host = urlparse(external_host).hostname or "localhost"

data = await get_dashboard_data()

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.

suggestion (bug_risk): External host parsing can mis-handle values without scheme or with trailing slashes

Because normalization only happens when external_host contains "://", values like "example.com/" or ones with a path but no scheme can be used as-is, producing invalid hosts. It would be safer to always parse non-empty env values (e.g., with urlparse) or at least strip paths and trailing slashes so external_host is always a bare hostname.

Suggested change
@app.get("/dashboard", response_class=HTMLResponse)
async def get_dashboard():
async def get_dashboard(request: Request):
"""Render the router main dashboard HTML showing system metrics, health checks, and recent token usage."""
external_host = os.getenv("BASEURL") or os.getenv("BASE_URL")
if not external_host:
external_host = request.base_url.host or "localhost"
else:
if "://" in external_host:
from urllib.parse import urlparse
external_host = urlparse(external_host).hostname or "localhost"
data = await get_dashboard_data()
@app.get("/dashboard", response_class=HTMLResponse)
async def get_dashboard(request: Request):
"""Render the router main dashboard HTML showing system metrics, health checks, and recent token usage."""
external_host_env = os.getenv("BASEURL") or os.getenv("BASE_URL")
if external_host_env:
from urllib.parse import urlparse
# Normalize env value to a bare hostname
value = external_host_env.strip()
if "://" in value:
# Treat as URL and extract hostname only
parsed = urlparse(value)
external_host = parsed.hostname
else:
# Strip any path component and trailing slashes, then drop any port
value = value.strip().strip("/")
if "/" in value:
value = value.split("/", 1)[0]
# At this point value is like "host" or "host:port"
external_host = value.split(":", 1)[0] or None
if not external_host:
# Fallback to request host, then localhost
external_host = request.base_url.host or "localhost"
else:
external_host = request.base_url.host or "localhost"
data = await get_dashboard_data()

@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: 2

🧹 Nitpick comments (1)
.agents/AGENTS.md (1)

66-68: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Verify that -k is intentional here.

If this is meant to validate the production HTTPS setup, curl -k bypasses cert/hostname verification and can hide a broken HAProxy cert configuration. Remove it unless you explicitly want a reachability-only probe.

🤖 Prompt for 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.

In @.agents/AGENTS.md around lines 66 - 68, The end-to-end verification step
uses curl with -k, which bypasses HTTPS certificate and hostname validation.
Update the verification guidance in AGENTS.md so the curl command uses normal
TLS verification unless this is explicitly intended as a reachability-only
probe, and keep the existing resolve/URL check in place so the HAProxy cert
setup is actually validated.
🤖 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 @.agents/AGENTS.md:
- Line 75: The AGENTS.md note includes a literal sudo password example that
should not be committed as-is. Update the Sudo Password Precaution guidance to
replace the exposed value with a neutral placeholder while keeping the warning
about preserving exact bytes, and ensure the surrounding text still points
readers to the password-handling behavior without revealing any real secret.

In `@router/main.py`:
- Around line 3075-3081: `external_host` is being taken from
`request.base_url.host`/`BASEURL` and later inserted into HTML, so sanitize it
before any template or href usage. Update the logic around `external_host` in
the request handling flow to either HTML-escape the value or strictly validate
it against a safe hostname allowlist before it reaches the dashboard links. Keep
the fix localized to the `external_host` resolution path so the downstream href
generation sites use only sanitized content.

---

Nitpick comments:
In @.agents/AGENTS.md:
- Around line 66-68: The end-to-end verification step uses curl with -k, which
bypasses HTTPS certificate and hostname validation. Update the verification
guidance in AGENTS.md so the curl command uses normal TLS verification unless
this is explicitly intended as a reachability-only probe, and keep the existing
resolve/URL check in place so the HAProxy cert setup is actually validated.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 694a5a96-64fe-49ec-999a-93ce953428ea

📥 Commits

Reviewing files that changed from the base of the PR and between 454593c and ee818d7.

📒 Files selected for processing (2)
  • .agents/AGENTS.md
  • router/main.py

Comment thread .agents/AGENTS.md Outdated
Comment thread router/main.py Outdated
@sheepdestroyer

Copy link
Copy Markdown
Owner Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request updates the AGENTS.md documentation with a production deployment checklist, configures a server root path for LiteLLM in pod.yaml, and dynamically resolves external dashboard URLs in router/main.py. The review feedback highlights two main issues: first, the URL resolution logic in router/main.py fails to correctly parse and validate hostnames that include ports; second, the deployment commands in AGENTS.md for starting the host-side daemon are missing the required SSH prefix and reference an incorrect path.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread router/main.py Outdated
Comment on lines +3075 to +3102
external_host = os.getenv("BASEURL") or os.getenv("BASE_URL")
if not external_host:
external_host = request.base_url.hostname or "localhost"
else:
if "://" in external_host:
from urllib.parse import urlparse
external_host = urlparse(external_host).hostname or "localhost"

domain = "vendeuvre.lan"
import re
if not isinstance(external_host, str) or not re.match(r"^[a-zA-Z0-9.-]+$", external_host):
external_host = "localhost"

if external_host and domain in external_host:
langfuse_url = f"https://{external_host}/llm-routing/langfuse"
litellm_url = f"https://{external_host}/llm-routing/litellm/ui"
llama_url = f"https://{external_host}/llm-routing/llama/"
elif domain in (request.base_url.hostname or ""):
scheme = request.url.scheme if re.match(r"^(?:http|https)$", request.url.scheme) else "https"
netloc = request.url.netloc if re.match(r"^[a-zA-Z0-9.-]+(?::\d+)?$", request.url.netloc) else "localhost"
base = f"{scheme}://{netloc}"
langfuse_url = f"{base}/llm-routing/langfuse"
litellm_url = f"{base}/llm-routing/litellm/ui"
llama_url = f"{base}/llm-routing/llama/"
else:
langfuse_url = f"http://{external_host}:3001"
litellm_url = f"http://{external_host}:4000/ui"
llama_url = f"http://{external_host}:8080"

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.

high

There are two issues with how external_host is resolved and validated:

  1. If BASE_URL or BASEURL contains a port but no scheme (e.g., x570.vendeuvre.lan:8443), the validation regex r"^[a-zA-Z0-9.-]+$" fails because of the colon, causing it to fall back to "localhost".
  2. If BASE_URL contains a scheme and a port (e.g., https://x570.vendeuvre.lan:8443), urlparse(external_host).hostname discards the port. This breaks the reverse proxy links (e.g., langfuse_url) which need to preserve the port.

To fix this, we can parse both the hostname (for the local fallback ports) and the netloc (to preserve the port for reverse proxy domain links), and validate netloc with a regex that allows an optional port.

    external_host_env = os.getenv("BASEURL") or os.getenv("BASE_URL")
    if external_host_env:
        if "://" not in external_host_env:
            from urllib.parse import urlparse
            parsed = urlparse(f"http://{external_host_env}")
        else:
            from urllib.parse import urlparse
            parsed = urlparse(external_host_env)
        external_host = parsed.hostname or "localhost"
        external_netloc = parsed.netloc or "localhost"
    else:
        external_host = request.base_url.hostname or "localhost"
        external_netloc = request.base_url.netloc or "localhost"

    domain = "vendeuvre.lan"
    import re
    if not isinstance(external_host, str) or not re.match(r"^[a-zA-Z0-9.-]+$", external_host):
        external_host = "localhost"
    if not isinstance(external_netloc, str) or not re.match(r"^[a-zA-Z0-9.-]+(?::\d+)?$", external_netloc):
        external_netloc = "localhost"

    if external_netloc and domain in external_netloc:
        langfuse_url = f"https://{external_netloc}/llm-routing/langfuse"
        litellm_url = f"https://{external_netloc}/llm-routing/litellm/ui"
        llama_url = f"https://{external_netloc}/llm-routing/llama/"
    elif domain in (request.base_url.hostname or ""):
        scheme = request.url.scheme if re.match(r"^(?:http|https)$", request.url.scheme) else "https"
        netloc = request.url.netloc if re.match(r"^[a-zA-Z0-9.-]+(?::\d+)?$", request.url.netloc) else "localhost"
        base = f"{scheme}://{netloc}"
        langfuse_url = f"{base}/llm-routing/langfuse"
        litellm_url = f"{base}/llm-routing/litellm/ui"
        llama_url = f"{base}/llm-routing/llama/"
    else:
        langfuse_url = f"http://{external_host}:3001"
        litellm_url = f"http://{external_host}:4000/ui"
        llama_url = f"http://{external_host}:8080"

Comment thread .agents/AGENTS.md Outdated
Comment on lines +62 to +64
# 5. Start the host-side agy daemon
pkill -f host_agy_daemon.py || true
nohup python3 ~/LLM-Routing/scripts/host_agy_daemon.py >/tmp/agy-daemon.log 2>&1 &

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.

medium

In step 5 of the deployment checklist, the commands to start the host-side agy daemon are missing the ssh boy prefix. If run as-is, they will execute on the local machine instead of the remote host boy. Additionally, the path to the script should point to the cloned repository location /mnt/DATA/boy/LLM-Routing/scripts/host_agy_daemon.py instead of ~/LLM-Routing/scripts/host_agy_daemon.py.

Suggested change
# 5. Start the host-side agy daemon
pkill -f host_agy_daemon.py || true
nohup python3 ~/LLM-Routing/scripts/host_agy_daemon.py >/tmp/agy-daemon.log 2>&1 &
# 5. Start the host-side agy daemon
ssh boy "pkill -f host_agy_daemon.py || true"
ssh boy "nohup python3 /mnt/DATA/boy/LLM-Routing/scripts/host_agy_daemon.py >/tmp/agy-daemon.log 2>&1 &"

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pod.yaml (1)

48-66: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Use the direct LiteLLM health endpoints here
SERVER_ROOT_PATH only sets FastAPI root_path; it doesn’t expose these probes under /llm-routing/litellm. Point them at /ping and /health/readiness so the kubelet hits the actual in-pod routes.

🤖 Prompt for 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.

In `@pod.yaml` around lines 48 - 66, The LiteLLM probes are using the routed path
instead of the actual in-pod health endpoints. Update the livenessProbe and
readinessProbe in the litellm-gateway pod spec to call LiteLLM’s direct /ping
and /health/readiness routes, since SERVER_ROOT_PATH only configures FastAPI
root_path and does not change the probe target path.
🧹 Nitpick comments (1)
router/main.py (1)

3083-3098: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the production domain configurable instead of hardcoding vendeuvre.lan.

The HTTPS route prefix logic only activates when the host matches the hardcoded domain = "vendeuvre.lan". Any deployment on a different domain silently falls back to direct HTTP port links, which won't work behind a reverse proxy. Extract this to an env var (e.g., ROUTING_DOMAIN) with a sensible default.

♻️ Proposed refactor
     domain = os.getenv("ROUTING_DOMAIN", "vendeuvre.lan")
     import re
     if not isinstance(external_host, str) or not re.match(r"^[a-zA-Z0-9.-]+$", external_host):
         external_host = "localhost"
🤖 Prompt for 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.

In `@router/main.py` around lines 3083 - 3098, The routing URL selection logic in
the main request handler uses a hardcoded production domain, which prevents
HTTPS route prefixes from working on other deployments. Update the `domain`
value in the `router/main.py` routing block to read from a configurable
environment variable such as `ROUTING_DOMAIN`, with a safe default fallback, and
keep the existing `external_host` and `request.base_url.hostname` checks using
that configurable domain so reverse-proxy URLs are generated correctly.
🤖 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.

Outside diff comments:
In `@pod.yaml`:
- Around line 48-66: The LiteLLM probes are using the routed path instead of the
actual in-pod health endpoints. Update the livenessProbe and readinessProbe in
the litellm-gateway pod spec to call LiteLLM’s direct /ping and
/health/readiness routes, since SERVER_ROOT_PATH only configures FastAPI
root_path and does not change the probe target path.

---

Nitpick comments:
In `@router/main.py`:
- Around line 3083-3098: The routing URL selection logic in the main request
handler uses a hardcoded production domain, which prevents HTTPS route prefixes
from working on other deployments. Update the `domain` value in the
`router/main.py` routing block to read from a configurable environment variable
such as `ROUTING_DOMAIN`, with a safe default fallback, and keep the existing
`external_host` and `request.base_url.hostname` checks using that configurable
domain so reverse-proxy URLs are generated correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26e69e61-1db9-4e39-bb62-227552f17901

📥 Commits

Reviewing files that changed from the base of the PR and between ee818d7 and 49b4f3a.

📒 Files selected for processing (4)
  • .agents/AGENTS.md
  • pod.yaml
  • router/main.py
  • start-stack.sh
✅ Files skipped from review due to trivial changes (2)
  • start-stack.sh
  • .agents/AGENTS.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant