Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions common/src/__tests__/free-agents.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
3 changes: 3 additions & 0 deletions common/src/constants/free-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export const FREE_MODE_AGENT_MODELS: Record<string, Set<string>> = {
'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']),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down
Loading