chore: address unresolved PR 208 reviews and fix doc inconsistencies#210
chore: address unresolved PR 208 reviews and fix doc inconsistencies#210sheepdestroyer wants to merge 24 commits into
Conversation
…main.py optimizations
…port-time crashes during pytest collection
…and fix router/Dockerfile dependencies
…ssifier thread pool optimization
…nd Prisma serialization monkey-patch
…e quota reset paths
…am limits and add early arg parsing for --help in start-stack.sh
…ed-core during fallback
…ave test_reasoning_tiers.py
…a CLASSIFIER_INPUT_MAX_CHARS env var
There was a problem hiding this comment.
Sorry @sheepdestroyer, your pull request is larger than the review limit of 150000 diff characters
📝 WalkthroughWalkthroughThis PR combines several independent changes: async improvements in router/main.py (regex token estimation, lazy AA-score loading, async AGY quota checks, cached annotation reads), memory_mcp v2 key format with concurrent deletion, placeholder-based secrets across pod.yaml and start-stack.sh, expanded/reorganized test suites, updated CI/dev scripts, agent policy docs, and a Prisma datetime serializer registration. ChangesDeployment Secrets & Bootstrap Hardening
Router Async Behavior & Memory Key Improvements
Test Infrastructure and New Coverage
Developer Scripts and CI Tooling
Agent Policy and Regression Analysis Notes
LiteLLM Prisma Datetime Serializer
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant Operator
participant StartStack as start-stack.sh
participant EnvFile as .env
participant PodYaml as pod.yaml
Operator->>StartStack: run start-stack.sh
StartStack->>StartStack: generate_uuid() for missing secrets
StartStack->>EnvFile: write generated secrets (chmod 600)
StartStack->>PodYaml: render_pod_yaml() substitutes *_PLACEHOLDER
PodYaml-->>StartStack: validate no PLACEHOLDER tokens remain
sequenceDiagram
participant Client
participant MainRouter as router/main.py
participant AgyProxy as agy_proxy.py
participant CliLog as cli.log
Client->>MainRouter: request routed to llm-routing-agy
MainRouter->>AgyProxy: try_agy_proxy()
AgyProxy->>AgyProxy: await _is_quota_exhausted()
AgyProxy->>CliLog: aiofiles.open + seek/read last lines
CliLog-->>AgyProxy: quota exhaustion markers
AgyProxy-->>MainRouter: fallback / update proxy latency stats
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
/gemini review |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (6)
.github/workflows/test.yml (1)
26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePin
aiofilesversion for CI reproducibility.
httpxis pinned to0.28.1butaiofilesis unpinned. For consistency and reproducible CI builds, consider pinning it.🤖 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 @.github/workflows/test.yml at line 26, The CI dependency install step is leaving aiofiles unpinned, which makes builds less reproducible; update the test workflow’s dependency list so aiofiles uses a fixed version like the other pinned packages. Keep the change localized to the workflow install command in the test job, alongside the existing httpx pin, so CI consistently installs the same aiofiles release.scripts/verification/verify_reasoning_tiers.py (1)
92-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider narrowing broad exception catches.
Both
except Exceptionblocks (lines 92 and 100) catch all exceptions includingKeyboardInterruptandSystemExit. For a verification script this is tolerable, but catchingExceptionexplicitly (or narrowing to(KeyError, IndexError, httpx.HTTPError)) would avoid maskingCtrl+Cduring long runs.Also applies to: 100-100
🤖 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 `@scripts/verification/verify_reasoning_tiers.py` at line 92, The exception handling in verify_reasoning_tiers.py is too broad in the parse and HTTP/error handling paths, so narrow the catches in the parse_inner and outer verification blocks instead of using a blanket handler. Update the try/except around the reasoning tier parsing and request verification logic to catch only the expected failures (for example KeyError, IndexError, and httpx.HTTPError, or a similarly scoped base exception), while avoiding interception of KeyboardInterrupt and SystemExit.Source: Linters/SAST tools
scripts/get_pr_status.py (1)
42-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider catching
subprocess.TimeoutExpiredexplicitly.The generic
Exceptionhandler on line 48 catchesTimeoutExpired(aSubprocessErrorsubclass, notCalledProcessError), producing a less targeted message. Adding an explicit handler before the generic catch would give clearer feedback whenghhangs.Proposed addition
except subprocess.CalledProcessError as e: print(f"Error: Failed to fetch PR status: {e.stderr.strip()}", file=sys.stderr) sys.exit(1) + except subprocess.TimeoutExpired: + print("Error: gh CLI command timed out after 30 seconds", file=sys.stderr) + sys.exit(1) except json.JSONDecodeError:🤖 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 `@scripts/get_pr_status.py` around lines 42 - 50, Add an explicit subprocess.TimeoutExpired handler in get_pr_status.py before the generic except Exception block so gh hangs are reported with a targeted timeout message instead of the fallback error path. Update the exception handling around the subprocess call in the PR status logic to catch TimeoutExpired separately, print a clear timeout-specific stderr message, and exit with the same failure code while leaving the existing CalledProcessError, JSONDecodeError, and generic Exception handling intact.start-stack.sh (2)
195-228: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAdd exit-status checks for direct
openssl randcalls.The
generate_uuid()function (lines 155–164) properly validatesopenssl randexit status and output length, but the directopenssl rand -hexcalls forLANGFUSE_INIT_USER_PASSWORD,REDIS_AUTH,CLICKHOUSE_PASSWORD,ROUTER_API_KEY,MINIO_ROOT_USER, andMINIO_ROOT_PASSWORDdo not. Ifopenssl randfails (e.g., entropy issues), empty secrets will be silently written to.envand used in production.🔒 Proposed fix: add validation helper for direct openssl rand calls
+gen_hex() { + local val + val=$(openssl rand -hex "$1" 2>/dev/null) + local status=$? + if [ $status -ne 0 ] || [ -z "$val" ]; then + echo "❌ Error: Failed to generate secure random value (openssl rand exit $status)." >&2 + return 1 + fi + printf '%s' "$val" +} + if [ -z "$LANGFUSE_INIT_USER_PASSWORD" ]; then - LANGFUSE_INIT_USER_PASSWORD="$(openssl rand -hex 16)" + LANGFUSE_INIT_USER_PASSWORD="$(gen_hex 16)" || exit 1 echo "LANGFUSE_INIT_USER_PASSWORD=\"$LANGFUSE_INIT_USER_PASSWORD\"" >> "$ENV_FILE" echo "✓ Generated new LANGFUSE_INIT_USER_PASSWORD and saved to $ENV_FILE" fi if [ -z "$REDIS_AUTH" ]; then - REDIS_AUTH="$(openssl rand -hex 16)" + REDIS_AUTH="$(gen_hex 16)" || exit 1 echo "REDIS_AUTH=\"$REDIS_AUTH\"" >> "$ENV_FILE"Apply the same pattern to
CLICKHOUSE_PASSWORD,ROUTER_API_KEY(32),MINIO_ROOT_USER(4), andMINIO_ROOT_PASSWORD.🤖 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 `@start-stack.sh` around lines 195 - 228, The secret-generation block in start-stack.sh writes values from direct openssl rand -hex calls without checking whether the command succeeded or returned output. Update the assignments for LANGFUSE_INIT_USER_PASSWORD, REDIS_AUTH, CLICKHOUSE_PASSWORD, ROUTER_API_KEY, MINIO_ROOT_USER, and MINIO_ROOT_PASSWORD to validate the openssl result the same way generate_uuid() does, and only append to ENV_FILE after confirming a non-empty value. Reuse or extract the existing validation pattern so failures abort instead of silently persisting empty secrets.
232-236: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer direct exit-code check over
$?(SC2181).Shellcheck flags the
$?check pattern afteruuid=$(generate_uuid). Useif !directly for clarity and to avoid masking intermediate command failures.♻️ Proposed refactor
if [ -z "$LANGFUSE_PUBLIC_KEY" ]; then - uuid=$(generate_uuid) - if [ $? -ne 0 ] || [ -z "$uuid" ]; then + if ! uuid=$(generate_uuid) || [ -z "$uuid" ]; then echo "❌ Error: Failed to generate LANGFUSE_PUBLIC_KEY." >&2 exit 1 fiApply the same pattern to
LANGFUSE_SECRET_KEY(line 244).Also applies to: 244-248
🤖 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 `@start-stack.sh` around lines 232 - 236, The uuid generation checks in the LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY setup blocks use $? after generate_uuid, which should be replaced with a direct exit-status check. Update the conditional in the generate_uuid assignments to use a negated command check and keep the empty-value guard, so failures are handled clearly without relying on $?; apply the same change in both key-generation sections.Source: Linters/SAST tools
router/tests/test_agy_proxy.py (1)
77-109: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd tests for the
return Falseand seek/tellOSErrorpaths.The three new tests cover: log contains markers →
True, throttled →True, file not found →True. Two meaningful paths are untested:
- Log read succeeds but no quota markers — this is the only path that returns
Falsefor the empty stdout/stderr case (source line 167). Without this test, a regression that always returnsTruewhen the log is readable would go undetected.seek/tellraisesOSError— given the PR objective to propagate these errors, a test should verify the fallback behavior.🧪 Suggested additional tests
+@patch("aiofiles.open") +@patch("router.agy_proxy.time.time") +@pytest.mark.asyncio +async def test_is_quota_exhausted_empty_log_no_markers(mock_time, mock_open): + mock_time.return_value = 1000.0 + mock_file = AsyncMock() + mock_file.seek = AsyncMock() + mock_file.tell = AsyncMock(return_value=100) + mock_file.read = AsyncMock(return_value=b"line 1\nsome other info\nline 3\n") + mock_open.return_value.__aenter__.return_value = mock_file + with patch("router.agy_proxy._last_log_check", 0): + assert await _is_quota_exhausted(0, "", "") is False + +@patch("aiofiles.open") +@patch("router.agy_proxy.time.time") +@pytest.mark.asyncio +async def test_is_quota_exhausted_empty_seek_oserror(mock_time, mock_open): + mock_time.return_value = 1000.0 + mock_file = AsyncMock() + mock_file.seek = AsyncMock(side_effect=OSError("seek failed")) + mock_file.tell = AsyncMock(return_value=100) + mock_open.return_value.__aenter__.return_value = mock_file + with patch("router.agy_proxy._last_log_check", 0): + # OSError swallowed by outer except → falls back to True + assert await _is_quota_exhausted(0, "", "") is True🤖 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/tests/test_agy_proxy.py` around lines 77 - 109, Add coverage in the existing _is_quota_exhausted test module for the missing branches: verify that when aiofiles.open succeeds and the log content has no RESOURCE_EXHAUSTED markers, _is_quota_exhausted returns False for empty stdout/stderr; also add a test where the mocked file’s seek or tell raises OSError so the fallback behavior is exercised. Use the existing _is_quota_exhausted helper and the current aiofiles.open/time patches to keep the tests aligned with the current async flow.
🤖 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/branch_audit_plan.md:
- Around line 54-56: The verification summary in branch_audit_plan.md is stale
and still reports 181 passing tests; update the Verification Status section to
match the actual local run count of 189 passing tests. Locate the existing test
suite result under the Verification Status heading and refresh the tally so the
audit record reflects the current pytest outcome consistently.
In `@pod.yaml`:
- Around line 192-201: The ClickHouse readiness probe is still using an
unauthenticated query, while the container and livenessProbe already require
clickhouse credentials. Update the readinessProbe in pod.yaml to use
clickhouse-client with the same --user clickhouse and --password
CLICKHOUSE_PASSWORD_PLACEHOLDER arguments as the livenessProbe, and then keep
the README health-check table aligned with this authenticated readiness check.
In `@README.md`:
- Line 244: The README tree entry is inconsistent with the actual stack
configuration: update the documented directory name from valkey-lf-data/ to
redis-lf-data/ so it matches start-stack.sh and pod.yaml. Make the change in the
README’s directory layout section where the storage folder is listed, keeping
the rest of the tree description unchanged.
- Around line 580-590: The Health Check note still refers to the default
minioadmin keys, which conflicts with the updated Minio credential flow. Update
the Health Check section to reference the auto-generated credentials documented
in the Configuration section instead of minioadmin, and keep the wording aligned
with the env vars and placeholders used in README.md.
---
Nitpick comments:
In @.github/workflows/test.yml:
- Line 26: The CI dependency install step is leaving aiofiles unpinned, which
makes builds less reproducible; update the test workflow’s dependency list so
aiofiles uses a fixed version like the other pinned packages. Keep the change
localized to the workflow install command in the test job, alongside the
existing httpx pin, so CI consistently installs the same aiofiles release.
In `@router/tests/test_agy_proxy.py`:
- Around line 77-109: Add coverage in the existing _is_quota_exhausted test
module for the missing branches: verify that when aiofiles.open succeeds and the
log content has no RESOURCE_EXHAUSTED markers, _is_quota_exhausted returns False
for empty stdout/stderr; also add a test where the mocked file’s seek or tell
raises OSError so the fallback behavior is exercised. Use the existing
_is_quota_exhausted helper and the current aiofiles.open/time patches to keep
the tests aligned with the current async flow.
In `@scripts/get_pr_status.py`:
- Around line 42-50: Add an explicit subprocess.TimeoutExpired handler in
get_pr_status.py before the generic except Exception block so gh hangs are
reported with a targeted timeout message instead of the fallback error path.
Update the exception handling around the subprocess call in the PR status logic
to catch TimeoutExpired separately, print a clear timeout-specific stderr
message, and exit with the same failure code while leaving the existing
CalledProcessError, JSONDecodeError, and generic Exception handling intact.
In `@scripts/verification/verify_reasoning_tiers.py`:
- Line 92: The exception handling in verify_reasoning_tiers.py is too broad in
the parse and HTTP/error handling paths, so narrow the catches in the
parse_inner and outer verification blocks instead of using a blanket handler.
Update the try/except around the reasoning tier parsing and request verification
logic to catch only the expected failures (for example KeyError, IndexError, and
httpx.HTTPError, or a similarly scoped base exception), while avoiding
interception of KeyboardInterrupt and SystemExit.
In `@start-stack.sh`:
- Around line 195-228: The secret-generation block in start-stack.sh writes
values from direct openssl rand -hex calls without checking whether the command
succeeded or returned output. Update the assignments for
LANGFUSE_INIT_USER_PASSWORD, REDIS_AUTH, CLICKHOUSE_PASSWORD, ROUTER_API_KEY,
MINIO_ROOT_USER, and MINIO_ROOT_PASSWORD to validate the openssl result the same
way generate_uuid() does, and only append to ENV_FILE after confirming a
non-empty value. Reuse or extract the existing validation pattern so failures
abort instead of silently persisting empty secrets.
- Around line 232-236: The uuid generation checks in the LANGFUSE_PUBLIC_KEY and
LANGFUSE_SECRET_KEY setup blocks use $? after generate_uuid, which should be
replaced with a direct exit-status check. Update the conditional in the
generate_uuid assignments to use a negated command check and keep the
empty-value guard, so failures are handled clearly without relying on $?; apply
the same change in both key-generation sections.
🪄 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: 522b4b61-ad57-4bb4-8a1b-6d1ff1582fd9
⛔ Files ignored due to path filters (1)
debug-homepage.pngis excluded by!**/*.png
📒 Files selected for processing (56)
.agents/AGENTS.md.agents/branch_audit_plan.md.agents/jules_regression_analysis.md.github/workflows/test.ymlREADME.mdget_pr_status.pylitellm/entrypoint.pypod.yamlpytest.inirouter/Dockerfilerouter/agy_proxy.pyrouter/main.pyrouter/memory_mcp.pyrouter/test_memory_mcp.pyrouter/tests/conftest.pyrouter/tests/test_agy_proxy.pyrouter/tests/test_detect_active_tool.pyrouter/tests/test_estimate_prompt_tokens.pyrouter/tests/test_get_gemini_oauth_status.pyrouter/tests/test_get_goose_sessions.pyrouter/tests/test_get_redis.pyrouter/tests/test_load_persisted_stats.pyrouter/tests/test_memory_mcp.pyrouter/tests/test_routing_behavior.pyscripts/README.mdscripts/benchmark_classifier.pyscripts/benchmark_tokens.pyscripts/get_pr_status.pyscripts/host_agy_daemon.pyscripts/sync_gemini_token.pyscripts/test_quota_reset.shscripts/verification/verify_breaker.pyscripts/verification/verify_reasoning_tiers.pyscripts/watch_quota.shstart-stack.shtest_memory_mcp.pytests/conftest.pytests/test_a2_verify.pytests/test_agy_behavior.pytests/test_agy_tiers.pytests/test_antigravity.pytests/test_atomic_write.pytests/test_check_http_endpoint.pytests/test_circuit_breaker.pytests/test_classifier_accuracy.pytests/test_compute_free_model_score.pytests/test_get_pr_status.pytests/test_host_agy_daemon.pytests/test_map_tool_to_category.pytests/test_models_proxy.pytests/test_pie_chart_gradient.pytests/test_read_annotations_async.pytests/test_record_tool_usage.pytests/test_src_badge.pytests/test_stream_latency.pytests/test_sync_gemini_token.py
💤 Files with no reviewable changes (6)
- get_pr_status.py
- tests/test_models_proxy.py
- tests/test_circuit_breaker.py
- router/test_memory_mcp.py
- test_memory_mcp.py
- tests/test_a2_verify.py
| ## Verification Status | ||
| * **Test Suite:** Ran `PYTHONPATH=router:. pytest` | ||
| * **Result:** **181 tests passed** successfully (100% success rate). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the verification tally.
This report says 181 tests passed, but the PR objective says the local run completed with 189 passing tests. Please refresh the audit record so the verification section matches the actual run.
🤖 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/branch_audit_plan.md around lines 54 - 56, The verification summary
in branch_audit_plan.md is stale and still reports 181 passing tests; update the
Verification Status section to match the actual local run count of 189 passing
tests. Locate the existing test suite result under the Verification Status
heading and refresh the tally so the audit record reflects the current pytest
outcome consistently.
| value: CLICKHOUSE_PASSWORD_PLACEHOLDER | ||
| image: docker.io/clickhouse/clickhouse-server:26.6.1.1193 | ||
| livenessProbe: | ||
| exec: | ||
| command: | ||
| - clickhouse-client | ||
| - --user | ||
| - clickhouse | ||
| - --password | ||
| - clickhouse | ||
| - CLICKHOUSE_PASSWORD_PLACEHOLDER |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether ClickHouse 26.6.x allows unauthenticated access for the default user
# when CLICKHOUSE_USER and CLICKHOUSE_PASSWORD env vars are set.
# Check ClickHouse docs or test with:
# podman run --rm -e CLICKHOUSE_USER=clickhouse -e CLICKHOUSE_PASSWORD=test123 \
# docker.io/clickhouse/clickhouse-server:26.6.1.1193 \
# clickhouse-client --query "SELECT 1"
# vs
# podman run --rm -e CLICKHOUSE_USER=clickhouse -e CLICKHOUSE_PASSWORD=test123 \
# docker.io/clickhouse/clickhouse-server:26.6.1.1193 \
# clickhouse-client --user clickhouse --password test123 --query "SELECT 1"
echo "Verify ClickHouse readiness probe behavior with and without credentials"Repository: sheepdestroyer/LLM-Routing
Length of output: 236
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the relevant files and exact probe commands.
git ls-files | rg '(^|/)(pod\.yaml|README\.md)$'
echo '--- pod.yaml excerpt ---'
cat -n pod.yaml | sed -n '180,235p'
echo '--- README excerpt ---'
cat -n README.md | sed -n '70,95p'Repository: sheepdestroyer/LLM-Routing
Length of output: 3881
Add credentials to the ClickHouse readiness probe
pod.yaml:208-213 still runs clickhouse-client --query "SELECT 1" without --user clickhouse --password CLICKHOUSE_PASSWORD_PLACEHOLDER, even though the container is configured with a generated password. Match the readiness probe to the liveness probe and update the README health-check table too.
🤖 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 192 - 201, The ClickHouse readiness probe is still
using an unauthenticated query, while the container and livenessProbe already
require clickhouse credentials. Update the readinessProbe in pod.yaml to use
clickhouse-client with the same --user clickhouse and --password
CLICKHOUSE_PASSWORD_PLACEHOLDER arguments as the livenessProbe, and then keep
the README health-check table aligned with this authenticated readiness check.
| ├── valkey-data/ # [Git Ignored] Persistent memory volumes for Valkey Cache | ||
| ├── postgres-data/ # [Git Ignored] Persistent tables for PostgreSQL | ||
| ├── clickhouse-data/ # [Git Ignored] Persistent traces for Langfuse v3 | ||
| ├── valkey-lf-data/ # [Git Ignored] Persistent job queues for Langfuse v3 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Directory name mismatch: valkey-lf-data/ should be redis-lf-data/.
The directory layout tree documents valkey-lf-data/ but both start-stack.sh (line 40: mkdir -p ... redis-lf-data ...) and pod.yaml (line 439: path: .../redis-lf-data, name: redis-lf-storage) use redis-lf-data. This mismatch could confuse developers troubleshooting volume mount issues.
📝 Proposed fix
-├── valkey-lf-data/ # [Git Ignored] Persistent job queues for Langfuse v3
+├── redis-lf-data/ # [Git Ignored] Persistent job queues for Langfuse v3📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ├── valkey-lf-data/ # [Git Ignored] Persistent job queues for Langfuse v3 | |
| ├── redis-lf-data/ # [Git Ignored] Persistent job queues for Langfuse v3 |
🤖 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 `@README.md` at line 244, The README tree entry is inconsistent with the actual
stack configuration: update the documented directory name from valkey-lf-data/
to redis-lf-data/ so it matches start-stack.sh and pod.yaml. Make the change in
the README’s directory layout section where the storage folder is listed,
keeping the rest of the tree description unchanged.
| > Minio credentials are auto-generated by `start-stack.sh` and injected via `.env` placeholders. You **must not** hardcode credentials in `pod.yaml`. | ||
|
|
||
| | Env Var | Value | | ||
| |----------|-------| | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_BUCKET` | `langfuse-events` | | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT` | `http://127.0.0.1:9002` | | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID` | `minioadmin` | | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY` | `minioadmin` | | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID` | `<generated>` (from `MINIO_USER_PLACEHOLDER`) | | ||
| | `LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY` | `<generated>` (from `MINIO_PASSWORD_PLACEHOLDER`) | | ||
| | `S3_FORCE_PATH_STYLE` | `true` | | ||
|
|
||
| Minio runs on ports **9001** (web console) and **9002** (S3 API). Default credentials (`minioadmin` / `minioadmin`) are only meant for local/dev setups. Image pinned to `docker.io/minio/minio:RELEASE.2025-10-15T17-29-55Z`. | ||
| Minio runs on ports **9001** (web console) and **9002** (S3 API). Credentials are generated at first boot and persisted in `.env`. Image pinned to `docker.io/minio/minio:RELEASE.2025-09-07T16-13-09Z`. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stale minioadmin reference in Health Check section.
The Configuration section (lines 580–590) now correctly documents auto-generated credentials, but the Health Check section (line 597) still references "the default minioadmin keys described in Configuration." This is contradictory — the Configuration section no longer describes minioadmin defaults.
📝 Proposed fix: update the Health Check note
-> When deploying to staging or production, ensure that custom credentials are configured (rather than the default `minioadmin` keys described in [Configuration](`#configuration`)), and ensure the deployment's probes and S3 configurations are updated to reference the new values.
+> When deploying to staging or production, ensure that the auto-generated credentials from `start-stack.sh` are replaced with production-appropriate values, and that the deployment's probes and S3 configurations reference the correct credentials.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| > Minio credentials are auto-generated by `start-stack.sh` and injected via `.env` placeholders. You **must not** hardcode credentials in `pod.yaml`. | |
| | Env Var | Value | | |
| |----------|-------| | |
| | `LANGFUSE_S3_EVENT_UPLOAD_BUCKET` | `langfuse-events` | | |
| | `LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT` | `http://127.0.0.1:9002` | | |
| | `LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID` | `minioadmin` | | |
| | `LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY` | `minioadmin` | | |
| | `LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID` | `<generated>` (from `MINIO_USER_PLACEHOLDER`) | | |
| | `LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY` | `<generated>` (from `MINIO_PASSWORD_PLACEHOLDER`) | | |
| | `S3_FORCE_PATH_STYLE` | `true` | | |
| Minio runs on ports **9001** (web console) and **9002** (S3 API). Default credentials (`minioadmin` / `minioadmin`) are only meant for local/dev setups. Image pinned to `docker.io/minio/minio:RELEASE.2025-10-15T17-29-55Z`. | |
| Minio runs on ports **9001** (web console) and **9002** (S3 API). Credentials are generated at first boot and persisted in `.env`. Image pinned to `docker.io/minio/minio:RELEASE.2025-09-07T16-13-09Z`. | |
| > When deploying to staging or production, ensure that the auto-generated credentials from `start-stack.sh` are replaced with production-appropriate values, and that the deployment's probes and S3 configurations reference the correct credentials. |
🤖 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 `@README.md` around lines 580 - 590, The Health Check note still refers to the
default minioadmin keys, which conflicts with the updated Minio credential flow.
Update the Health Check section to reference the auto-generated credentials
documented in the Configuration section instead of minioadmin, and keep the
wording aligned with the env vars and placeholders used in README.md.
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive updates to the routing gateway, including security hardening via dynamic credential generation in start-stack.sh, image version upgrades, and restricting Valkey Cache to 127.0.0.1. It also optimizes performance by offloading blocking file operations to asynchronous threads using aiofiles and asyncio.to_thread, refactors token estimation with a regex-based heuristic, and implements robust URL-encoding for memory keys in memory_mcp.py. Additionally, the test suite has been reorganized and expanded with several new unit and integration tests. The code review feedback suggests further security hardening by restricting valkey-lf to bind only to 127.0.0.1 and adding defensive error handling when parsing the CLASSIFIER_INPUT_MAX_CHARS environment variable.
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.
| - --port | ||
| - '6380' | ||
| - --requirepass | ||
| - langfuse-redis-2026 | ||
| - REDIS_AUTH_PLACEHOLDER |
There was a problem hiding this comment.
Security: Since the pod is configured with hostNetwork: true, any container port binding to all interfaces (0.0.0.0) will be exposed to the external network. Just like the fix applied to valkey-cache, valkey-lf should be restricted to bind only to 127.0.0.1 to prevent unauthorized external access to the Langfuse queue.
- --bind
- 127.0.0.1
- --port
- '6380'
- --requirepass
- REDIS_AUTH_PLACEHOLDER| try: | ||
| client = get_http_client() | ||
| # Truncate prompt to prevent 400 Bad Request in llama-server due to cache-ram limit | ||
| max_chars = int(os.getenv("CLASSIFIER_INPUT_MAX_CHARS", "300")) |
There was a problem hiding this comment.
Defensive programming: os.getenv("CLASSIFIER_INPUT_MAX_CHARS") might not be a valid integer if misconfigured in the environment. It is safer to wrap this in a try-except block with a fallback default value.
try:
max_chars = int(os.getenv("CLASSIFIER_INPUT_MAX_CHARS", "300"))
except ValueError:
max_chars = 300
This PR addresses all outstanding/unresolved reviews and comments from PR #208, and resolves multiple documentation inconsistencies identified in README.md.
Summary of Changes
127.0.0.1(restricting external access under hostNetwork: true)._save_best_model_to_diskto synchronous (was async but scheduled via threadpool/to_thread).copy.deepcopyin annotations.agy_proxy.pyquota checking.{data, tags}, dropping unexpected keys./minio/health/liveinstead of port 9001.README.md.verify_reasoning_tiers.pyand updated all links/paths.README.md.urlopenand threadjoinintests/test_host_agy_daemon.pyto prevent CI hangs.test_memory_mcp.py.All 189 tests pass locally.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation