Skip to content
Closed
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: 1 addition & 1 deletion backend/src/inference/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ describe('Inference Routes', () => {
})

it('should validate all supported models', () => {
const expectedModels = ['mistral-medium-3.1', 'mistral-large-3', 'sonnet-4.5', 'opus-4.8']
const expectedModels = ['mistral-medium-3.1', 'mistral-large-3', 'sonnet-4.5', 'opus-4.8', 'deepseek-v4-flash']
expect(Object.keys(supportedModels)).toEqual(expectedModels)
})

Expand Down
4 changes: 4 additions & 0 deletions backend/src/inference/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export const supportedModels: Record<string, ModelConfig> = {
internalName: 'claude-opus-4-8',
omitTemperature: true,
},
'deepseek-v4-flash': {
provider: 'fireworks',
internalName: 'accounts/fireworks/models/deepseek-v4-flash',
},
}

/**
Expand Down
2 changes: 1 addition & 1 deletion backend/src/tinfoil/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ describe('createTinfoilRoutes', () => {

it('forwards JSON bodies untouched (parse: none keeps the stream intact)', async () => {
const app = buildApp()
const jsonBody = JSON.stringify({ model: 'deepseek-v4-pro', messages: [] })
const jsonBody = JSON.stringify({ model: 'glm-5-2', messages: [] })

await drain(
await app.handle(
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/model-selector/model-selector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('needsApiKey', () => {
test('system tinfoil rows do not need a key (injected by backend proxy)', () => {
const model = makeModel({
id: 'tinfoil-system',
name: 'DeepSeek V4 Pro',
name: 'GLM 5.2',
provider: 'tinfoil',
isSystem: 1,
apiKey: null,
Expand Down
4 changes: 2 additions & 2 deletions src/defaults/model-profiles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ describe('hashModelProfile', () => {
})

describe('defaultModelProfiles', () => {
test('contains four profiles', () => {
expect(defaultModelProfiles).toHaveLength(4)
test('contains three profiles', () => {
expect(defaultModelProfiles).toHaveLength(3)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny thought, feel free to ignore: these count tests need a manual bump every time the lineup changes. An assertion that every default profile's modelId maps to a default model (and the other way around) would catch real wiring mistakes without the ceremony.

})

test('each profile has a non-null modelId', () => {
Expand Down
3 changes: 1 addition & 2 deletions src/defaults/model-profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

export {
defaultModelProfileDeepseekV4Pro,
defaultModelProfileDeepseekV4Flash,
defaultModelProfileGlm52,
defaultModelProfileKimiK26,
defaultModelProfileOpus48,
defaultModelProfiles,
hashModelProfile,
Expand Down
6 changes: 3 additions & 3 deletions src/defaults/model-profiles/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import type { ModelProfile } from '@/types'
import { defaultModelDeepseekV4Pro } from '@/defaults/models'
import { defaultModelDeepseekV4Flash } from '@/defaults/models'

export const defaultModelProfileDeepseekV4Pro: ModelProfile = {
modelId: defaultModelDeepseekV4Pro.id,
export const defaultModelProfileDeepseekV4Flash: ModelProfile = {
modelId: defaultModelDeepseekV4Flash.id,
temperature: 0.2,
maxSteps: 20,
maxAttempts: 2,
Expand Down
9 changes: 3 additions & 6 deletions src/defaults/model-profiles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

import { hashValues } from '@/lib/utils'
import type { ModelProfile } from '@/types'
import { defaultModelProfileDeepseekV4Pro } from './deepseek'
import { defaultModelProfileDeepseekV4Flash } from './deepseek'
import { defaultModelProfileGlm52 } from './glm'
import { defaultModelProfileKimiK26 } from './kimi'
import { defaultModelProfileOpus48 } from './opus'

export { defaultModelProfileDeepseekV4Pro } from './deepseek'
export { defaultModelProfileDeepseekV4Flash } from './deepseek'
export { defaultModelProfileGlm52 } from './glm'
export { defaultModelProfileKimiK26 } from './kimi'
export { defaultModelProfileOpus48 } from './opus'

/**
Expand Down Expand Up @@ -46,7 +44,6 @@ export const hashModelProfile = (profile: ModelProfile): string =>
/** All default model profiles for iteration */
export const defaultModelProfiles: ReadonlyArray<ModelProfile> = [
defaultModelProfileOpus48,
defaultModelProfileDeepseekV4Pro,
defaultModelProfileKimiK26,
defaultModelProfileDeepseekV4Flash,
defaultModelProfileGlm52,
] as const
32 changes: 0 additions & 32 deletions src/defaults/model-profiles/kimi.ts

