# Wire All 4 Microservice Agents Into Chat
Wires all 4 microservice-backed agents into the chat so the LLM can call real services and return session URLs.
---
## Changes
### New
* `src/routes/chat.ts`
* Added a direct HTTP chat endpoint.
* When the LLM calls:
* `start_interview_session`
* `analyze_resume`
* `start_roleplay_session`
* `compute_qscore`
* The route executes real service probes and returns live session URLs.
---
### Fixed
* `src/index.ts`
* Rivet proxy now forwards requests to the engine at `localhost:6420`
instead of using `registry.handler()`.
* Prevents the:
```txt
Runtime already started as runner
```
conflict.
* `src/actors/user-actor.ts`
* `receiveMessage()` now returns:
```ts
{
reply,
sessions: []
}
```
* Includes per-module session URLs in responses.
* `docker-compose.yml`
* Fixed:
* Gitea health check port
* Port mapping
* `A2A_ALLOWED_KEY` default value
* `src/config.ts`
* Added:
```ts
resumeServiceUrl
```
* Configured to use port `8002`.
---
### Rewritten
* `prompts/system.txt`
* Reworked into a conversational step-by-step flow.
* Added explicit rule:
> CALL THE TOOL IMMEDIATELY
---
### Updated
* `agents/*.md` (6 files)
* Updated:
* Domain descriptions
* Trigger phrases
* Agent boundaries
---
## Verified
| Agent | Service | Result |
| ------------- | ------------------------ | --------------------------- |
| Resume (Mira) | `resume-builder:8002` | Real analysis |
| Sara | `interview-service:8007` | Real Gemini session + URL |
| Emily | `roleplay-service:8008` | Real roleplay session + URL |
| Quinn | `qscore-service:8000` | Real Q-Score (~84) |
---
## Outcome
The chat system can now:
* Trigger real backend agent services directly from LLM tool calls
* Return live session URLs
* Maintain structured multi-agent responses
* Avoid Rivet runtime conflicts
* Support end-to-end conversational workflows across all 4 agents
Reviewed-on: puter/growqr-backend#3
Co-authored-by: NinjasPyajamas <divyansh242805@gmail.com>
Co-committed-by: NinjasPyajamas <divyansh242805@gmail.com>
139 lines
5.1 KiB
YAML
139 lines
5.1 KiB
YAML
services:
|
|
# Postgres for backend metadata (users, actor registry, billing,
|
|
# repo/container mappings). PRD §11.
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
container_name: growqr-postgres
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-growqr}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-growqr}
|
|
POSTGRES_DB: ${POSTGRES_DB:-growqr}
|
|
ports:
|
|
- "5432:5432"
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-growqr}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
restart: unless-stopped
|
|
|
|
# ── Central Gitea (one org-wide instance, changes.md §2A) ──
|
|
# Every user gets a repo inside the GrowQR organization on this instance.
|
|
# Per-user Gitea containers are REMOVED — the backend no longer spawns them.
|
|
gitea:
|
|
image: gitea/gitea:1.22
|
|
container_name: growqr-gitea
|
|
environment:
|
|
USER_UID: "1000"
|
|
USER_GID: "1000"
|
|
GITEA__server__ROOT_URL: http://localhost:3001
|
|
GITEA__server__SSH_PORT: "2222"
|
|
GITEA__security__INSTALL_LOCK: "true"
|
|
GITEA__service__DISABLE_REGISTRATION: "true"
|
|
ports:
|
|
- "3001:3000" # HTTP (Gitea listens on 3000 internally)
|
|
- "2222:2222" # SSH
|
|
volumes:
|
|
- gitea-data:/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -qO- http://localhost:3000/api/v1/version || exit 1"]
|
|
interval: 10s
|
|
timeout: 10s
|
|
retries: 15
|
|
restart: unless-stopped
|
|
|
|
# Self-hosted Rivet engine. The backend's Rivet Kit client connects here.
|
|
# The unified user agent runs as a durable Rivet actor (changes.md §5).
|
|
rivet-engine:
|
|
image: rivetgg/engine:latest
|
|
container_name: growqr-rivet
|
|
ports:
|
|
- "6420:6420" # API
|
|
- "6421:6421" # Guard/edge
|
|
environment:
|
|
RIVET__AUTH__ADMIN_TOKEN: ${RIVET_ADMIN_TOKEN:-dev-admin-token}
|
|
volumes:
|
|
- rivet-data:/data
|
|
restart: unless-stopped
|
|
|
|
# The HTTP backend (Hono + Rivet Kit client + Docker manager).
|
|
# Mounts the host Docker socket so it can spawn per-user OpenCode containers.
|
|
backend:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: growqr-backend
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
gitea:
|
|
condition: service_healthy
|
|
rivet-engine:
|
|
condition: service_started
|
|
ports:
|
|
- "4000:4000"
|
|
environment:
|
|
PORT: 4000
|
|
NODE_ENV: ${NODE_ENV:-production}
|
|
DATABASE_URL: postgres://${POSTGRES_USER:-growqr}:${POSTGRES_PASSWORD:-growqr}@postgres:5432/${POSTGRES_DB:-growqr}
|
|
# Central Gitea (shared org-wide instance)
|
|
GITEA_URL: http://gitea:3001
|
|
GITEA_ADMIN_USER: ${GITEA_ADMIN_USER:-growqr-admin}
|
|
GITEA_ADMIN_PASSWORD: ${GITEA_ADMIN_PASSWORD:-growqr-admin-dev}
|
|
GITEA_ADMIN_TOKEN: ${GITEA_ADMIN_TOKEN:-}
|
|
GITEA_ORG_NAME: ${GITEA_ORG_NAME:-growqr}
|
|
# Version tracking for image rollouts (changes.md §9)
|
|
OPENCODE_IMAGE_VERSION: ${OPENCODE_IMAGE_VERSION:-1.0.0}
|
|
MIGRATION_VERSION: ${MIGRATION_VERSION:-1}
|
|
PROMPT_VERSION: ${PROMPT_VERSION:-1}
|
|
# Rivet
|
|
RIVET_ENDPOINT: http://rivet-engine:6420
|
|
RIVET_CLIENT_ENDPOINT: ${RIVET_CLIENT_ENDPOINT:-http://127.0.0.1:4000/api/rivet}
|
|
# Auth
|
|
CLERK_SECRET_KEY: ${CLERK_SECRET_KEY}
|
|
CLERK_PUBLISHABLE_KEY: ${CLERK_PUBLISHABLE_KEY}
|
|
SERVICE_TOKEN: ${SERVICE_TOKEN:-dev-service-token}
|
|
A2A_ALLOWED_KEY: ${A2A_ALLOWED_KEY:-dev-a2a-key}
|
|
# LLM
|
|
OPENCODE_API_KEY: ${OPENCODE_API_KEY}
|
|
LLM_PROVIDER: ${LLM_PROVIDER:-opencode}
|
|
LLM_BASE_URL: ${LLM_BASE_URL:-https://opencode.ai/zen/v1}
|
|
LLM_MODEL: ${LLM_MODEL:-kimi-k2.6}
|
|
GROW_AGENT_MODEL: ${GROW_AGENT_MODEL:-kimi-k2.6}
|
|
# Per-user OpenCode containers
|
|
OPENCODE_IMAGE: ${OPENCODE_IMAGE:-ghcr.io/anomalyco/opencode:latest}
|
|
USER_CONTAINER_HOST: ${USER_CONTAINER_HOST:-host.docker.internal}
|
|
USER_DATA_ROOT: /data/users
|
|
USER_PORT_RANGE_START: 20000
|
|
USER_PORT_RANGE_END: 29999
|
|
# Microservices
|
|
INTERVIEW_SERVICE_URL: ${INTERVIEW_SERVICE_URL:-http://host.docker.internal:8007}
|
|
ROLEPLAY_SERVICE_URL: ${ROLEPLAY_SERVICE_URL:-http://host.docker.internal:8008}
|
|
QSCORE_SERVICE_URL: ${QSCORE_SERVICE_URL:-http://host.docker.internal:8000}
|
|
RESUME_SERVICE_URL: ${RESUME_SERVICE_URL:-http://host.docker.internal:8002}
|
|
# Frontend
|
|
FRONTEND_ORIGIN: ${FRONTEND_ORIGIN:-http://localhost:3000}
|
|
volumes:
|
|
# Docker-out-of-Docker: backend uses host Docker to spawn per-user OpenCode containers.
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
# Shared host dir that per-user containers will also bind-mount their
|
|
# workspace from (so backend and spawned containers see the same files).
|
|
- ./.data/users:/data/users
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -qO- http://localhost:4000/healthz || exit 1"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 6
|
|
restart: unless-stopped
|
|
|
|
# Only per-user OpenCode containers are spawned dynamically now.
|
|
# Gitea is a central shared service defined above.
|
|
# See src/docker/manager.ts for the per-user OpenCode lifecycle.
|
|
|
|
volumes:
|
|
rivet-data:
|
|
postgres-data:
|
|
gitea-data:
|