feat(hub,web): support custom Claude models via settings.json (customClaudeModels)

This commit is contained in:
2026-08-02 22:32:19 +08:00
parent da59a0011a
commit 087cb08e53
6 changed files with 66 additions and 2 deletions
+4
View File
@@ -198,6 +198,10 @@ export class ApiClient {
return await this.request<PushVapidPublicKeyResponse>('/api/push/vapid-public-key')
}
async getClaudeCustomModels(): Promise<{ models: string[] }> {
return await this.request<{ models: string[] }>('/api/claude/custom-models')
}
async subscribePushNotifications(payload: PushSubscriptionPayload): Promise<void> {
await this.request('/api/push/subscribe', {
method: 'POST',
+30 -1
View File
@@ -35,6 +35,7 @@ import {
shouldRestoreNewSessionFormDraft
} from './newSessionFormDraft'
import type { AgentType, LaunchEffort, CodexReasoningEffort, NewSessionServiceTier, SessionType } from './types'
import { MODEL_OPTIONS } from './types'
import { ActionButtons } from './ActionButtons'
import { AgentSelector } from './AgentSelector'
import { CollaborationModeSelector } from './CollaborationModeSelector'
@@ -246,6 +247,32 @@ export function NewSession(props: {
machineId,
enabled: agent === 'codex' && Boolean(machineId)
})
const [claudeCustomModels, setClaudeCustomModels] = useState<string[]>([])
useEffect(() => {
let cancelled = false
if (!props.api) {
return
}
props.api.getClaudeCustomModels().then((result) => {
if (!cancelled) {
setClaudeCustomModels(Array.isArray(result.models) ? result.models : [])
}
}).catch(() => {
// Custom models are optional — fall back to the built-in presets.
})
return () => {
cancelled = true
}
}, [props.api])
const claudeModelOptions = useMemo(() => {
const options = [...MODEL_OPTIONS.claude]
for (const modelName of claudeCustomModels) {
if (!options.some((option) => option.value === modelName)) {
options.push({ value: modelName, label: modelName })
}
}
return options
}, [claudeCustomModels])
const runnerSpawnError = useMemo(
() => formatRunnerSpawnError(selectedMachine),
[selectedMachine]
@@ -1321,7 +1348,9 @@ export function NewSession(props: {
agent={agent}
model={model}
options={
agent === 'codex'
agent === 'claude'
? claudeModelOptions
: agent === 'codex'
? codexModelOptions
: agent === 'grok'
? grokModelOptions