Skip to content
openvibers/openvibe.ai
Commits
main · .env.example
-
Network tokens verify with keys from openvibe-sdk/auth's JWKS client (v0.23.1): fresh keys, the last good ones through a Network outage, backoff, and a rotation honoured on an unknown kid, in place of the hand-written key store. Every claim rule is still openvibe-contracts' verifyServiceToken (a sandbox token and a sub that is not a principal stay 401); the console's sign-in verifies with the SDK's verifyUserToken. Nothing public names the internal JWKS URL or its fetch error (503 detail, /api/ready), an unexpected guard error answers a plain 500, and /api/ready stays 503 until the key loads. Tests: a stub JWKS, an outage with cached keys, an unreachable JWKS, and an expired sign-in token (the SDK takes the clock as a number; a function made every expiry pass).OpenVibers · 29 Sept 2026
dde5e8f
-
The SQLite era is gone (on PostgreSQL since 2026-09-28; no compatibility kept): the one-time migrate-to-postgres script, *_DB_PATH settings (config, .env.example, systemd unit, test helpers), the unused better-sqlite3 dependency and its lockfile entries, and docs, docstrings and STATUS lines about SQLite or its rollback window. Reviewed independently; its blockers (an edited applied migration, the lockfile) are resolved here, Host's inventory follow-up is separate. npm test 23/23 test files passed.OpenVibers · 29 Sept 2026
fa943d1
-
AI moves to PostgreSQL (ADR-035, roadmap WS-X2, repository-pass group G2), async from end to end.OpenVibers · 28 Sept 2026
1a52447
-
Offloaded recordings are readable: a redirect from Media to its object storage is followed (roadmap WS-O task 2). Most VODs live in B2 (676) or R2 (19), and Media answers /v/:id with a 302 to a presigned URL there. The fetcher refused those hosts, so a transcript of an offloaded VOD failed at the first window, found by the production check on private VOD 3780. The storage hosts (AI_MEDIA_STORAGE_HOSTS, default *.backblazeb2.com and *.r2.cloudflarestorage.com) are followed only as a redirect from Media itself (its public host or the internal origin), over https, with no credentials in the URL and no IP literal, with connect-time address checks as always. They are never a URL a caller may name. test/ssrf.test.js covers Media to B2 and to R2, and refuses another host sending there, naming storage directly, http, another host and credentials. npm test passes.OpenVibers · 28 Sept 2026
549bed0
-
Namespaces are the token's ns claim, nothing else: the fallback for service tokens without ns (AI_NS_FALLBACK) and the open-rule lever (AI_NS_REQUIRED=false) are retired (shims C-22 and C-23, roadmap WS-O task 2). Every caller's token names its namespaces: Live's grant lists live.*, network.site_copy and media.analyze; news and blog list their own; Network mints network.*. Checked in production on 2026-09-28, where this week's runs came only from those services and none of the settings was set. A token without ns now runs nothing. test/auth.test.js: ns-less and empty-ns service tokens are refused even in their own namespace, Live's named namespaces decide, and the retired settings have no effect. README, .env.example and docs/migration.md follow. npm test passes.OpenVibers · 28 Sept 2026
5b73bb9
-
.env.example documents AI_MEDIA_STREAM (media.analyze streams through the loopback reader by default; 0 downloads first).OpenVibers · 28 Sept 2026
60eca1e
-
A person's own provider key lives in OpenVibe.AI (roadmap WS-O task 2; openvibe-contracts 0.49.0 -> 0.73.0).OpenVibers · 28 Sept 2026
fca04c7
-
media.analyze, local-first media analysis (roadmap WS-O task 5). A new step kind, media_analysis (server/workflows/media-analysis.js), behind the workflow media.analyze (server/workflows/media.js, namespace media; Live may run it through the default AI_NS_FALLBACK). A VOD, clip or audio file is fetched like any media input: allow-listed hosts only, into media-tmp beside the database (never /tmp, which is memory on the production host), capped at 4 GB and at that disk's free space less a 3 GB reserve, refused with media.no_space before downloading. Everything runs on this host, one analysis at a time, at nice 15. (1) Signals come from one FFmpeg pass, video decoded at keyframes only: scene changes (scdet), black and frozen picture, silence, and loudness (integrated, range, the typical level, i.e. the median audible second, since one burst drags the gated integrated level up, and loud moments at least 6 LU above it). (2) Scenes come from the changes. (3) Speech is whisper.cpp through live.stt. (4) Highlights are windows scored by loud, scene changes and speech, each with its reasons and transcript excerpt. (5) The overview comes from a local model (new provider `local`, any OpenAI-compatible server on this host, AI_LOCAL_LLM_URL, route media.local), else it is extractive from the measured facts. A paid provider (route media.paid) writes it only with allow_paid and an active quota with workflow_prefix media.paid and a max_cost_usd while today's media.* spend is under it; that quota gates only this call (quotas.paidBudget), never runs. overview.source names the writer, gaps list what is missing, and the output is not cached. test/media-analysis.test.js: the log parser; a real run on a 28 s fixture (cuts, black, still picture, silence, a loud burst) with a fake local model that sees only the facts; the local model down -> extractive and said; paid refused without allow_paid, without a budget and past it, used within it; too little disk refused before any download. workflows.test runs it on the fixture too (both skip the runs without ffmpeg). npm test 19/19.OpenVibers · 27 Sept 2026
67fb2a4
-
Operator console (roadmap WS-O task 4): /console on ai.openvibe.network, server-rendered with no JavaScript, for OpenVibe.Network staff. Providers (secret reference names and whether they resolve, never a value; base URLs without query or user info), models, routes with their fallbacks in order, templates and workflows with every version, its status and the version in use; runs with status tabs and filters (workflow, requester, error code, UTC time range), failures by error code, and a run page (versions, provider/model, fallback, attempts, tokens, cost, error, grounding, citations, the hash-only request log, and the stored input/output bounded: strings cut at 240 characters, lists at 20 items, credential-named keys blanked); quotas with their current windows, usage by day/requester/workflow/model; cache entries and hits; the audit log by kind, action, actor and target. Sign-in is Network SSO (authorization code + PKCE S256 as OAuth client `ai`, refresh token revoked at once) with Billing's session scheme (__Host- cookie, only its hash stored in console_sessions, 60 min, CSRF token plus same-origin check on every POST, sanitizeNext keeps next on /console and sends control characters and backslashes home). The token's staff claims map to AI's capability ids and are re-mapped on every request: staff.site.view (admin, owner) -> ai.usage.read, staff.ai.manage (admin, owner) -> ai.workflow.manage (version status, cancel a run), staff.secrets.manage (owner) -> ai.provider.manage (provider enable/disable, circuit reset, quotas, cache purge); a global_mod or user gets 403 and no session. Writes reuse the admin API's functions (provider status, circuit reset, cache purge and the status summary move to server/ops.js, shared by both), so each writes the same audit_log row with the person as actor; sign-ins, sign-outs and refusals are audited as console.*. Strict CSP (one hashed stylesheet), noindex, no-store, GET /robots.txt disallows /console, /auth/ and /api/; the nginx reference vhost proxies /console, /auth/ and /robots.txt with the client address from $remote_addr. 503 in production without AI_CONSOLE_SESSION_SECRET or OV_OAUTH_CLIENT_SECRET. Checked in headless Chrome at 390/768/1280 px (no horizontal overflow, wide tables scroll in their container) and with axe (WCAG 2.1 AA, light and dark): no violations. test/console.test.jsOpenVibers · 26 Sept 2026
86e1246
-
Run queue caps: a run that would wait for a slot is refused 429 queue.full (problem+json, Retry-After) once its caller already has AI_MAX_QUEUED_RUNS_PER_CALLER runs waiting (default 50) or the queue holds AI_MAX_QUEUED_RUNS (default 200), checked before quota so a refused run leaves no row and spends nothing; one caller can no longer fill the queue for every otherOpenVibers · 23 Sept 2026
bdca064
-
Schema cache: the compiled-validator cache shared by every caller (ai.extract/ai.enrich schemas are caller-supplied) is an LRU capped by entry count and total schema bytes (AI_SCHEMA_CACHE_MAX=500, AI_SCHEMA_CACHE_MAX_BYTES=8 MiB); evicted and failed schemas are removed from Ajv's own cache too, and a schema larger than the byte budget is compiled for that call onlyOpenVibers · 23 Sept 2026
549ec14
-
Namespaces fail closed: a token without an ns claim no longer runs every namespace's workflows. A service token (svc:<id>) without ns falls back to its AI_NS_FALLBACK entry (default live=live.*|network.site_copy, since Network grants Live's ai.run.create with no namespaces), else <id>.*; app and module tokens get nothing; AI_NS_REQUIRED=false is a rollback leverOpenVibers · 23 Sept 2026
f75c66b
-
Capability proposals (ai.run.create, ai.run.read, ai.workflow.manage, ai.provider.manage, ai.usage.read) and the ai service manifest; README, .env.example, systemd unit, nginx vhost, CI on Node 22.22.1, STATUS alpha W13OpenVibers · 23 Sept 2026
87d38e3