feat: consolidate project runtime deployment
This commit is contained in:
@@ -13,10 +13,9 @@
|
||||
# /health liveness probe
|
||||
# /internal/project-setup single-call project setup coordinator
|
||||
# /internal/agents/<agentId>/events agent event dispatch callback
|
||||
# - The RivetKit serverless registry at /internal/rivet/* is NOT proxied. It
|
||||
# is a private loopback callback the Engine reaches directly at
|
||||
# http://127.0.0.1:3000/internal/rivet; exposing it publicly would widen the
|
||||
# private worker protocol.
|
||||
# - The AgentOS registry runs in-process as a native envoy (Rivet Mode A),
|
||||
# so there is no /internal/rivet/* route to expose. Exposing a private
|
||||
# worker protocol publicly would widen the attack surface needlessly.
|
||||
# - Former routes (/agents/zopu/*, /internal/work-attempts/*, /workflows/*,
|
||||
# /api/rivet/*) are intentionally absent: they are stale and not part of the
|
||||
# current Convex→agents contract.
|
||||
|
||||
+13
-15
@@ -1,36 +1,35 @@
|
||||
# Zopu VDS agents deployment
|
||||
|
||||
This directory holds the systemd unit, environment template, and Caddy reverse-proxy config that run the single Zopu agents Node process on the VDS. It supersedes the former container deployment for the agents process.
|
||||
This directory holds the systemd unit, environment template, and Caddy reverse-proxy config that run the Zopu intelligence runtime on the VDS. It supersedes the former container deployment for the agents process.
|
||||
|
||||
## Runtime topology
|
||||
|
||||
One Node process (`zopu-agents.service`) runs the whole intelligence runtime:
|
||||
One Node process hosts the entire runtime:
|
||||
|
||||
```
|
||||
zopu-agents.service
|
||||
└─ node /srv/zopu/current/packages/agents/dist/server.mjs
|
||||
├─ Hono server 127.0.0.1:3000
|
||||
├─ Flue 2.0 agents SQLite at /srv/zopu/data/flue/flue.db
|
||||
└─ AgentOS registry in-process, serverless, at /internal/rivet/*
|
||||
└─ AgentOS registry envoy, native runtime (in-process)
|
||||
```
|
||||
|
||||
The **Rivet Engine is a separate private service** on `127.0.0.1:6420`, managed by its own unit/compose. This unit does not start it. There is **no standalone AgentOS runner**: the registry handler runs inside the agents process.
|
||||
The process connects outbound to the **Rivet Engine**, a separate private service on `127.0.0.1:6420`, managed by its own unit/compose. This unit does not start or own it.
|
||||
|
||||
### The two Rivet endpoints (not interchangeable)
|
||||
The Hono/Flue server handles Convex callbacks and dispatches to Flue agents. The **AgentOS actor is hosted in-process**: the same process is the envoy that owns the native Actor Runtime Socket (Rivet Mode A). There is no separate runner process and no Rivet HTTP handler route.
|
||||
|
||||
### Rivet endpoint
|
||||
|
||||
| Variable | Role | Value on this host |
|
||||
| --- | --- | --- |
|
||||
| `RIVET_ENDPOINT` | Engine **control plane** this process connects _to_ for actor metadata | `http://127.0.0.1:6420` |
|
||||
| `RIVET_SERVERLESS_ENDPOINT` | Address the engine calls **back into** this process's `/internal/rivet` handler | `http://127.0.0.1:3000/internal/rivet` |
|
||||
|
||||
Pointing both at the engine, or dropping the `/internal/rivet` path, breaks the registry. See `agents.env.example` for the authoritative comments.
|
||||
|
||||
## Files
|
||||
|
||||
- `zopu-agents.service` — systemd unit. Runs `/srv/zopu/current/.../server.mjs` as user `zopu`, waits for engine health before binding, hardens the service, and restarts on failure.
|
||||
- `agents.env.example` — template for `/etc/zopu/agents.env`. Contains the full validated env schema with no secrets.
|
||||
- `zopu-agents.service` — systemd unit. Runs `/srv/zopu/current/packages/agents/dist/server.mjs` as user `zopu`, waits for engine health before binding, hardens the service, and restarts on failure.
|
||||
- `agents.env.example` — template for `/etc/zopu/agents.env`. Contains the full validated env schema (Hono/Flue + in-process envoy) with no secrets.
|
||||
- `../../scripts/release-agents.sh` — local build, upload, and atomic release promotion command. Each release includes this directory so the unit's `Documentation=` target remains valid.
|
||||
- `Caddyfile` — source-controlled public ingress for `agents.zopu.puter.wtf`. Terminates TLS and forwards only `/health`, `/internal/project-setup`, and `/internal/agents/*` to `127.0.0.1:3000`; the private `/internal/rivet/*` registry handler is never proxied.
|
||||
- `Caddyfile` — source-controlled public ingress for `agents.zopu.puter.wtf`. Terminates TLS and forwards only `/health`, `/internal/project-setup`, and `/internal/agents/*` to `127.0.0.1:3000`.
|
||||
|
||||
## Prerequisites on the VDS
|
||||
|
||||
@@ -73,7 +72,7 @@ curl -fsS http://127.0.0.1:3000/health # {"service":"zopu-agents","status
|
||||
|
||||
### Public ingress (Caddy)
|
||||
|
||||
Caddy terminates TLS for `agents.zopu.puter.wtf` and forwards only the three paths the Convex backend calls to the internal agents worker (`127.0.0.1:3000`). The in-process serverless registry at `/internal/rivet/*` is reachable only over loopback (the Engine's `RIVET_SERVERLESS_ENDPOINT` callback), never through Caddy. All other paths return `404`.
|
||||
Caddy terminates TLS for `agents.zopu.puter.wtf` and forwards only the three paths the Convex backend calls to the internal agents worker (`127.0.0.1:3000`). The AgentOS actor registry runs in-process, so no `/internal/rivet/*` path is exposed on the agents listener. All other paths return `404`.
|
||||
|
||||
Install or update from this checked-in artifact:
|
||||
|
||||
@@ -92,7 +91,6 @@ Verify the narrow public surface:
|
||||
|
||||
```sh
|
||||
curl -fsS https://agents.zopu.puter.wtf/health # {"service":"zopu-agents","status":"ok"}
|
||||
curl -i https://agents.zopu.puter.wtf/internal/rivet/anything # 404 — registry stays private
|
||||
```
|
||||
|
||||
## Release switch
|
||||
@@ -103,13 +101,13 @@ From the repository root on the build host, create and promote a release:
|
||||
scripts/release-agents.sh <vds-host> <release-id>
|
||||
```
|
||||
|
||||
The script atomically swaps `/srv/zopu/current`; it deliberately does **not** restart the service. After the upload succeeds, restart the single agents unit:
|
||||
The script atomically swaps `/srv/zopu/current`; it deliberately does **not** restart the service. After the upload succeeds, restart the unit:
|
||||
|
||||
```sh
|
||||
sudo systemctl restart zopu-agents.service
|
||||
```
|
||||
|
||||
Roll back by atomically replacing `current` with a symlink to a prior release, then restarting the same service.
|
||||
Roll back by atomically replacing `current` with a symlink to a prior release, then restarting the service.
|
||||
|
||||
## Optional: explicit engine ordering
|
||||
|
||||
|
||||
@@ -13,22 +13,29 @@ HOST=127.0.0.1
|
||||
PORT=3000
|
||||
NODE_ENV=production
|
||||
|
||||
# --- Rivet Engine + in-process registry (two distinct endpoints) -------------
|
||||
# --- Rivet Engine ------------------------------------------------------------
|
||||
#
|
||||
# RIVET_ENDPOINT is the Engine CONTROL PLANE this process connects TO for actor
|
||||
# metadata/management. The engine is a separate private service on this host.
|
||||
RIVET_ENDPOINT=http://127.0.0.1:6420
|
||||
#
|
||||
# RIVET_SERVERLESS_ENDPOINT is the address the Engine calls BACK INTO this same
|
||||
# process to reach the in-process serverless AgentOS registry handler, which is
|
||||
# mounted at /internal/rivet/*. It must resolve to this process's own listener
|
||||
# plus that base path. Do NOT point this at the engine; do NOT drop the path.
|
||||
RIVET_SERVERLESS_ENDPOINT=http://127.0.0.1:3000/internal/rivet
|
||||
#
|
||||
# Shared secret authenticating actor connections between the engine and this
|
||||
# registry's onBeforeConnect. Must match the value configured on the engine.
|
||||
# Shared secret authenticating actor connections between the in-process envoy
|
||||
# and the AgentOS project workspace actor. Must match the value used by the
|
||||
# engine.
|
||||
RIVET_WORKSPACE_TOKEN=REPLACE-WITH-LONG-RANDOM-WORKSPACE-TOKEN
|
||||
|
||||
# RivetKit runtime selection. These make the native Mode A choice explicit;
|
||||
# the registry still connects outbound to the private Engine.
|
||||
RIVETKIT_RUNTIME_MODE=envoy
|
||||
RIVETKIT_RUNTIME=native
|
||||
|
||||
# --- Actor versioning --------------------------------------------------------
|
||||
#
|
||||
# RivetKit uses this to drain actors when the envoy version changes. Bump it
|
||||
# whenever the actor definition or envoy behavior changes in a way that cannot
|
||||
# coexist with the previous version.
|
||||
RIVET_ENVOY_VERSION=1
|
||||
|
||||
# --- Flue SQLite persistence -------------------------------------------------
|
||||
# Canonical conversation state. Parent dir must be one of the unit's
|
||||
# ReadWritePaths (/srv/zopu/data).
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
# zopu-agents.service — single Node intelligence runtime for the Zopu VDS.
|
||||
# zopu-agents.service — single Zopu intelligence runtime for the VDS.
|
||||
#
|
||||
# Runtime shape (one process, no separate runner):
|
||||
# One process hosts both the Hono/Flue server and the AgentOS registry running
|
||||
# in native envoy mode (Rivet Mode A):
|
||||
#
|
||||
# zopu-agents (this unit)
|
||||
# └─ node /srv/zopu/current/packages/agents/dist/server.mjs
|
||||
# ├─ Hono HTTP server on 127.0.0.1:3000
|
||||
# ├─ Flue 2.0 conversation agents + SQLite at /srv/zopu/data/flue
|
||||
# └─ AgentOS registry in serverless mode, served in-process at
|
||||
# /internal/rivet/* (registry.handler drives the per-request
|
||||
# runtime; there is no standalone AgentOS runner process).
|
||||
# └─ AgentOS registry in envoy/native mode (registry.startAndWait)
|
||||
#
|
||||
# The AgentOS actor is hosted in-process: the Hono/Flue process is also the
|
||||
# envoy that connects outbound to the Rivet Engine. There is no separate
|
||||
# runner process and no Rivet HTTP handler route.
|
||||
#
|
||||
# The Rivet Engine is a SEPARATE private service on 127.0.0.1:6420, managed
|
||||
# by its own unit/compose. This unit does not start or own it; it only waits
|
||||
# for the engine health endpoint before binding (ExecStartPre below).
|
||||
#
|
||||
# Two distinct Rivet endpoints (see agents.env):
|
||||
# RIVET_ENDPOINT — engine control plane the registry connects to
|
||||
# (http://127.0.0.1:6420). Used for actor metadata.
|
||||
# RIVET_SERVERLESS_ENDPOINT — address the engine calls BACK into this same
|
||||
# process's /internal/rivet handler
|
||||
# (http://127.0.0.1:3000/internal/rivet).
|
||||
# These are NOT interchangeable; do not point both at the engine.
|
||||
# RIVET_ENDPOINT is the engine control plane (http://127.0.0.1:6420).
|
||||
#
|
||||
# The release is a self-contained bundle under /srv/zopu/releases/<id> with
|
||||
# /srv/zopu/current as the live symlink. This unit always runs `current`; the
|
||||
# release script swaps it atomically, then the operator restarts this service.
|
||||
|
||||
[Unit]
|
||||
Description=Zopu agents intelligence runtime (Flue + in-process AgentOS registry)
|
||||
Description=Zopu agents intelligence runtime (Hono + Flue + in-process envoy)
|
||||
# Soft network ordering. The real gate on the separate Engine is the health
|
||||
# probe in ExecStartPre. If the engine is itself a named systemd unit on this
|
||||
# host, add an explicit ordering here, e.g.:
|
||||
|
||||
Reference in New Issue
Block a user