From 341c35d194493624f43f93cd24cf2d0b14240417 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Mon, 4 May 2026 23:26:02 -0700 Subject: [PATCH] Allow browser-use in free mode --- common/src/__tests__/free-agents.test.ts | 9 ++++ common/src/constants/free-agents.ts | 3 ++ .../completions/__tests__/completions.test.ts | 41 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/common/src/__tests__/free-agents.test.ts b/common/src/__tests__/free-agents.test.ts index e6370c9cc..6913f4834 100644 --- a/common/src/__tests__/free-agents.test.ts +++ b/common/src/__tests__/free-agents.test.ts @@ -8,6 +8,15 @@ import { } from '../constants/free-agents' describe('free mode agent model allowlist', () => { + test('allows the browser-use subagent with its bundled model', () => { + expect( + isFreeModeAllowedAgentModel( + 'browser-use', + 'google/gemini-3.1-flash-lite-preview', + ), + ).toBe(true) + }) + test('allows Gemini Pro for the thinker subagent but not the freebuff root', () => { expect( isFreeModeAllowedAgentModel('base2-free', FREEBUFF_GEMINI_PRO_MODEL_ID), diff --git a/common/src/constants/free-agents.ts b/common/src/constants/free-agents.ts index 4a6078e92..9d41abd89 100644 --- a/common/src/constants/free-agents.ts +++ b/common/src/constants/free-agents.ts @@ -54,6 +54,9 @@ export const FREE_MODE_AGENT_MODELS: Record> = { 'researcher-web': new Set(['google/gemini-3.1-flash-lite-preview']), 'researcher-docs': new Set(['google/gemini-3.1-flash-lite-preview']), + // Browser automation + 'browser-use': new Set(['google/gemini-3.1-flash-lite-preview']), + // Command execution basher: new Set(['google/gemini-3.1-flash-lite-preview']), diff --git a/web/src/app/api/v1/chat/completions/__tests__/completions.test.ts b/web/src/app/api/v1/chat/completions/__tests__/completions.test.ts index a5a91dee0..6f98c96a3 100644 --- a/web/src/app/api/v1/chat/completions/__tests__/completions.test.ts +++ b/web/src/app/api/v1/chat/completions/__tests__/completions.test.ts @@ -184,6 +184,13 @@ describe('/api/v1/chat/completions POST endpoint', () => { status: 'running', } } + if (runId === 'run-browser-use-child') { + return { + agent_id: 'browser-use', + ancestor_run_ids: ['run-free'], + status: 'running', + } + } if (runId === 'run-completed') { return { agent_id: 'agent-123', @@ -917,6 +924,40 @@ describe('/api/v1/chat/completions POST endpoint', () => { expect(body.error).toBe('free_mode_invalid_agent_model') }) + it('allows browser-use as a free-mode subagent under a freebuff root', async () => { + const req = new NextRequest( + 'http://localhost:3000/api/v1/chat/completions', + { + method: 'POST', + headers: allowedFreeModeHeaders('test-api-key-new-free-gemini'), + body: JSON.stringify({ + model: 'google/gemini-3.1-flash-lite-preview', + stream: false, + codebuff_metadata: { + run_id: 'run-browser-use-child', + client_id: 'test-client-id-123', + cost_mode: 'free', + }, + }), + }, + ) + + const response = await postChatCompletions({ + req, + getUserInfoFromApiKey: mockGetUserInfoFromApiKey, + logger: mockLogger, + trackEvent: mockTrackEvent, + getUserUsageData: mockGetUserUsageData, + getAgentRunFromId: mockGetAgentRunFromId, + fetch: mockFetch, + insertMessageBigquery: mockInsertMessageBigquery, + loggerWithContext: mockLoggerWithContext, + checkSessionAdmissible: mockCheckSessionAdmissibleAllow, + }) + + expect(response.status).toBe(200) + }) + it('rejects standalone free-mode reviewer runs even when the model is allowlisted', async () => { const req = new NextRequest( 'http://localhost:3000/api/v1/chat/completions',