mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-17 11:07:11 +08:00
feat(desktop): align API client and types with latest web backend endpoints
This commit is contained in:
@@ -1,38 +1,74 @@
|
||||
import type { ConfigData, ChannelInfo, SkillInfo, ToolInfo, MemoryItem, SchedulerTask, Attachment } from '../types'
|
||||
import type {
|
||||
ConfigData,
|
||||
ChannelInfo,
|
||||
ChannelAction,
|
||||
SkillInfo,
|
||||
ToolInfo,
|
||||
MemoryItem,
|
||||
MemoryCategory,
|
||||
MemoryPage,
|
||||
SchedulerTask,
|
||||
Attachment,
|
||||
SessionsPage,
|
||||
HistoryPage,
|
||||
ModelsData,
|
||||
ModelsAction,
|
||||
KnowledgeList,
|
||||
KnowledgeGraph,
|
||||
KnowledgeAction,
|
||||
} from '../types'
|
||||
|
||||
interface ApiResult {
|
||||
status: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
class ApiClient {
|
||||
private baseUrl: string = 'http://127.0.0.1:9899'
|
||||
private baseUrl = 'http://127.0.0.1:9899'
|
||||
|
||||
setBaseUrl(url: string) {
|
||||
this.baseUrl = url
|
||||
}
|
||||
|
||||
getBaseUrl() {
|
||||
return this.baseUrl
|
||||
}
|
||||
|
||||
private async request<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
const res = await fetch(`${this.baseUrl}${path}`, {
|
||||
...options,
|
||||
// Send cookies for future web_password auth support
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers,
|
||||
},
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
|
||||
return res.json()
|
||||
}
|
||||
|
||||
// Chat
|
||||
// ---------------------------------------------------------
|
||||
// Chat / messages
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async sendMessage(
|
||||
sessionId: string,
|
||||
message: string,
|
||||
stream: boolean = true,
|
||||
attachments?: Attachment[]
|
||||
): Promise<{ status: string; request_id: string; stream: boolean }> {
|
||||
opts?: { stream?: boolean; attachments?: Attachment[]; isVoice?: boolean; lang?: string }
|
||||
): Promise<{ status: string; request_id: string; stream: boolean; inline_reply?: string }> {
|
||||
return this.request('/message', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ session_id: sessionId, message, stream, attachments }),
|
||||
body: JSON.stringify({
|
||||
session_id: sessionId,
|
||||
message,
|
||||
stream: opts?.stream ?? true,
|
||||
attachments: opts?.attachments,
|
||||
is_voice: opts?.isVoice ?? false,
|
||||
lang: opts?.lang,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -49,10 +85,38 @@ class ApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
async cancel(opts: { requestId?: string; sessionId?: string; lang?: string }): Promise<{ status: string; cancelled: number }> {
|
||||
return this.request('/cancel', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ request_id: opts.requestId, session_id: opts.sessionId, lang: opts.lang }),
|
||||
})
|
||||
}
|
||||
|
||||
createSSEStream(requestId: string): EventSource {
|
||||
return new EventSource(`${this.baseUrl}/stream?request_id=${requestId}`)
|
||||
}
|
||||
|
||||
async deleteMessage(opts: {
|
||||
sessionId: string
|
||||
userSeq: number
|
||||
deleteUser?: boolean
|
||||
cascade?: boolean
|
||||
}): Promise<{ status: string; deleted: number }> {
|
||||
return this.request('/api/messages/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
session_id: opts.sessionId,
|
||||
user_seq: opts.userSeq,
|
||||
delete_user: opts.deleteUser ?? true,
|
||||
cascade: opts.cascade ?? false,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Upload / files
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async uploadFile(file: File, sessionId?: string): Promise<{
|
||||
status: string
|
||||
file_path: string
|
||||
@@ -62,49 +126,138 @@ class ApiClient {
|
||||
}> {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (sessionId) {
|
||||
formData.append('session_id', sessionId)
|
||||
}
|
||||
|
||||
if (sessionId) formData.append('session_id', sessionId)
|
||||
const res = await fetch(`${this.baseUrl}/upload`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include',
|
||||
})
|
||||
|
||||
return res.json()
|
||||
}
|
||||
|
||||
// Config
|
||||
async getConfig(): Promise<ConfigData> {
|
||||
const data = await this.request<{ status: string } & ConfigData>('/config')
|
||||
return data
|
||||
getFileUrl(previewUrl: string): string {
|
||||
if (/^https?:\/\//.test(previewUrl)) return previewUrl
|
||||
return `${this.baseUrl}${previewUrl}`
|
||||
}
|
||||
|
||||
async updateConfig(updates: Partial<ConfigData>): Promise<{ status: string; applied: Record<string, unknown> }> {
|
||||
getServeFileUrl(absPath: string): string {
|
||||
return `${this.baseUrl}/api/file?path=${encodeURIComponent(absPath)}`
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Sessions
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getSessions(page = 1, pageSize = 50): Promise<SessionsPage> {
|
||||
return this.request<{ status: string } & SessionsPage>(`/api/sessions?page=${page}&page_size=${pageSize}`)
|
||||
}
|
||||
|
||||
async deleteSession(sessionId: string): Promise<ApiResult> {
|
||||
return this.request(`/api/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
async renameSession(sessionId: string, title: string): Promise<ApiResult> {
|
||||
return this.request(`/api/sessions/${encodeURIComponent(sessionId)}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ title }),
|
||||
})
|
||||
}
|
||||
|
||||
async generateSessionTitle(sessionId: string, userMessage: string, assistantReply?: string): Promise<{ status: string; title: string }> {
|
||||
return this.request(`/api/sessions/${encodeURIComponent(sessionId)}/generate_title`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ user_message: userMessage, assistant_reply: assistantReply }),
|
||||
})
|
||||
}
|
||||
|
||||
async clearContext(sessionId: string): Promise<{ status: string; context_start_seq: number }> {
|
||||
return this.request(`/api/sessions/${encodeURIComponent(sessionId)}/clear_context`, { method: 'POST' })
|
||||
}
|
||||
|
||||
async getHistory(sessionId: string, page = 1, pageSize = 20): Promise<HistoryPage> {
|
||||
return this.request<{ status: string } & HistoryPage>(
|
||||
`/api/history?session_id=${encodeURIComponent(sessionId)}&page=${page}&page_size=${pageSize}`
|
||||
)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Config
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getConfig(): Promise<ConfigData> {
|
||||
return this.request<{ status: string } & ConfigData>('/config')
|
||||
}
|
||||
|
||||
async updateConfig(updates: Record<string, unknown>): Promise<{ status: string; applied: Record<string, unknown> }> {
|
||||
return this.request('/config', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ updates }),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Models console
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getModels(): Promise<ModelsData> {
|
||||
return this.request<{ status: string } & ModelsData>('/api/models')
|
||||
}
|
||||
|
||||
async modelsAction(action: ModelsAction): Promise<Record<string, unknown> & { status: string }> {
|
||||
return this.request('/api/models', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(action),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Channels
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getChannels(): Promise<ChannelInfo[]> {
|
||||
const data = await this.request<{ status: string; channels: ChannelInfo[] }>('/api/channels')
|
||||
return data.channels
|
||||
}
|
||||
|
||||
async channelAction(
|
||||
action: 'save' | 'connect' | 'disconnect',
|
||||
action: ChannelAction,
|
||||
channel: string,
|
||||
config?: Record<string, unknown>
|
||||
): Promise<{ status: string }> {
|
||||
): Promise<Record<string, unknown> & { status: string }> {
|
||||
return this.request('/api/channels', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action, channel, config }),
|
||||
})
|
||||
}
|
||||
|
||||
// Tools & Skills
|
||||
// Weixin QR login
|
||||
async getWeixinQr(): Promise<{ status: string; qrcode_url?: string; qr_image?: string; source?: string; message?: string }> {
|
||||
return this.request('/api/weixin/qrlogin')
|
||||
}
|
||||
|
||||
async weixinQrAction(action: 'poll' | 'refresh'): Promise<Record<string, unknown> & { status: string }> {
|
||||
return this.request('/api/weixin/qrlogin', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action }),
|
||||
})
|
||||
}
|
||||
|
||||
// Feishu one-click register
|
||||
async getFeishuRegister(): Promise<{ status: string; qrcode_url?: string; qr_image?: string; expire_in?: number; message?: string }> {
|
||||
return this.request('/api/feishu/register')
|
||||
}
|
||||
|
||||
async feishuRegisterPoll(): Promise<Record<string, unknown> & { status: string }> {
|
||||
return this.request('/api/feishu/register', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action: 'poll' }),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Tools & skills
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getTools(): Promise<ToolInfo[]> {
|
||||
const data = await this.request<{ status: string; tools: ToolInfo[] }>('/api/tools')
|
||||
return data.tools
|
||||
@@ -115,60 +268,136 @@ class ApiClient {
|
||||
return data.skills
|
||||
}
|
||||
|
||||
async toggleSkill(name: string, action: 'open' | 'close'): Promise<{ status: string }> {
|
||||
async toggleSkill(name: string, action: 'open' | 'close'): Promise<ApiResult> {
|
||||
return this.request('/api/skills', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action, name }),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Memory
|
||||
async getMemoryList(page: number = 1, pageSize: number = 20): Promise<{ list: MemoryItem[]; total: number }> {
|
||||
const data = await this.request<{ status: string; list: MemoryItem[]; total: number }>(
|
||||
`/api/memory?page=${page}&page_size=${pageSize}`
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getMemoryList(page = 1, pageSize = 20, category: MemoryCategory = 'memory'): Promise<MemoryPage> {
|
||||
return this.request<{ status: string } & MemoryPage>(
|
||||
`/api/memory?page=${page}&page_size=${pageSize}&category=${category}`
|
||||
)
|
||||
return { list: data.list, total: data.total }
|
||||
}
|
||||
|
||||
async getMemoryContent(filename: string): Promise<string> {
|
||||
async getMemoryContent(filename: string, category: MemoryCategory = 'memory'): Promise<string> {
|
||||
const data = await this.request<{ status: string; content: string }>(
|
||||
`/api/memory/content?filename=${encodeURIComponent(filename)}`
|
||||
`/api/memory/content?filename=${encodeURIComponent(filename)}&category=${category}`
|
||||
)
|
||||
return data.content
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Knowledge
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getKnowledgeList(): Promise<KnowledgeList> {
|
||||
return this.request<{ status: string } & KnowledgeList>('/api/knowledge/list')
|
||||
}
|
||||
|
||||
async readKnowledge(path: string): Promise<{ status: string; content: string; path: string }> {
|
||||
return this.request(`/api/knowledge/read?path=${encodeURIComponent(path)}`)
|
||||
}
|
||||
|
||||
async getKnowledgeGraph(): Promise<KnowledgeGraph> {
|
||||
return this.request<KnowledgeGraph>('/api/knowledge/graph')
|
||||
}
|
||||
|
||||
async knowledgeAction(req: KnowledgeAction): Promise<Record<string, unknown> & { status: string }> {
|
||||
return this.request('/api/knowledge/action', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(req),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Scheduler
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async getSchedulerTasks(): Promise<SchedulerTask[]> {
|
||||
const data = await this.request<{ status: string; tasks: SchedulerTask[] }>('/api/scheduler')
|
||||
return data.tasks
|
||||
}
|
||||
|
||||
// History
|
||||
async getHistory(
|
||||
sessionId: string,
|
||||
page: number = 1,
|
||||
pageSize: number = 20
|
||||
): Promise<{ messages: ChatMessage[]; has_more: boolean }> {
|
||||
const data = await this.request<{ status: string; messages: ChatMessage[]; has_more: boolean }>(
|
||||
`/api/history?session_id=${sessionId}&page=${page}&page_size=${pageSize}`
|
||||
)
|
||||
return { messages: data.messages, has_more: data.has_more }
|
||||
async toggleTask(taskId: string, enabled: boolean): Promise<{ status: string; task: SchedulerTask }> {
|
||||
return this.request('/api/scheduler/toggle', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ task_id: taskId, enabled }),
|
||||
})
|
||||
}
|
||||
|
||||
// Logs SSE
|
||||
async updateTask(taskId: string, updates: Partial<Pick<SchedulerTask, 'name' | 'enabled' | 'schedule' | 'action'>>): Promise<{ status: string; task: SchedulerTask }> {
|
||||
return this.request('/api/scheduler/update', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ task_id: taskId, ...updates }),
|
||||
})
|
||||
}
|
||||
|
||||
async deleteTask(taskId: string): Promise<ApiResult> {
|
||||
return this.request('/api/scheduler/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ task_id: taskId }),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Voice
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async voiceAsr(audio: File | Blob): Promise<{ status: string; text?: string; audio_url?: string; message?: string }> {
|
||||
const formData = new FormData()
|
||||
formData.append('file', audio, 'recording.webm')
|
||||
const res = await fetch(`${this.baseUrl}/api/voice/asr`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include',
|
||||
})
|
||||
return res.json()
|
||||
}
|
||||
|
||||
async voiceTts(text: string, sessionId?: string): Promise<{ status: string; audio_url?: string; message?: string }> {
|
||||
return this.request('/api/voice/tts', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ text, session_id: sessionId }),
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Logs / version
|
||||
// ---------------------------------------------------------
|
||||
|
||||
createLogStream(): EventSource {
|
||||
return new EventSource(`${this.baseUrl}/api/logs`)
|
||||
}
|
||||
|
||||
getFileUrl(previewUrl: string): string {
|
||||
return `${this.baseUrl}${previewUrl}`
|
||||
async getVersion(): Promise<string> {
|
||||
const data = await this.request<{ version: string }>('/api/version')
|
||||
return data.version
|
||||
}
|
||||
}
|
||||
|
||||
interface ChatMessage {
|
||||
role: string
|
||||
content: string
|
||||
timestamp: number
|
||||
// ---------------------------------------------------------
|
||||
// Auth (web_password) — placeholder for future use
|
||||
// ---------------------------------------------------------
|
||||
|
||||
async authCheck(): Promise<{ status: string; auth_required: boolean; authenticated?: boolean }> {
|
||||
return this.request('/auth/check')
|
||||
}
|
||||
|
||||
async authLogin(password: string): Promise<ApiResult> {
|
||||
return this.request('/auth/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ password }),
|
||||
})
|
||||
}
|
||||
|
||||
async authLogout(): Promise<ApiResult> {
|
||||
return this.request('/auth/logout', { method: 'POST' })
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient()
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ============================================================
|
||||
// Electron bridge
|
||||
// ============================================================
|
||||
|
||||
export interface ElectronAPI {
|
||||
getBackendPort: () => Promise<number | null>
|
||||
getBackendStatus: () => Promise<string>
|
||||
@@ -6,6 +10,11 @@ export interface ElectronAPI {
|
||||
selectFile: (filters?: { name: string; extensions: string[] }[]) => Promise<string | null>
|
||||
onBackendStatus: (callback: (data: BackendStatusEvent) => void) => void
|
||||
onBackendLog: (callback: (line: string) => void) => void
|
||||
windowMinimize: () => Promise<void>
|
||||
windowMaximize: () => Promise<boolean>
|
||||
windowClose: () => Promise<void>
|
||||
windowIsMaximized: () => Promise<boolean>
|
||||
onMaximizeChange: (callback: (maximized: boolean) => void) => void
|
||||
platform: string
|
||||
}
|
||||
|
||||
@@ -15,32 +24,166 @@ export interface BackendStatusEvent {
|
||||
error?: string
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Chat / messages / streaming
|
||||
// ============================================================
|
||||
|
||||
export type Role = 'user' | 'assistant'
|
||||
|
||||
/** A single ordered step inside an assistant turn (matches backend history). */
|
||||
export interface MessageStep {
|
||||
type: 'thinking' | 'content' | 'tool'
|
||||
content?: string
|
||||
// tool step fields
|
||||
id?: string
|
||||
name?: string
|
||||
arguments?: Record<string, unknown>
|
||||
result?: string
|
||||
is_error?: boolean
|
||||
status?: string
|
||||
execution_time?: number
|
||||
}
|
||||
|
||||
/** Local UI message model (superset of backend history message). */
|
||||
export interface ChatMessage {
|
||||
id: string
|
||||
role: 'user' | 'assistant'
|
||||
role: Role
|
||||
content: string
|
||||
/** Unix seconds. Backend history uses `created_at`; we normalize to `timestamp`. */
|
||||
timestamp: number
|
||||
attachments?: Attachment[]
|
||||
/** Ordered steps (thinking / content / tool). Preferred over legacy toolCalls. */
|
||||
steps?: MessageStep[]
|
||||
/** Legacy live-stream tool events (kept for backward compat during streaming). */
|
||||
toolCalls?: ToolCall[]
|
||||
/** Reasoning text streamed via `reasoning` SSE events. */
|
||||
reasoning?: string
|
||||
/** Sequence numbers from backend (for delete/regenerate). */
|
||||
userSeq?: number
|
||||
botSeq?: number
|
||||
/** Self-evolution bubble flag. */
|
||||
kind?: 'evolution'
|
||||
extras?: Record<string, unknown>
|
||||
isStreaming?: boolean
|
||||
isCancelled?: boolean
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface Attachment {
|
||||
file_path: string
|
||||
file_name: string
|
||||
file_type: 'image' | 'video' | 'file'
|
||||
file_type: 'image' | 'video' | 'file' | 'directory'
|
||||
preview_url?: string
|
||||
}
|
||||
|
||||
/** Live tool event during SSE streaming. */
|
||||
export interface ToolCall {
|
||||
type: 'tool_start' | 'tool_end'
|
||||
type: 'tool_start' | 'tool_end' | 'tool_progress'
|
||||
tool: string
|
||||
tool_call_id?: string
|
||||
arguments?: Record<string, unknown>
|
||||
result?: string
|
||||
status?: string
|
||||
execution_time?: number
|
||||
}
|
||||
|
||||
/** All SSE event types emitted on /stream. */
|
||||
export type StreamEventType =
|
||||
| 'delta'
|
||||
| 'reasoning'
|
||||
| 'tool_start'
|
||||
| 'tool_progress'
|
||||
| 'tool_end'
|
||||
| 'message_end'
|
||||
| 'phase'
|
||||
| 'file_to_send'
|
||||
| 'image'
|
||||
| 'video'
|
||||
| 'file'
|
||||
| 'text'
|
||||
| 'done'
|
||||
| 'cancelled'
|
||||
| 'voice_attach'
|
||||
| 'error'
|
||||
|
||||
export interface StreamEvent {
|
||||
type: StreamEventType
|
||||
content?: string
|
||||
tool?: string
|
||||
tool_call_id?: string
|
||||
arguments?: Record<string, unknown>
|
||||
status?: string
|
||||
result?: string
|
||||
execution_time?: number
|
||||
has_tool_calls?: boolean
|
||||
path?: string
|
||||
file_name?: string
|
||||
file_type?: string
|
||||
web_url?: string
|
||||
audio_url?: string
|
||||
request_id?: string
|
||||
timestamp?: number
|
||||
user_seq?: number
|
||||
bot_seq?: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Sessions / history
|
||||
// ============================================================
|
||||
|
||||
export interface SessionItem {
|
||||
session_id: string
|
||||
title: string
|
||||
created_at: number
|
||||
last_active: number
|
||||
msg_count: number
|
||||
}
|
||||
|
||||
export interface SessionsPage {
|
||||
sessions: SessionItem[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
has_more: boolean
|
||||
}
|
||||
|
||||
/** Backend history message (as returned by /api/history). */
|
||||
export interface HistoryMessage {
|
||||
role: Role
|
||||
content: string
|
||||
created_at: number
|
||||
steps?: MessageStep[]
|
||||
tool_calls?: Array<{ id?: string; name: string; arguments?: Record<string, unknown>; result?: string }>
|
||||
reasoning?: string
|
||||
kind?: 'evolution'
|
||||
extras?: Record<string, unknown>
|
||||
/** Per-message sequence number used by delete/regenerate APIs. */
|
||||
_seq?: number
|
||||
}
|
||||
|
||||
export interface HistoryPage {
|
||||
messages: HistoryMessage[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
has_more: boolean
|
||||
context_start_seq?: number
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Config
|
||||
// ============================================================
|
||||
|
||||
export interface ProviderMeta {
|
||||
label: string
|
||||
models: string[]
|
||||
api_base_key?: string
|
||||
api_base_default?: string
|
||||
api_key_field?: string
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
export interface ConfigData {
|
||||
use_agent: boolean
|
||||
title: string
|
||||
@@ -51,54 +194,190 @@ export interface ConfigData {
|
||||
agent_max_context_tokens: number
|
||||
agent_max_context_turns: number
|
||||
agent_max_steps: number
|
||||
enable_thinking?: boolean
|
||||
self_evolution_enabled?: boolean
|
||||
api_bases: Record<string, string>
|
||||
api_keys: Record<string, string>
|
||||
providers: Record<string, unknown>
|
||||
providers: Record<string, ProviderMeta>
|
||||
web_password_masked?: string
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Models console (/api/models)
|
||||
// ============================================================
|
||||
|
||||
export interface ModelProvider {
|
||||
id: string
|
||||
label: string
|
||||
configured: boolean
|
||||
is_custom: boolean
|
||||
custom_id?: string
|
||||
active?: boolean
|
||||
api_key_masked?: string
|
||||
api_base?: string
|
||||
models: string[]
|
||||
}
|
||||
|
||||
export type CapabilityKey = 'chat' | 'vision' | 'asr' | 'tts' | 'embedding' | 'image' | 'search'
|
||||
|
||||
export interface CapabilityState {
|
||||
current_provider?: string
|
||||
current_model?: string
|
||||
providers?: string[]
|
||||
provider_models?: Record<string, string[]>
|
||||
strategy?: string
|
||||
fallback_provider?: string
|
||||
fallback_model?: string
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
export interface ModelsData {
|
||||
providers: ModelProvider[]
|
||||
capabilities: Record<CapabilityKey, CapabilityState>
|
||||
}
|
||||
|
||||
export type ModelsAction =
|
||||
| { action: 'set_provider'; provider_id: string; api_key?: string; api_base?: string }
|
||||
| { action: 'delete_provider'; provider_id: string }
|
||||
| { action: 'set_custom_provider'; name: string; id?: string; api_base: string; api_key?: string; model?: string; make_active?: boolean }
|
||||
| { action: 'delete_custom_provider'; id: string }
|
||||
| { action: 'set_active_custom_provider'; id: string }
|
||||
| { action: 'set_capability'; capability: CapabilityKey; provider_id: string; model: string; voice?: string; strategy?: string; provider?: string }
|
||||
| { action: 'set_voice_reply_mode'; mode: 'off' | 'voice_if_voice' | 'always' }
|
||||
| { action: 'set_search_credential'; api_key: string }
|
||||
|
||||
// ============================================================
|
||||
// Channels
|
||||
// ============================================================
|
||||
|
||||
export interface ChannelField {
|
||||
key: string
|
||||
label: string
|
||||
type: 'text' | 'secret' | 'number' | 'bool'
|
||||
value?: string | number | boolean
|
||||
default?: string | number | boolean
|
||||
}
|
||||
|
||||
export interface ChannelInfo {
|
||||
name: string
|
||||
label: Record<string, string>
|
||||
label: { zh: string; en: string }
|
||||
icon: string
|
||||
color: string
|
||||
active: boolean
|
||||
fields: ChannelField[]
|
||||
login_status?: string
|
||||
}
|
||||
|
||||
export interface ChannelField {
|
||||
key: string
|
||||
label: Record<string, string>
|
||||
type: string
|
||||
required?: boolean
|
||||
placeholder?: Record<string, string>
|
||||
export type ChannelAction = 'save' | 'connect' | 'disconnect'
|
||||
|
||||
// ============================================================
|
||||
// Tools / skills
|
||||
// ============================================================
|
||||
|
||||
export interface ToolInfo {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface SkillInfo {
|
||||
name: string
|
||||
display_name: string
|
||||
description: string
|
||||
source?: string
|
||||
enabled: boolean
|
||||
category?: string
|
||||
}
|
||||
|
||||
export interface ToolInfo {
|
||||
name: string
|
||||
display_name: string
|
||||
description: string
|
||||
}
|
||||
// ============================================================
|
||||
// Memory
|
||||
// ============================================================
|
||||
|
||||
export type MemoryCategory = 'memory' | 'dream' | 'evolution'
|
||||
|
||||
export interface MemoryItem {
|
||||
filename: string
|
||||
modified: number
|
||||
type: string // global | daily | dream | evolution
|
||||
size: number
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface MemoryPage {
|
||||
list: MemoryItem[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Knowledge
|
||||
// ============================================================
|
||||
|
||||
export interface KnowledgeNode {
|
||||
name: string
|
||||
path: string
|
||||
type: 'category' | 'file'
|
||||
children?: KnowledgeNode[]
|
||||
count?: number
|
||||
}
|
||||
|
||||
export interface KnowledgeList {
|
||||
root_files?: KnowledgeNode[]
|
||||
tree: KnowledgeNode[]
|
||||
stats: { pages: number; size: number }
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface KnowledgeGraph {
|
||||
nodes: Array<{ id: string; label: string; category?: string }>
|
||||
links: Array<{ source: string; target: string }>
|
||||
}
|
||||
|
||||
export type KnowledgeAction =
|
||||
| { action: 'create_category'; payload: { path: string } }
|
||||
| { action: 'rename_category'; payload: { path: string; new_path: string } }
|
||||
| { action: 'delete_category'; payload: { path: string; confirm?: boolean } }
|
||||
| { action: 'delete_documents'; payload: { paths: string[] } }
|
||||
| { action: 'move_documents'; payload: { paths: string[]; target_category: string } }
|
||||
|
||||
// ============================================================
|
||||
// Scheduler
|
||||
// ============================================================
|
||||
|
||||
export interface TaskSchedule {
|
||||
type: 'cron' | 'interval' | 'once'
|
||||
expression?: string
|
||||
seconds?: number
|
||||
run_at?: string
|
||||
}
|
||||
|
||||
export interface TaskAction {
|
||||
type: 'send_message' | 'agent_task'
|
||||
content?: string
|
||||
task_description?: string
|
||||
receiver?: string
|
||||
receiver_name?: string
|
||||
is_group?: boolean
|
||||
channel_type?: string
|
||||
}
|
||||
|
||||
export interface SchedulerTask {
|
||||
id: string
|
||||
name: string
|
||||
cron: string
|
||||
enabled: boolean
|
||||
last_run?: string
|
||||
next_run?: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
schedule: TaskSchedule
|
||||
action: TaskAction
|
||||
next_run_at?: string
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Logs
|
||||
// ============================================================
|
||||
|
||||
export interface LogEvent {
|
||||
type: 'init' | 'line' | 'error'
|
||||
content?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
Reference in New Issue
Block a user