feat: wire real service agents into chat with LLM tool dispatch + Rivet proxy fix (#3)

# 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>
This commit is contained in:
2026-06-01 09:26:19 +00:00
committed by puter
parent ff0bf5e5f0
commit 9ddbb4a8e5
37 changed files with 2962 additions and 1039 deletions

View File

@@ -19,8 +19,33 @@ services:
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.
# Per the PRD, the Grow Agent + sub-agents are durable actors running on Rivet.
# The unified user agent runs as a durable Rivet actor (changes.md §5).
rivet-engine:
image: rivetgg/engine:latest
container_name: growqr-rivet
@@ -34,7 +59,7 @@ services:
restart: unless-stopped
# The HTTP backend (Hono + Rivet Kit client + Docker manager).
# Mounts the host Docker socket so it can spawn per-user containers.
# Mounts the host Docker socket so it can spawn per-user OpenCode containers.
backend:
build:
context: .
@@ -43,6 +68,8 @@ services:
depends_on:
postgres:
condition: service_healthy
gitea:
condition: service_healthy
rivet-engine:
condition: service_started
ports:
@@ -51,22 +78,45 @@ services:
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}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
GROW_AGENT_MODEL: ${GROW_AGENT_MODEL:-claude-opus-4-7}
SUB_AGENT_MODEL: ${SUB_AGENT_MODEL:-claude-sonnet-4-6}
SERVICE_TOKEN: ${SERVICE_TOKEN:-dev-service-token}
GITEA_IMAGE: ${GITEA_IMAGE:-gitea/gitea:1.22}
OPENCODE_IMAGE: ${OPENCODE_IMAGE:-ghcr.io/sst/opencode:latest}
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 user containers.
# 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).
@@ -78,10 +128,11 @@ services:
retries: 6
restart: unless-stopped
# Note: per-user OpenCode + Gitea containers are NOT defined here.
# The backend spawns them dynamically via dockerode on /actors/provision.
# See src/docker/manager.ts.
# 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: