diff --git a/packages/api/src/llm/open-router.test.ts b/packages/api/src/llm/open-router.test.ts index cf086d39..c4af7677 100644 --- a/packages/api/src/llm/open-router.test.ts +++ b/packages/api/src/llm/open-router.test.ts @@ -32,7 +32,7 @@ const request = { }; // The body of the request made to OpenRouter. -function sent(): {model: string; messages: unknown[]; tools: unknown[]; max_tokens: number; provider: {data_collection: string}} { +function sent(): {model: string; messages: unknown[]; tools: unknown[]; max_tokens: number; provider: Record} { return JSON.parse(String(fetchSpy.mock.calls[0]?.[1]?.body)); } @@ -48,14 +48,14 @@ describe('askForTurn', () => { expect(body.messages).toEqual(request.messages); expect(body.tools).toEqual([{type: 'function', function: {name: 'read', description: 'Reads', parameters: {type: 'object', properties: {}}}}]); expect(body.max_tokens).toBe(100); - expect(body.provider.data_collection).toBe('deny'); + expect(body.provider).toEqual({data_collection: 'deny'}); }); - test('asks GLM 5.3 for a persona switched to it', async () => { + test('asks GLM 5.3 for a persona switched to it, only of the hosts chosen, and only where they keep nothing', async () => { await askForTurn({...request, model: 'glm'}); expect(sent().model).toBe('z-ai/glm-5.3'); - expect(sent().provider.data_collection).toBe('deny'); + expect(sent().provider).toEqual({only: ['together', 'fireworks', 'deepinfra', 'baseten'], data_collection: 'deny', zdr: true}); }); test('reads the calls the model made, with their arguments as it wrote them', async () => { diff --git a/packages/api/src/llm/open-router.ts b/packages/api/src/llm/open-router.ts index 3819bbff..190773cb 100644 --- a/packages/api/src/llm/open-router.ts +++ b/packages/api/src/llm/open-router.ts @@ -44,7 +44,16 @@ export type ModelTool = {name: string; description: string; parameters: object}; export type {ModelMessage}; // Which hosts of the model OpenRouter may send the request to. -type ProviderPolicy = {order?: string[]; allow_fallbacks?: boolean; data_collection: 'deny'; zdr?: boolean}; +type ProviderPolicy = {order?: string[]; only?: string[]; allow_fallbacks?: boolean; data_collection: 'deny'; zdr?: boolean}; + +// Only a host that neither keeps prompts nor trains on them: the conversation is the person's, +// and what their email and notes say is in it. GLM is open, served by dozens of hosts, the +// cheapest of them the least known: it goes only to these, American, and only where OpenRouter +// records them as keeping nothing, not even for a while to check for abuse. +const TURN_PROVIDERS: Record = { + claude: {data_collection: 'deny'}, + glm: {only: ['together', 'fireworks', 'deepinfra', 'baseten'], data_collection: 'deny', zdr: true}, +}; // What is sent to OpenRouter. type CompletionBody = { @@ -206,9 +215,7 @@ export function askForTurn(request: TurnRequest): Promise ({type: 'function', function: {name: tool.name, description: tool.description, parameters: tool.parameters}})), max_tokens: request.maxTokens, - // Only a host that neither keeps prompts nor trains on them: the conversation is - // the person's, and what their email and notes say is in it. - provider: {data_collection: 'deny'}, + provider: TURN_PROVIDERS[request.model], }, request.timeoutMs, {model: request.model, purpose: 'turn'},