openvibers/openvibe.exchange AGENTS.md

AGENTS.md

main 10.5 KB · 169 lines · markdown

1# AGENTS.md — OpenVibe.Exchange
2
3## Project overview
4
5"Every AI model, one account." Exchange is the network's AI front: every model OpenVibe can run with the
6live price, speed and uptime of every offer that serves it, one chat that puts up to three models side by
7side, the OpenAI- and Anthropic-compatible endpoint, community machines, the uncensored tier, companions
8and the AI arena. It **reads OpenVibe.AI** (catalog, aggregate usage, and the runs a chat makes for a
9person) and keeps only two things of its own: a person's chats and their 18+ confirmation. Node.js/
10Express, PostgreSQL (PGlite in development), CommonJS, **no build step**.
11
12- Service id `exchange`, port `5150`, origin `https://openvibe.exchange`, unit
13 `openvibe-exchange.service`, release root `/opt/openvibe.exchange`.
14- The v1 marketplace is retired: `/api/v1/*` answers `410`, and its tables stay as they are, read-only.
15 Every old chat row remains for a one-time import into Chat.
16
17## What it owns
18
19- The pages and their live numbers: `/` (every model, popular, cheapest, uncensored, community machines,
20 endpoint), `/models`, `/m/<org>/<model>` (price in/out/cached per million, p50/p95, uptime, data policy,
21 Try it, curl and the SDK line), `/api` (endpoint, model ids, keys, aggregate usage), `/start`, `/why`
22 (a real run's explain), `/faq`, `/sell` (Link machines and pools; what is **not** sold), `/uncensored`,
23 `/ai`, `/status`.
24- A person's chats (`server/chat/store.js`) and their 18+ confirmation; companions, lorebooks, notes,
25 memory and the Locker; the arena and compare surfaces; the deep-dive/analysis pages.
26- The one-time import contract: `GET /internal/exchange/chat/export` requires Chat's service token with
27 `exchange.chat.export` and the authenticated person's `x-ov-subject`; it returns only that person's
28 unsealed chats.
29- The `/chat` redirect: 301 to `https://openvibe.chat/vibe`, carrying `?models=` and mapping old `@vN`
30 model ids. Model pages' Try it links go there directly.
31- Its own PostgreSQL state, migrations and account-data receipts.
32
33Not owned: the catalog/prices/usage and the model runs (AI), the models and provider keys (AI/Network),
34identity, chat itself (Chat), ratings (Bench), machines and pools (Network/Link), money (Billing), Media.
35
36## What it reads (AI and Network)
37
38- `GET https://ai.openvibe.services/api/v1/exchange/catalog` — models grouped, with every live offer:
39 price (rate cards), measured speed/uptime, `metadata.data_policy` where recorded. Prepaid capacity has
40 no price (`free: true`); **BYOK and restricted capacity are never an offer**.
41- `GET .../api/v1/exchange/usage?days=30` — aggregate requests, tokens and spend by day/model/product
42 (`usage_daily`; never a prompt, answer or person).
43- `POST .../api/v1/runs` with `workflow: ai.complete` and `on_behalf_of` — one chat turn or Try it, on the
44 person's allowance, with Exchange's token (`ai.run.create`, namespace `ai.complete`).
45- `GET .../api/v1/community/offers` — live community offers; a pool says **how many** machines serve it,
46 never which ones ("Community pool (N machines)").
47- `GET https://openvibe.network/api/v1/machines` and `/machine-pools` — the person's machines, pools and
48 poolable machines, with their Network token (names, free VRAM/RAM, local network key, approvals,
49 readiness); `POST /api/v1/machine-pools` proposes, `.../:id/revoke` stops. Link measures links and fit;
50 Exchange shows what Network carries and says "not measured yet" when it carries nothing.
51- AI unreachable is **said, not papered over**: the catalog read keeps the last good copy for five minutes
52 and pages carry an honest notice; no number is invented.
53
54## Repository map
55
56- **Entry:** [server/index.js](server/index.js) — `createApp()`, listen, graceful stop.
57- **App:** [server/app.js](server/app.js) — helmet/CSP, `/auth`, `/internal/events`, `/shared`,
58 `/api/v1/arena`, `/api/v1/analysis`, `/api/v1/compare`, `/api/v1`, pages, machine endpoints.
59- **Reads:** [server/ai.js](server/ai.js), [server/network.js](server/network.js),
60 [server/bench.js](server/bench.js), [server/compare.js](server/compare.js),
61 [server/model-directory.js](server/model-directory.js), [server/model-search.js](server/model-search.js),
62 [server/compute-prices.js](server/compute-prices.js), [server/catalog-history.js](server/catalog-history.js),
63 [server/analysis.js](server/analysis.js).
64- **Person state:** [server/chat/store.js](server/chat/store.js), [server/companions/](server/companions/)
65 (`store.js`, `group.js`, `voice.js`, `adult.js`, `memory.js`, `lorebook.js`, `locker.js`, `taking-notes.js`),
66 [server/actor.js](server/actor.js), [server/sharing.js](server/sharing.js).
67- **Arena:** [server/arena/store.js](server/arena/store.js), `category.js`; HTTP in
68 [server/http/arena.js](server/http/arena.js), `compare.js`, `compare-site.js`, `analysis.js`,
69 `deep-dive.js`, `dashboard.js`, `search.js`.
70- **Pages/API:** [server/http/pages.js](server/http/pages.js), `api.js`, `console.js`, `companions.js`,
71 `principal.js`, `router.js`, [server/openapi.js](server/openapi.js); [server/render/](server/render/).
72- **Config/db:** [server/config.js](server/config.js), [server/db.js](server/db.js).
73- **Deploy:** [deploy/systemd/openvibe-exchange.service](deploy/systemd/openvibe-exchange.service),
74 [deploy/nginx/openvibe.exchange.conf](deploy/nginx/openvibe.exchange.conf).
75
76## Commands
77
78```bash
79npm ci
80npm start # development: PGlite in data/pglite, http://localhost:5150
81npm test # test/run.js, PGlite, mock Network/AI
82npm test -- pages chat retirement # filter by word
83npm run test:pg # same on PostgreSQL (EXCHANGE_TEST_STORE=pg)
84npm run seed:proof # scripts/seed-proof.js
85ov test # the harness's sharded run of what the change reaches
86```
87
88`DATABASE_URL` serves, `DATABASE_DIRECT_URL` migrates; `OV_OAUTH_CLIENT_SECRET` makes sign-in and the AI
89client-credentials token work. See `.env.example`.
90
91## Database and migrations
92
93Exchange's own PostgreSQL database (ADR-035; PGlite under `data/pglite` in development). Async through
94`openvibe-sdk/db`; migrations `migrations/NNNN_*.sql` applied at boot; never edit an applied migration, add
95a new number. **Exchange v1's tables are read-only**: nothing is written to them any more, and the old chat
96rows exist only for the one-time import. A new column for the current product goes in a new migration.
97
98## Auth, privacy and the 18+ gate
99
100- People sign in through Network SSO (OAuth client `exchange`, PKCE). Exchange's AI calls use its own
101 client-credentials token with `on_behalf_of` the person, so the run is theirs (allowance, receipt).
102- A page rendered for a signed-in person is `private, no-store`; a public page is `public, max-age=60`.
103 Do not cache a signed-in page publicly.
104- The 18+ confirmation is on the **account**, not a cookie: `/uncensored` explains the abliterated models
105 and the hard floor. Do not move the gate into client state.
106- The old-chat export is service-only: Chat's token (`exchange.chat.export`) plus `x-ov-subject`; it
107 returns only that person's unsealed chats. Never expose it publicly.
108- Service callers need a Network service token audience `openvibe.exchange` and the route's capability;
109 account export/deletion goes through `/internal/events`.
110
111## Frontend loading model
112
113Every page is **server-rendered with `openvibe-shared/kit` and complete without JavaScript**; there is no
114SPA, bundler or transpiler. `openvibe-shared` supplies the Frame/kit/legal/SEO and `/shared/*` from the
115pinned node_modules. The pages negotiate cleanly for agents (JSON/llms) and their numbers come from the
116same AI reads. CSP is in [server/app.js](server/app.js).
117
118## Deploy
119
120Unit [deploy/systemd/openvibe-exchange.service](deploy/systemd/openvibe-exchange.service) runs
121`/opt/openvibe.exchange/server/index.js` on `127.0.0.1:5150`, env `/etc/openvibe/exchange.env`; vhost
122[deploy/nginx/openvibe.exchange.conf](deploy/nginx/openvibe.exchange.conf). The README does not document
123an `ovhost deploy exchange` command — use the host's own service installer. Migrations run at boot; no
124secret in a command line, file or log.
125
126## Tests
127
128`npm test` runs each `test/*.test.js` in its own process with PGlite and in-process Network/AI mocks. It
129pins the pages and their numbers, the catalog/usage reads and the "last good copy for five minutes" rule,
130the `/chat` redirect and old `@vN` mapping, the v1 retirement (`410`), the 18+ gate, companions/arena/
131compare, the internal chat export (subject-scoped), account export/deletion and discovery. `ov test` runs
132the same.
133
134## Conventions
135
136- CommonJS, 4-space indent, single quotes, semicolons; reads live in `server/ai.js`/`server/network.js`,
137 person state in `server/*/store.js`, HTTP in `server/http/`.
138- A number shown to a person comes from AI or Network and carries its freshness; a missing number is said,
139 never defaulted. Prices are per million tokens with the currency and the offer.
140- Errors are problem+json with stable codes; an AI/Network failure is a clear notice, not a 500 page.
141- The v1 surface is retired: do not revive `/api/v1` marketplace routes; keep the `410`.
142
143## Pitfalls
144
145- **Never invent a price, a model or an uptime.** If AI does not answer, keep the last good catalog for at
146 most five minutes and show the notice; a page with no data says so.
147- **BYOK and restricted capacity are not offers**, and prepaid capacity is `free: true`; do not list them
148 as purchasable.
149- **A community pool never names its machines**, only the count.
150- **Person state is private:** chats, companions, notes and the 18+ flag are per subject; a signed-in page
151 is `no-store`. The old-chat export is the only cross-service read and is subject-scoped by Chat.
152- **Do not write Exchange v1's tables.** They are the migration's archive; the old chat rows are for the
153 one-time import only.
154- **`/chat` is a 301 to Chat/Vibe** with `?models=` and the old `@vN` mapping; do not rebuild a local chat
155 page.
156- **Money is AI's/Billing's**; Exchange charges a turn to the person's allowance through AI, never a local
157 ledger.
158- **No fabricated "selling compute"**: `/sell` says plainly what is not sold (personal plans, personal API
159 keys); machines/pools are Network's truth.
160- **A unit description that says "trade what people make" is stale** (the remake is the AI front); do not
161 use it as the product description.
162
163## Documentation
164
165- [README.md](README.md) — pages, what it reads, money/free use, the retired v1, run.
166- [STATUS.json](STATUS.json) — the remake's state.
167- [docs/](docs/) — platform review, shared analysis, C2 notes and screenshots.
168- OpenVibe.Contracts holds `exchange.*`/`ai.*` shapes; AI and Network own their upstream APIs.
169