openvibers/openvibe.codes Commits

DeepSeek on the Exchange: keep the agent's own model id (#385)

OP OpenVibers committed 2 days ago · 331abe7b14 · 3 files, +14 −20

Changes

ddiff --git a/README.md b/README.md
iindex e49c775..f1fe9cd 100644
---- a/README.md
++++ b/README.md
@@@ -65,7 +65,7 @@ More: [docs/cli.md](docs/cli.md).
| OpenCode | `opencode run --format json` | `opencode` on PATH |
| Command Code | `cmd --print --output-format json` | `cmd` on PATH |
| Aider | `aider --message` | `aider` on PATH |
--| DeepSeek | the harness's own tool loop, through OpenVibe.Exchange's compatible API with the SDK's Exchange client ([harness/adapters/api.js](harness/adapters/api.js), `openvibe-sdk/exchange`) | `OPENVIBE_EXCHANGE_KEY` (an Exchange key from openvibe.exchange; a person's or the service's) or a Codes run token; `OPENVIBE_EXCHANGE_URL` overrides the endpoint and `OPENVIBE_EXCHANGE_MODEL` the model (the default is the Exchange's id for the agent's DeepSeek chat model, `deepseek/deepseek-flash`). The direct DeepSeek API is used only for a self-hosted run: `OPENVIBE_CODES_DEEPSEEK_DIRECT=1` and your own `DEEPSEEK_API_KEY` (with `DEEPSEEK_BASE_URL` for another compatible server) |
++| DeepSeek | the harness's own tool loop, through OpenVibe.Exchange's compatible API with the SDK's Exchange client ([harness/adapters/api.js](harness/adapters/api.js), `openvibe-sdk/exchange`) | `OPENVIBE_EXCHANGE_KEY` (an Exchange key from openvibe.exchange; a person's or the service's) or a Codes run token; `OPENVIBE_EXCHANGE_URL` overrides the endpoint and `OPENVIBE_EXCHANGE_MODEL` names an Exchange catalog id instead of the agent's own model id (the Exchange routes the request to the offer that can run it; the result names the model that answered). The direct DeepSeek API is used only for a self-hosted run: `OPENVIBE_CODES_DEEPSEEK_DIRECT=1` and your own `DEEPSEEK_API_KEY` (with `DEEPSEEK_BASE_URL` for another compatible server) |
| OpenVibe.AI | the same loop against AI's `/v1/chat/completions`; each answer reports its cost | `OPENVIBE_APP_ID` + `OPENVIBE_APP_SECRET` (an app with `ai.app.run`; tokens are fetched and refreshed), or `OPENVIBE_AI_TOKEN`. App runs on AI's router use free capacity without tools, so name your project's own provider: `OPENVIBE_AI_SECRET` (a project secret granted to `ai` for reveal to the provider's origin), `OPENVIBE_AI_PROVIDER_URL` (default `https://api.openai.com/v1`), `OPENVIBE_AI_PROVIDER_MODEL`. The key stays in OpenVibe.Network, never on the machine |
| Your own model | the same loop against any OpenAI-compatible server | `OPENVIBE_CODES_BASE_URL`, `OPENVIBE_CODES_MODEL`, optional `OPENVIBE_CODES_API_KEY` |
ddiff --git a/harness/index.js b/harness/index.js
iindex 0937ffa..fd2b05c 100644
---- a/harness/index.js
++++ b/harness/index.js
@@@ -94,17 +94,14 @@ function exchangeKeyOf(env) {
* A bare hosted run token at OpenVibe.AI (DEEPSEEK_BASE_URL there, DEEPSEEK_API_KEY = run token) goes through
* Exchange: api.openvibe.exchange speaks the same compatible API and takes the same person's token.
*/
--/** The Exchange's catalog ids for the models the deepseek agent names (deepseek-chat is DeepSeek's own alias). */
--const EXCHANGE_MODELS = { 'deepseek-chat': 'deepseek/deepseek-flash', 'deepseek-reasoner': 'deepseek/deepseek-v4-pro' };
--/** A model the Exchange names itself (a catalog id or a dynamic alias) goes through as it is. */
--const EXCHANGE_NAME = /^(openvibe(\/|$)|@preset\/)/;
--
--/** The model the Exchange should run: its own id for the agent's model, a catalog id as given, a dynamic alias as given. */
++/**
++ * The model the Exchange should run: the agent's own id (deepseek-chat), or an Exchange catalog id when
++ * OPENVIBE_EXCHANGE_MODEL names one. The id is sent as it is, the same model id the agent asked for; the Exchange's
++ * router chooses the offer that can run the request (today its DeepSeek offer does not declare tools, so a tool loop
++ * is answered by a tool-capable offer and the result names the model that ran).
++ */
function exchangeModelOf(model, env) {
-- const named = String((env && env.OPENVIBE_EXCHANGE_MODEL) || model || '').trim();
-- if (EXCHANGE_NAME.test(named) || named.includes('/')) return named;
-- if (EXCHANGE_MODELS[named]) return EXCHANGE_MODELS[named];
-- return `deepseek/${named || 'deepseek-flash'}`;
++ return String((env && env.OPENVIBE_EXCHANGE_MODEL) || model || 'deepseek-chat').trim();
}
function deepseekAdapter(env) {
@@@ -122,8 +119,7 @@ function deepseekAdapter(env) {
return apiAgent({
id: 'deepseek', name: 'DeepSeek', model: 'deepseek-chat',
exchange: { baseUrl, ...exchange },
-- // The same DeepSeek model under the Exchange's own catalog id (deepseek/deepseek-flash is DeepSeek's
-- // V4.1 Flash, the model deepseek-chat names today); OPENVIBE_EXCHANGE_MODEL overrides it.
++ // The agent's model id is sent as it is; OPENVIBE_EXCHANGE_MODEL names an Exchange catalog id instead.
mapModel: exchangeModelOf,
priceIn: 0.00027, priceOut: 0.0011,
available: () => ({ available: true, where: baseUrl }),
ddiff --git a/test/harness-exchange.test.js b/test/harness-exchange.test.js
iindex 5649e7c..07fd8b5 100644
---- a/test/harness-exchange.test.js
++++ b/test/harness-exchange.test.js
@@@ -65,7 +65,7 @@ const collect = async (run) => { const out = []; for await (const e of run) out.
assert.strictEqual(api.requests.length, 2, 'the tool loop ran both turns');
assert.strictEqual(api.requests[0].url, 'https://api.openvibe.exchange/v1/chat/completions');
assert.strictEqual(api.requests[0].headers.authorization, `Bearer ${EXCHANGE_KEY}`);
-- assert.strictEqual(api.requests[0].body.model, 'deepseek/deepseek-flash', 'the Exchange\'s id for the same DeepSeek model');
++ assert.strictEqual(api.requests[0].body.model, 'deepseek-chat', 'the same model id the agent asked for');
assert.ok(api.requests[0].body.tools.some((t) => t.function.name === 'read_file'), 'the same tools');
assert.ok(api.requests[1].body.messages.some((m) => m.role === 'tool' && m.content.includes('const name = 1;')), 'the tool result went back to the model');
assert.strictEqual(r.receipt_id, 'rcpt_test', 'the Exchange receipt is on the result');
@@@ -73,12 +73,10 @@ const collect = async (run) => { const out = []; for await (const e of run) out.
assert.deepStrictEqual([r.usage.input_tokens, r.usage.cache_read_input_tokens, r.usage.output_tokens], [1200, 800, 200]);
});
-- await check('the agent\'s model ids map to the Exchange\'s catalog ids, and an Exchange id is not mapped again', () => {
-- assert.strictEqual(exchangeModelOf('deepseek-chat'), 'deepseek/deepseek-flash');
-- assert.strictEqual(exchangeModelOf('deepseek-reasoner'), 'deepseek/deepseek-v4-pro');
-- assert.strictEqual(exchangeModelOf('deepseek/deepseek-v4-pro'), 'deepseek/deepseek-v4-pro');
-- assert.strictEqual(exchangeModelOf('openvibe'), 'openvibe');
-- assert.strictEqual(exchangeModelOf('deepseek-chat', { OPENVIBE_EXCHANGE_MODEL: 'openvibe/auto' }), 'openvibe/auto');
++ await check('the agent\'s model id goes as it is; OPENVIBE_EXCHANGE_MODEL can name an Exchange catalog id', () => {
++ assert.strictEqual(exchangeModelOf('deepseek-chat'), 'deepseek-chat');
++ assert.strictEqual(exchangeModelOf('deepseek-reasoner'), 'deepseek-reasoner');
++ assert.strictEqual(exchangeModelOf('deepseek-chat', { OPENVIBE_EXCHANGE_MODEL: 'deepseek/deepseek-v4-pro' }), 'deepseek/deepseek-v4-pro');
});
await check('a service Exchange key is the fallback, and the Exchange URL can be pointed elsewhere', async () => {