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
2 changes: 2 additions & 0 deletions agents/__tests__/base2.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, test } from 'bun:test'

import {
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_KIMI_MODEL_ID,
FREEBUFF_MINIMAX_MODEL_ID,
Expand All @@ -13,6 +14,7 @@ describe('base2 reviewer selection', () => {
[FREEBUFF_MINIMAX_MODEL_ID, 'code-reviewer-minimax'],
[FREEBUFF_KIMI_MODEL_ID, 'code-reviewer-kimi'],
[FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID, 'code-reviewer-deepseek'],
[FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID, 'code-reviewer-deepseek-flash'],
])('uses matching reviewer for model %p', (model, expectedReviewer) => {
const base2 = createBase2('free', { model })

Expand Down
13 changes: 13 additions & 0 deletions agents/base2/base2-free-deepseek-flash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID } from '@codebuff/common/constants/freebuff-models'

import { createBase2 } from './base2'

const definition = {
...createBase2('free', {
model: FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
}),
id: 'base2-free-deepseek-flash',
displayName: 'Buffy the DeepSeek Flash Free Orchestrator',
}

export default definition
1 change: 0 additions & 1 deletion agents/base2/base2-free-deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { createBase2 } from './base2'

const definition = {
...createBase2('free', {
noAskUser: true,
model: FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
}),
id: 'base2-free-deepseek',
Expand Down
13 changes: 13 additions & 0 deletions agents/reviewer/code-reviewer-deepseek-flash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID } from '@codebuff/common/constants/freebuff-models'

import { publisher } from '../constants'
import type { SecretAgentDefinition } from '../types/secret-agent-definition'
import { createReviewer } from './code-reviewer'

const definition: SecretAgentDefinition = {
id: 'code-reviewer-deepseek-flash',
publisher,
...createReviewer(FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID),
}

export default definition
2 changes: 2 additions & 0 deletions agents/types/agent-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ export type ModelName =
// DeepSeek
| 'deepseek/deepseek-v4-pro'
| 'deepseek-v4-pro'
| 'deepseek/deepseek-v4-flash'
| 'deepseek-v4-flash'
| 'deepseek/deepseek-chat-v3-0324'
| 'deepseek/deepseek-chat-v3-0324:nitro'
| 'deepseek/deepseek-r1-0528'
Expand Down
22 changes: 22 additions & 0 deletions common/src/__tests__/free-agents.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, test } from 'bun:test'

import {
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_GEMINI_PRO_MODEL_ID,
FREEBUFF_KIMI_MODEL_ID,
Expand All @@ -24,6 +25,9 @@ describe('free mode agent model allowlist', () => {
expect(
getFreebuffRootAgentIdForModel(FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID),
).toBe('base2-free-deepseek')
expect(
getFreebuffRootAgentIdForModel(FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID),
).toBe('base2-free-deepseek-flash')
})

test('allows each freebuff root agent only with its configured model', () => {
Expand All @@ -48,6 +52,12 @@ describe('free mode agent model allowlist', () => {
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
),
).toBe(true)
expect(
isFreeModeAllowedAgentModel(
'base2-free-deepseek-flash',
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
),
).toBe(true)
})

test('allows each freebuff reviewer agent only with its configured model', () => {
Expand All @@ -72,6 +82,12 @@ describe('free mode agent model allowlist', () => {
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
),
).toBe(true)
expect(
isFreeModeAllowedAgentModel(
'code-reviewer-deepseek-flash',
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
),
).toBe(true)
})

test('allows legacy code-reviewer-lite with freebuff reviewer models', () => {
Expand All @@ -90,6 +106,12 @@ describe('free mode agent model allowlist', () => {
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
),
).toBe(true)
expect(
isFreeModeAllowedAgentModel(
'code-reviewer-lite',
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
),
).toBe(true)
})

test('allows the browser-use subagent with its bundled model', () => {
Expand Down
15 changes: 15 additions & 0 deletions common/src/__tests__/freebuff-models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { describe, expect, test } from 'bun:test'
import {
canFreebuffModelSpawnGeminiThinker,
DEFAULT_FREEBUFF_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_GLM_MODEL_ID,
FREEBUFF_KIMI_MODEL_ID,
Expand All @@ -12,6 +13,7 @@ import {
getFreebuffDeploymentAvailabilityLabel,
isFreebuffDeploymentHours,
isFreebuffModelId,
isFreebuffPremiumModelId,
isSupportedFreebuffModelId,
} from '../constants/freebuff-models'

Expand All @@ -27,6 +29,16 @@ describe('freebuff model availability', () => {
expect(deepseek?.warning).toBe('Collects data for training')
})

test('DeepSeek V4 Flash is selectable and unlimited', () => {
expect(FREEBUFF_MODELS.map((model) => model.id)).toContain(
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
)
expect(isFreebuffModelId(FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID)).toBe(true)
expect(isFreebuffPremiumModelId(FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID)).toBe(
false,
)
})

test('only smart freebuff models can spawn the gemini-thinker subagent', () => {
expect(canFreebuffModelSpawnGeminiThinker(FREEBUFF_KIMI_MODEL_ID)).toBe(
true,
Expand All @@ -37,6 +49,9 @@ describe('freebuff model availability', () => {
expect(canFreebuffModelSpawnGeminiThinker(FREEBUFF_MINIMAX_MODEL_ID)).toBe(
false,
)
expect(
canFreebuffModelSpawnGeminiThinker(FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID),
).toBe(false)
})

test('supports GLM 5.1 as a legacy server-side model without selecting it for new clients', () => {
Expand Down
10 changes: 10 additions & 0 deletions common/src/constants/free-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { parseAgentId } from '../util/agent-id-parsing'

import { FREEBUFF_GEMINI_THINKER_AGENT_ID } from './freebuff-gemini-thinker'
import {
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_GEMINI_PRO_MODEL_ID,
FREEBUFF_GLM_MODEL_ID,
Expand All @@ -28,6 +29,7 @@ export const FREEBUFF_ROOT_AGENT_IDS = [
'base2-free',
'base2-free-kimi',
'base2-free-deepseek',
'base2-free-deepseek-flash',
] as const
const FREEBUFF_ROOT_AGENT_ID_SET: ReadonlySet<string> = new Set(
FREEBUFF_ROOT_AGENT_IDS,
Expand All @@ -40,12 +42,14 @@ export const FREEBUFF_ROOT_AGENT_ID_BY_MODEL: Record<string, string> = {
[FREEBUFF_MINIMAX_MODEL_ID]: 'base2-free',
[FREEBUFF_KIMI_MODEL_ID]: 'base2-free-kimi',
[FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID]: 'base2-free-deepseek',
[FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID]: 'base2-free-deepseek-flash',
}

export const FREEBUFF_REVIEWER_AGENT_ID_BY_MODEL: Record<string, string> = {
[FREEBUFF_MINIMAX_MODEL_ID]: 'code-reviewer-minimax',
[FREEBUFF_KIMI_MODEL_ID]: 'code-reviewer-kimi',
[FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID]: 'code-reviewer-deepseek',
[FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID]: 'code-reviewer-deepseek-flash',
}

export function getFreebuffRootAgentIdForModel(model: string): string {
Expand All @@ -66,10 +70,12 @@ export const FREE_MODE_AGENT_MODELS: Record<string, Set<string>> = {
FREEBUFF_MINIMAX_MODEL_ID,
FREEBUFF_GLM_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
FREEBUFF_KIMI_MODEL_ID,
]),
'base2-free-kimi': new Set([FREEBUFF_KIMI_MODEL_ID]),
'base2-free-deepseek': new Set([FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID]),
'base2-free-deepseek-flash': new Set([FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID]),

// File exploration agents
'file-picker': new Set(['google/gemini-2.5-flash-lite']),
Expand All @@ -93,12 +99,16 @@ export const FREE_MODE_AGENT_MODELS: Record<string, Set<string>> = {
]),
'code-reviewer-kimi': new Set([FREEBUFF_KIMI_MODEL_ID]),
'code-reviewer-deepseek': new Set([FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID]),
'code-reviewer-deepseek-flash': new Set([
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
]),
// Legacy freebuff clients spawned code-reviewer-lite under provider-specific
// free roots before those reviewer IDs existed.
'code-reviewer-lite': new Set([
FREEBUFF_MINIMAX_MODEL_ID,
FREEBUFF_KIMI_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
]),

// Legacy: kept for the standalone gemini thinker agent if invoked directly.
Expand Down
7 changes: 7 additions & 0 deletions common/src/constants/freebuff-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface FreebuffModelOption {
export const FREEBUFF_DEPLOYMENT_HOURS_LABEL = '9am ET-5pm PT every day'
export const FREEBUFF_GEMINI_PRO_MODEL_ID = 'google/gemini-3.1-pro-preview'
export const FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID = 'deepseek/deepseek-v4-pro'
export const FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID = 'deepseek/deepseek-v4-flash'
export const FREEBUFF_GLM_MODEL_ID = 'z-ai/glm-5.1'
export const FREEBUFF_KIMI_MODEL_ID = 'moonshotai/kimi-k2.6'
export const FREEBUFF_MINIMAX_MODEL_ID = 'minimax/minimax-m2.7'
Expand Down Expand Up @@ -86,6 +87,12 @@ export const FREEBUFF_MODELS = [
tagline: 'Fastest',
availability: 'always',
},
{
id: FREEBUFF_DEEPSEEK_V4_FLASH_MODEL_ID,
displayName: 'DeepSeek V4 Flash',
tagline: 'Most efficient',
availability: 'always',
},
] as const satisfies readonly FreebuffModelOption[]

export const LEGACY_FREEBUFF_MODELS = [
Expand Down
2 changes: 2 additions & 0 deletions common/src/constants/model-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const deepseekModels = {
deepseekReasoner: 'deepseek-reasoner',
deepseekV4ProDirect: 'deepseek-v4-pro',
deepseekV4Pro: 'deepseek/deepseek-v4-pro',
deepseekV4FlashDirect: 'deepseek-v4-flash',
deepseekV4Flash: 'deepseek/deepseek-v4-flash',
} as const
export type DeepseekModel = (typeof deepseekModels)[keyof typeof deepseekModels]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ export type ModelName =
// DeepSeek
| 'deepseek/deepseek-v4-pro'
| 'deepseek-v4-pro'
| 'deepseek/deepseek-v4-flash'
| 'deepseek-v4-flash'
| 'deepseek/deepseek-chat-v3-0324'
| 'deepseek/deepseek-chat-v3-0324:nitro'
| 'deepseek/deepseek-r1-0528'
Expand Down
Loading
Loading