openvibers/openvibe.ai Commits

AI: the home names the OpenAI-compatible endpoint and a project's own provider, and stops claiming metered models for production apps (#76)

OP OpenVibers committed 29 days ago · 72d84ff0b5 · 2 files, +9 −4

**ai.openvibe.services' home now names the OpenAI-compatible endpoint and a project's own provider, and stops saying production apps use metered models.**

**Why:** the home predates #70–#74. It never mentioned that any OpenAI client works at `/v1`, or that an app can name its project's own provider. Its Sandbox and production table also said production apps get "metered models under a project budget", but tier budgets are off in production, so app runs that use the router get free and local capacity only.

**Change (`server/home.js`):**
- **Lede:** "…through one API, or point any OpenAI client at it."
- **First card:** "Six operations, and OpenAI's API". Any OpenAI client works by pointing it at `/v1` for Chat Completions with tools.
- **Table, Models row:** production says "metered models open with project budgets".
- **Table, new row "Your project's own provider":** on `/v1/chat/completions`, keyed by a project secret granted to `ai`, in both environments.

**Test:** `home.test.js` checks the endpoint line, the new row, and that the old production claim is gone. The 13 test files that reach the change pass.

Changes

ddiff --git a/server/home.js b/server/home.js
iindex 7e69800..61ec70b 100644
---- a/server/home.js
++++ b/server/home.js
@@@ -61,14 +61,15 @@ function sections({ siteUrl }) {
return showcase.hero({
eyebrow: 'OpenVibe.AI · alpha',
title: 'Many models, one API.', accent: 'Every answer explained.',
-- lede: 'Chat, generate, summarize, classify, extract and embed through one API. OpenVibe.AI picks a model by price, measured latency '
-- + 'and health, falls back when a provider fails, and tells you on every run which model answered, why it was chosen and what it cost.',
++ lede: 'Chat, generate, summarize, classify, extract and embed through one API, or point any OpenAI client at it. OpenVibe.AI picks a '
++ + 'model by price, measured latency and health, falls back when a provider fails, and tells you on every run which model answered, '
++ + 'why it was chosen and what it cost.',
actions: [{ label: 'Start building', href: PROJECTS_URL, primary: true }, { label: 'See prices and latency', href: '/stats' }],
note: 'Alpha. OpenVibe.Live and OpenVibe.Network already run their AI here in production; developer apps start in the sandbox, on free and local capacity.',
}) + showcase.features({
title: 'What you get',
items: [
-- { icon: 'ov:text', title: 'Six operations', text: 'Chat, generate, summarize, classify, extract and embed, with structured JSON output when you ask for a schema.' },
++ { icon: 'ov:text', title: 'Six operations, and OpenAI\'s API', text: 'Chat, generate, summarize, classify, extract and embed, with JSON output on a schema. Any OpenAI client works too: point it at /v1 for Chat Completions with tools.' },
{ icon: 'ov:map', title: 'Routing you can read', text: 'Every run carries an explanation: what it optimised for, the model it picked, and every other candidate with its estimated cost and latency.' },
{ icon: 'ov:history', title: 'Fallbacks on the record', text: 'A provider that is down, out of credentials or too slow is skipped and logged. When a fallback answers, the run says so.' },
{ icon: 'ov:host', title: 'Free and local first', text: 'A small open model runs on OpenVibe\'s own server, beside free providers. Sandbox apps use only that capacity, so trying it costs nothing.' },
@@@ -98,7 +99,8 @@ function sections({ siteUrl }) {
columns: ['Sandbox', 'Production'],
rows: [
{ label: 'Access to ai.app.run', values: ['Every sandbox app, without asking', 'Once OpenVibe staff add it to the project'] },
-- { label: 'Models', values: ['Free and local capacity only', 'Free and local capacity; metered models under a project budget'] },
++ { label: 'Models', values: ['Free and local capacity only', 'Free and local capacity; metered models open with project budgets'] },
++ { label: 'Your project\'s own provider', values: ['On /v1/chat/completions, keyed by a project secret granted to ai', 'The same'] },
{ label: 'Free allowance', values: ['Per project, per provider', 'Per project, per provider'] },
{ label: 'Who can read a run', values: ['The project that made it', 'The project that made it'] },
{ label: 'A person\'s own provider key', values: ['Never used', 'Never used'] },
ddiff --git a/test/home.test.js b/test/home.test.js
iindex 3486c12..40dd052 100644
---- a/test/home.test.js
++++ b/test/home.test.js
@@@ -38,6 +38,9 @@ t.test('GET / as a browser: the home page, its CSP and a private cache', async (
assert.match(r.headers.get('vary'), /Accept/);
assert.strictEqual((r.text.match(/<h1\b/g) || []).length, 1, 'exactly one h1');
assert.ok(r.text.includes('Many models, one API.'), 'the hero');
++ assert.ok(r.text.includes('point it at /v1 for Chat Completions with tools'), 'the OpenAI-compatible endpoint is on the home');
++ assert.ok(r.text.includes('Your project&#39;s own provider') || r.text.includes("Your project's own provider"), 'the project\'s own provider row');
++ assert.ok(!r.text.includes('metered models under a project budget'), 'production app runs are free-only until project budgets open');
assert.ok(r.text.includes(`<link rel="canonical" href="${SITE}/">`), 'the canonical public origin');
assert.ok(r.text.includes(`${SITE}/api/v1/chat`), 'the examples call the public origin');
assert.ok(r.text.includes('https://openvibe.services/projects'), 'where a project and an app are made');