Integration prompt — ai-ahu-chatbot
Paste this into a Claude Code session running inside the
ai-ahu-chatbotrepo. Fill in<GATEWAY_URL>before pasting (e.g.http://192.168.83.20:8200), or leave it and only the commented env entries will reference it.
We are introducing a central GPU/LLM gateway (ahu-gpu-manager) that all model traffic must flow through. It is OpenAI-compatible, adds priority queueing, and emits audit events. Your job is to prepare this repo for it. Hard constraint: every change must be backwards-compatible and dormant — with no new env vars set, behavior must be byte-for-byte identical to today. Do not flip any live env values in infra/env/*.env; only add commented-out entries showing the future values.
1. Header propagation in the Agno agents
In apps/internal-agent/dash/agents.py and its mirror apps/public-agent/dash/agents.py, the models built by _resolve_model() / _build_model_from_slot() (via OpenAILike) currently send no identifying headers — only the orchestrator's direct calls do. Add default headers to the model construction:
X-Tenant-Id: ahu-chatbotX-Surface: from the existingSURFACEenv (internal|public)X-Priority:planningfor the tool-loop model,synthesisfor the synthesis model (mirroring whatapps/public-web/src/lib/orchestrator/orchestrate.tsalready sends)
If Agno supports per-run extra headers, also propagate the per-run user_id as X-User-Id; if it only supports client-level headers, add the static ones and leave a # TODO(gateway) noting the per-run limitation. Verify against the installed agno==2.4.7 API — do not guess.
2. Close the bare-OpenAI egress
apps/internal-agent/app/api/knowledge.py:421 (and the public-agent mirror if present) constructs a bare OpenAI() client calling model="gpt-4o" — this bypasses MODEL_GATEWAY_URL and hits api.openai.com directly. Change it to construct the client from the same gateway-resolution logic the agents use (base_url from MODEL_GATEWAY_URL + /v1 when set, model name from a new env KNOWLEDGE_LLM_MODEL defaulting to the current gpt-4o). When MODEL_GATEWAY_URL is unset, behavior must be unchanged.
3. Queue-awareness in the orchestrator LLM client
In apps/public-web/src/lib/orchestrator/llm/client.ts:
- On
429or503responses, readRetry-AfterandX-Queue-Depthheaders and include them in the thrown error object so callers can degrade with a friendly "sistem sedang sibuk" message instead of a generic failure. - Add opt-in structured queue events: when a new env
LLM_QUEUE_EVENTS=onis set, send headerX-Queue-Events: onon streaming requests and parse SSE frames of the formevent: queue/data: {"position":N,"eta_ms":M}that may arrive before the first chat chunk. Surface them via a callback soorchestrate.tscan forward a status event to the browser stream (reuse the existing SSE status/error event channel) — the user should see "Antrian ke-N (±Xs)" rather than a spinner. Unknown SSE event types must be ignored gracefully (today's vLLM sends none). - Send an
Idempotency-Keyheader on each request, derived from the existing per-request/session identifiers.
4. Env preparation (commented, not active)
In infra/env/internal.env, infra/env/public.env, infra/env/shared.env, add commented blocks:
# --- ahu-gpu-manager (do not enable until gateway is live) ---
# MODEL_GATEWAY_URL=<GATEWAY_URL>
# SYNTHESIS_GATEWAY_URL=<GATEWAY_URL>/synthesis
# EMBEDDER_BASE_URL=<GATEWAY_URL>/v1
# LLM_QUEUE_EVENTS=on
Note in a comment that once the gateway is live, the DashScope SYNTHESIS_API_KEY moves server-side into the gateway registry and gets removed from this repo.
5. Verification
- Run the existing test suites; nothing may regress.
- With no new envs set, confirm (by reading the constructed clients or a local smoke run) that request URLs, headers minus the new static X- headers, and bodies are unchanged against the current vLLM endpoint.
- Type-check and lint clean.
Report back: files changed, any Agno API limitations found for per-run headers, and anything in the header/queue-event contract that needed interpretation.