feat: add model selector, skills/memory pages, and config management
- Add model selector in sidebar that discovers models from auth.json credential pool - Add per-session model display (badge in chat header and session list) - Add skills browser page and memory editor page - Add BFF routes for skills, memory, and config model management - Model switching updates config.yaml provider field to bypass env auto-detection - Refactor Settings page, simplify ChatInput with file upload - Add attachment upload support via BFF /upload endpoint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ export interface StartRunRequest {
|
||||
instructions?: string
|
||||
conversation_history?: ChatMessage[]
|
||||
session_id?: string
|
||||
model?: string
|
||||
}
|
||||
|
||||
export interface StartRunResponse {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { request } from './client'
|
||||
|
||||
export interface SkillInfo {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SkillCategory {
|
||||
name: string
|
||||
description: string
|
||||
skills: SkillInfo[]
|
||||
}
|
||||
|
||||
export interface SkillListResponse {
|
||||
categories: SkillCategory[]
|
||||
}
|
||||
|
||||
export interface SkillFileEntry {
|
||||
path: string
|
||||
name: string
|
||||
isDir: boolean
|
||||
}
|
||||
|
||||
export interface MemoryData {
|
||||
memory: string
|
||||
user: string
|
||||
memory_mtime: number | null
|
||||
user_mtime: number | null
|
||||
}
|
||||
|
||||
export async function fetchSkills(): Promise<SkillCategory[]> {
|
||||
const res = await request<SkillListResponse>('/api/skills')
|
||||
return res.categories
|
||||
}
|
||||
|
||||
export async function fetchSkillContent(skillPath: string): Promise<string> {
|
||||
const res = await request<{ content: string }>(`/api/skills/${skillPath}`)
|
||||
return res.content
|
||||
}
|
||||
|
||||
export async function fetchSkillFiles(category: string, skill: string): Promise<SkillFileEntry[]> {
|
||||
const res = await request<{ files: SkillFileEntry[] }>(`/api/skills/${category}/${skill}/files`)
|
||||
return res.files
|
||||
}
|
||||
|
||||
export async function fetchMemory(): Promise<MemoryData> {
|
||||
return request<MemoryData>('/api/memory')
|
||||
}
|
||||
|
||||
export async function saveMemory(section: 'memory' | 'user', content: string): Promise<void> {
|
||||
await request('/api/memory', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ section, content }),
|
||||
})
|
||||
}
|
||||
@@ -16,6 +16,41 @@ export interface ModelsResponse {
|
||||
data: Model[]
|
||||
}
|
||||
|
||||
// Config-based model types
|
||||
export interface ModelInfo {
|
||||
id: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export interface ModelGroup {
|
||||
provider: string
|
||||
models: ModelInfo[]
|
||||
}
|
||||
|
||||
export interface ConfigModelsResponse {
|
||||
default: string
|
||||
groups: ModelGroup[]
|
||||
}
|
||||
|
||||
export interface AvailableModelGroup {
|
||||
provider: string // credential pool key (e.g. "zai", "custom:subrouter.ai")
|
||||
label: string // display name (e.g. "zai", "subrouter.ai")
|
||||
base_url: string
|
||||
models: string[]
|
||||
}
|
||||
|
||||
export interface AvailableModelsResponse {
|
||||
default: string
|
||||
groups: AvailableModelGroup[]
|
||||
}
|
||||
|
||||
export interface CustomProvider {
|
||||
name: string
|
||||
base_url: string
|
||||
api_key: string
|
||||
model: string
|
||||
}
|
||||
|
||||
export async function checkHealth(): Promise<HealthResponse> {
|
||||
return request<HealthResponse>('/health')
|
||||
}
|
||||
@@ -23,3 +58,36 @@ export async function checkHealth(): Promise<HealthResponse> {
|
||||
export async function fetchModels(): Promise<ModelsResponse> {
|
||||
return request<ModelsResponse>('/v1/models')
|
||||
}
|
||||
|
||||
export async function fetchConfigModels(): Promise<ConfigModelsResponse> {
|
||||
return request<ConfigModelsResponse>('/api/config/models')
|
||||
}
|
||||
|
||||
export async function fetchAvailableModels(): Promise<AvailableModelsResponse> {
|
||||
return request<AvailableModelsResponse>('/api/available-models')
|
||||
}
|
||||
|
||||
export async function updateDefaultModel(data: {
|
||||
default: string
|
||||
provider?: string
|
||||
base_url?: string
|
||||
api_key?: string
|
||||
}): Promise<void> {
|
||||
await request('/api/config/model', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function addCustomProvider(data: CustomProvider): Promise<void> {
|
||||
await request('/api/config/providers', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
export async function removeCustomProvider(name: string): Promise<void> {
|
||||
await request(`/api/config/providers/${encodeURIComponent(name)}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user