openvibers/openvibe.exchange Commits

The refusal rate of an offer, with the day it was measured (#102)

OP OpenVibers committed 6 days ago · 84f180d3b7 · 2 files, +61 −2

* The refusal rate of an offer, with the day it was measured

OpenVibe.AI measures what each offer refuses on a fixed, published probe set and sends the rate on
the catalog's offer, with the day it was measured. The page showed the rate as a bare percentage,
which reads as if it were this morning's; a share that may be weeks old says when it was measured.

So the rate now carries its date: "refuses 25.0% (measured 2026-11-07)" in the model's list and in
the offer table. An offer nobody measured still shows nothing at all: no rate, no dash, no invented
figure.

test/refusal-rate.test.js proves both: the rate with its day, and the silence for an offer nobody
measured.

* The public numbers say what a half-price batch is

Half price. Answered within your deadline when spare low-cost capacity is free; if none comes free in time, the prompt expires and you pay nothing.

Changes

ddiff --git a/server/views/exchange.js b/server/views/exchange.js
iindex ea22aee..f3fd5d0 100644
---- a/server/views/exchange.js
++++ b/server/views/exchange.js
@@@ -16,6 +16,17 @@ const money = (n, free = false) => (free ? 'free' : n == null ? '–' : n === 0
const inOut = (price) => (price ? `${money(price.in)} in · ${money(price.out)} out` : 'no per-token price');
const ms = (n) => (n == null ? '–' : n < 1000 ? `${Math.round(n)} ms` : `${(n / 1000).toFixed(1)} s`);
const pct = (n) => (n == null ? '–' : `${(n * 100).toFixed(1)}%`);
++
++/**
++ * The refusal rate of an offer, with the day it was measured. The rate is a share of the published probe set
++ * (OpenVibe.AI measures it), and a number without its date would look current when it may be weeks old, so
++ * the day is part of the number. An offer nobody measured shows nothing at all: no rate, no dash.
++ */
++const refusalText = (o) => {
++ if (!o || o.refusal_rate == null) return null;
++ const date = o.refusal_measured_on ? ` (measured ${o.refusal_measured_on})` : '';
++ return `refuses ${pct(o.refusal_rate)}${date}`;
++};
const count = (n) => (n == null ? '–' : Number(n).toLocaleString('en-US'));
const blended = (price) => (price ? (Number(price.in) + Number(price.out)) / 2 : Number.POSITIVE_INFINITY);
const cheapest = (m) => (m.offers || []).filter((o) => o.price).sort((a, b) => blended(a.price) - blended(b.price))[0] || null;
@@@ -134,7 +145,8 @@ function modelRow(m, { withTry = true } = {}) {
// A stat not measured yet is left out, never printed as a dash ("– · –" read as noise in a row).
if (best) bits.push(providerLabel(best), inOut(best.price), ...(best.speed && best.speed.p50_ms != null ? [ms(best.speed.p50_ms)] : []), ...(best.uptime != null ? [`${pct(best.uptime)} up`] : []));
else if (m.offers[0]) bits.push(providerLabel(m.offers[0]), 'free capacity');
-- if (best && best.refusal_rate != null) bits.push(`refuses ${pct(best.refusal_rate)}`);
++ const refuses = refusalText(best);
++ if (refuses) bits.push(refuses);
const pv = privacyOf(best || m.offers[0]);
if (pv) bits.push(pv.short);
return `<li class="ex-mrow">
@@@ -305,12 +317,13 @@ function modelPage({ model, viewer, result = null, problem = null, text = '', ad
];
const rows = offers.map((o) => {
const p = privacyOf(o);
++ const refuses = refusalText(o);
return {
provider: `<a class="ex-offer-name" href="#try">${esc(providerLabel(o))}</a>${o.trust === 'community' ? ` ${kit.badge('Community', 'accent')}` : ''}${freeTier(o) ? ` ${kit.badge('Free to try')}` : (freePaused(o) ? ` ${kit.badge('Free paused')}` : '')}`,
price: o.price ? `<b>${money(o.price.in)}</b> / ${money(o.price.out)}` : '<span class="ex-muted">free capacity</span>',
speed: `${ms(o.speed.p50_ms)} <small>p50</small> · ${ms(o.speed.p95_ms)} <small>p95</small>`,
uptime: o.uptime == null ? '–' : pct(o.uptime),
-- privacy: p ? `${kit.badge(p.label, p.kind)}${o.refusal_rate != null ? `<br><small>refuses ${pct(o.refusal_rate)}</small>` : ''}` : '–',
++ privacy: `${p ? kit.badge(p.label, p.kind) : ''}${refuses ? `<br><small>${esc(refuses)}</small>` : ''}` || '–',
policy: policyText(o.data_policy),
try: '<a class="ex-mini" href="#try">Try it</a>',
};
@@@ -448,6 +461,7 @@ ${keyPrivacy && keyPrivacy.note ? kit.notice({ kind: 'info', text: keyPrivacy.no
</form>`);
return `<div class="ex-wrap ex-page">
${kit.head({ title: 'The API', sub: 'One endpoint. OpenAI and Anthropic compatible.', actions: [kit.button({ href: '/chat', label: 'Chat', icon: 'chat', kind: 'quiet' })] })}
++${panel({ title: 'Batches, at half price', body: `<p class="ex-prose">Half price. Answered within your deadline when spare low-cost capacity is free; if none comes free in time, the prompt expires and you pay nothing.</p>` })}
${panel({ title: 'One endpoint', body: `
<p class="ex-prose"><code>${ENDPOINT}</code> speaks OpenAI's Chat Completions; <code>https://api.openvibe.exchange/v1/messages</code> speaks Anthropic's Messages API, so Claude Code works by pointing <code>ANTHROPIC_BASE_URL</code> at it.</p>
${kit.snippet({ code: `curl ${ENDPOINT} \\\n -H "Authorization: Bearer $OPENVIBE_KEY" \\\n -H "Content-Type: application/json" \\\n -d '{"model":"openvibe/auto","messages":[{"role":"user","content":"Hello"}]}'`, id: 'api-curl' })}
ddiff --git a/test/refusal-rate.test.js b/test/refusal-rate.test.js
nnew file mode 100644
iindex 0000000..7100470
---- /dev/null
++++ b/test/refusal-rate.test.js
@@@ -0,0 +1,45 @@
++'use strict';
++/**
++ * The measured refusal rate on an offer, and the day it was measured.
++ *
++ * The rate is measured by OpenVibe.AI on a published probe set and travels on the catalog's offer. The page
++ * shows it with the day it was measured: a share without its date would look current when it may be weeks
++ * old. An offer nobody measured shows no rate at all.
++ */
++const assert = require('assert');
++const { boot, check, done } = require('./helpers/boot');
++const { createFakeAi } = require('./helpers/ai');
++
++const offer = {
++ provider: 'shared', provider_name: 'Shared provider', model: 'deepseek-chat', id: 'deepseek/deepseek-chat@v1',
++ trust: 'first-party', free: false, price: { in: 0.2, out: 0.3 }, speed: { p50_ms: 400, p95_ms: 800 },
++ uptime: 0.99, requests_7d: 5, data_policy: { trains: false, retention_days: 0 },
++};
++const model = {
++ slug: 'deepseek/deepseek-chat', canonical: 'deepseek/deepseek-chat', name: 'DeepSeek Chat', family: 'DeepSeek',
++ kind: 'chat', capabilities: {}, requests_7d: 5, offers: [offer],
++};
++const catalogWith = (o) => async () => ({ generated_at: '', models: [{ ...model, offers: [o] }], families: [], count: 1 });
++
++(async () => {
++ const c = await boot({ ai: { ...createFakeAi(), catalog: catalogWith({ ...offer, refusal_rate: 0.25, refusal_measured_on: '2026-11-07' }) } });
++ try {
++ await check('an offer shows its refusal rate with the day it was measured', async () => {
++ const r = await c.get('/m/deepseek/deepseek-chat');
++ assert.strictEqual(r.status, 200, r.text);
++ assert.ok(r.text.includes('refuses 25.0%'), 'the rate is shown as a percentage');
++ assert.ok(r.text.includes('measured 2026-11-07'), 'and with the day it was measured');
++ });
++ } finally { await c.close(); }
++
++ const u = await boot({ ai: { ...createFakeAi(), catalog: catalogWith({ ...offer, refusal_rate: null, refusal_measured_on: null }) } });
++ try {
++ await check('an offer nobody measured shows no rate at all', async () => {
++ const r = await u.get('/m/deepseek/deepseek-chat');
++ assert.strictEqual(r.status, 200, r.text);
++ assert.ok(!/refuses \d/.test(r.text), 'no rate is shown for an offer nobody measured');
++ });
++ } finally { await u.close(); }
++
++ done();
++})();