This file was deleted.

46 changes: 16 additions & 30 deletions src/defaults/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,22 @@ export const defaultModelOpus48: Model = {
userId: null,
}

export const defaultModelDeepseekV4Pro: Model = {
id: '019e70af-e5b2-76d0-9ede-f22d8265bb14',
name: 'DeepSeek V4 Pro',
provider: 'tinfoil',
model: 'deepseek-v4-pro',
/**
* Flash ships under a fresh id — not the retired V4 Pro id. Reusing Pro's id
* would flip isConfidential 1→0 on threads that were created encrypted
* (isEncrypted mirrors the model's isConfidential at creation), stranding them
* because the model picker and send guard both enforce isEncrypted === isConfidential.
* cleanupRemovedDefaults soft-deletes the Pro row instead, so those threads
* surface as "model retired" rather than broken.
*/
export const defaultModelDeepseekV4Flash: Model = {
id: '019f227e-d640-727d-ba12-d51bd7d0a3d6',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love that Flash ships under a fresh id, the reasoning above checks out on every enforcement point I traced. One thing worries me though: any device still on an older build already runs cleanupRemovedDefaults, and its defaults array doesn't contain this id. When the Flash row syncs to that device it looks like an unedited system model that's no longer shipped, so the old client soft deletes it. And since hashModel includes deletedAt, updated clients then treat the row as user modified and never bring it back, so the whole account loses the new default for good. A lagging desktop app next to an updated web session is enough to trigger it. Maybe cleanup should only touch an explicit list of retired ids, or reconcile could resurrect a row whose hash matches the shipped default plus deletedAt?

name: 'DeepSeek V4 Flash',
provider: 'thunderbolt',
model: 'deepseek-v4-flash',
isSystem: 1,
enabled: 1,
isConfidential: 1,
isConfidential: 0,
Comment thread
raivieiraadriano92 marked this conversation as resolved.
contextWindow: 131072,
toolUsage: 1,
startWithReasoning: 0,
Expand All @@ -75,28 +83,7 @@ export const defaultModelDeepseekV4Pro: Model = {
url: null,
defaultHash: null,
vendor: 'deepseek',
description: 'Confidential reasoning via Tinfoil',
userId: null,
}

export const defaultModelKimiK26: Model = {
id: '019e7580-2b0c-77d6-8b99-16a99abe4591',
name: 'Kimi K2.6',
provider: 'tinfoil',
model: 'kimi-k2-6',
isSystem: 1,
enabled: 1,
isConfidential: 1,
contextWindow: 131072,
toolUsage: 1,
startWithReasoning: 0,
supportsParallelToolCalls: 0,
deletedAt: null,
apiKey: null,
url: null,
defaultHash: null,
vendor: 'moonshot',
description: 'Confidential chat via Tinfoil',
description: 'Fast DeepSeek reasoning',
userId: null,
}

Expand Down Expand Up @@ -127,7 +114,6 @@ export const defaultModelGlm52: Model = {
*/
export const defaultModels: ReadonlyArray<Model> = [
defaultModelOpus48,
defaultModelDeepseekV4Pro,
defaultModelKimiK26,
defaultModelDeepseekV4Flash,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging with no strong feelings: user edited Pro or Kimi rows survive by design, still pointing at Tinfoil ids that are presumably going away upstream. Those users will hit raw upstream errors with no hint the model was retired. If that's the accepted tradeoff, all good.

defaultModelGlm52,
] as const
Loading