openvibers/openvibe.ai Commits

Prepare Claude Opus for owner-configured icon generation (#473)

OP OpenVibers committed 2 days ago · eee6beba94 · 3 files, +45 −2

* Seed Claude Opus for owner-configured Design routing

* Recognize Anthropic price source in provider test

Changes

ddiff --git a/server/providers/pool-providers.js b/server/providers/pool-providers.js
iindex 8ca899b..4236f7d 100644
---- a/server/providers/pool-providers.js
++++ b/server/providers/pool-providers.js
@@@ -739,7 +739,19 @@ const PROVIDERS = [
{ key: 'deepseek', keys_url: 'https://platform.deepseek.com/api_keys', display_name: 'DeepSeek', base_url: 'https://api.deepseek.com/v1', default_model: 'deepseek-flash',
docs_url: 'https://api-docs.deepseek.com/', capabilities: ['chat', 'vision', 'tools', 'web-search'], search_adapters: ['deepseek'] },
{ key: 'anthropic', keys_url: 'https://console.anthropic.com/settings/keys', display_name: 'Anthropic', kind: 'anthropic', base_url: 'https://api.anthropic.com/v1', auth_mode: 'x-api-key',
-- docs_url: 'https://platform.claude.com/docs/en/api/overview', capabilities: ['chat', 'messages', 'vision', 'tools'] },
++ docs_url: 'https://platform.claude.com/docs/en/api/overview', capabilities: ['chat', 'messages', 'vision', 'tools'],
++ default_model: 'claude-opus-5-5',
++ // Design's signed-in icon task names this model. The provider remains disabled and UNVERIFIED until
++ // the owner supplies a key and confirms the commercial access and retail price.
++ models: [{
++ model_key: 'claude-opus-5-5', display_name: 'Claude Opus 5.5', family: 'claude',
++ context_window: 1000000, max_output: 128000,
++ cost: { in_per_mtok: 4, cached_per_mtok: 0.2, out_per_mtok: 20 },
++ source: 'https://platform.claude.com/docs/en/models/opus-5-5/overview', checked: '2026-11-11',
++ supports: { json: true, tools: true, streaming: true, vision: true },
++ quantization: null, refusal_rate: null,
++ }],
++ },
{ key: 'openai', keys_url: 'https://platform.openai.com/api-keys', display_name: 'OpenAI', base_url: 'https://api.openai.com/v1', default_model: 'gpt-5-mini',
docs_url: 'https://platform.openai.com/docs/api-reference/models/list', capabilities: ['chat', 'vision', 'tools', 'image', 'video', 'speech', 'transcribe', 'embed'] },
{ key: 'gemini', models_dev_id: 'google', keys_url: 'https://aistudio.google.com/apikey', display_name: 'Google AI Studio (Gemini API)', base_url: 'https://generativelanguage.googleapis.com/v1beta/openai',
ddiff --git a/test/ai-provider-adapters.test.js b/test/ai-provider-adapters.test.js
iindex 433a680..73703f4 100644
---- a/test/ai-provider-adapters.test.js
++++ b/test/ai-provider-adapters.test.js
@@@ -35,7 +35,7 @@ const DOMAIN = {
fireworks: 'fireworks.ai', groq: 'groq.com', cerebras: 'cerebras.ai', sambanova: 'sambanova.ai',
baseten: 'baseten.co', hyperbolic: 'hyperbolic.xyz', parasail: 'parasail.io', 'particle-ai': 'particle.ai',
'inference-net': 'inference.net', 'atlas-cloud': 'atlascloud.ai', avian: 'avian.io',
-- nanogpt: 'nano-gpt.com', infermatic: 'totalgpt.ai', arliai: 'arliai.com', friendli: 'friendli.ai', scaleway: 'scaleway.com',
++ nanogpt: 'nano-gpt.com', infermatic: 'totalgpt.ai', arliai: 'arliai.com', friendli: 'friendli.ai', scaleway: 'scaleway.com', anthropic: 'claude.com',
iteracompute: 'iteracompute.com', sable: 'sableapi.com', inception: 'inceptionlabs.ai', dosai: 'dos.ai', 'runpod-vllm': 'runpod.io', meta: 'meta.ai',
};
const onItsOwnSite = (url, key) => {
ddiff --git a/test/anthropic-catalog.test.js b/test/anthropic-catalog.test.js
nnew file mode 100644
iindex 0000000..10465bd
---- /dev/null
++++ b/test/anthropic-catalog.test.js
@@@ -0,0 +1,31 @@
++'use strict';
++const assert = require('node:assert/strict');
++const { boot, request, suite } = require('./helpers');
++const { byKey } = require('../server/providers/pool-providers');
++const { recordOf, modelOf } = require('../server/providers/pool-seed');
++
++const t = suite('anthropic-catalog');
++const anthropic = byKey.get('anthropic');
++const opus = anthropic.models.find((model) => model.model_key === 'claude-opus-5-5');
++let h;
++
++t.test('the Design model has an owner key slot and a sourced rate, but starts off', () => {
++ assert.equal(anthropic.default_model, opus.model_key);
++ assert.equal(recordOf(anthropic).status, 'disabled');
++ assert.equal(recordOf(anthropic).secret_ref, 'vault:anthropic');
++ assert.equal(recordOf(anthropic).provider_access, 'UNVERIFIED');
++ assert.deepEqual([modelOf(anthropic, opus).cost.in_per_mtok, modelOf(anthropic, opus).cost.out_per_mtok], [4, 20]);
++ assert.match(opus.source, /^https:\/\/platform\.claude\.com\/docs\/en\/models\/opus-5-5\//);
++});
++
++t.test('the model is seeded for owner configuration but a disabled provider is absent from public offers', async () => {
++ h = await boot();
++ assert.equal((await h.registry.getProvider('anthropic')).status, 'disabled');
++ assert.ok(await h.registry.getModel('anthropic', opus.model_key));
++ const r = await request(h.base, 'GET', '/api/v1/exchange/catalog');
++ assert.equal(r.status, 200);
++ assert.ok(!r.body.models.some((model) => model.canonical === 'anthropic/claude-opus-5-5'));
++});
++
++t.test('stop', async () => { if (h) await h.stop(); });
++t.run();