feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type {
|
||||
SearchProvider,
|
||||
McpServer,
|
||||
KnowledgeBase,
|
||||
MemoryNamespace,
|
||||
Artifact,
|
||||
BackupManifest,
|
||||
ContextSource,
|
||||
ConversationBranch,
|
||||
ConversationWorkspaceSnapshot,
|
||||
ProgramPolicy,
|
||||
GatewayDiagnostic,
|
||||
GatewayTemplate,
|
||||
DesktopCapability,
|
||||
} from '@/types';
|
||||
|
||||
describe('Phase-2 type contracts', () => {
|
||||
it('SearchProvider has required fields', () => {
|
||||
const sp: SearchProvider = {
|
||||
id: 'sp1',
|
||||
name: 'Tavily',
|
||||
providerType: 'tavily',
|
||||
hasApiKey: false,
|
||||
enabled: true,
|
||||
resultLimit: 10,
|
||||
timeoutMs: 5000,
|
||||
};
|
||||
expect(sp.id).toBe('sp1');
|
||||
expect(sp.providerType).toBe('tavily');
|
||||
});
|
||||
|
||||
it('McpServer has required fields', () => {
|
||||
const ms: McpServer = {
|
||||
id: 'ms1',
|
||||
name: 'Local MCP',
|
||||
transport: 'stdio',
|
||||
enabled: true,
|
||||
permissionPolicy: 'ask',
|
||||
source: 'custom',
|
||||
};
|
||||
expect(ms.transport).toBe('stdio');
|
||||
});
|
||||
|
||||
it('KnowledgeBase has required fields', () => {
|
||||
const kb: KnowledgeBase = {
|
||||
id: 'kb1',
|
||||
name: 'Test KB',
|
||||
enabled: true,
|
||||
sortOrder: 0,
|
||||
};
|
||||
expect(kb.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it('MemoryNamespace has required fields', () => {
|
||||
const mn: MemoryNamespace = {
|
||||
id: 'mn1',
|
||||
name: 'Global',
|
||||
scope: 'global',
|
||||
sortOrder: 0,
|
||||
};
|
||||
expect(mn.scope).toBe('global');
|
||||
});
|
||||
|
||||
it('Artifact has required fields', () => {
|
||||
const a: Artifact = {
|
||||
id: 'a1',
|
||||
conversationId: 'c1',
|
||||
kind: 'draft',
|
||||
title: 'Test',
|
||||
content: 'content',
|
||||
format: 'markdown',
|
||||
pinned: false,
|
||||
updatedAt: '2025-01-01',
|
||||
};
|
||||
expect(a.kind).toBe('draft');
|
||||
});
|
||||
|
||||
it('BackupManifest has required fields', () => {
|
||||
const bm: BackupManifest = {
|
||||
id: 'bm1',
|
||||
version: '1.0',
|
||||
createdAt: '2025-01-01',
|
||||
encrypted: false,
|
||||
checksum: 'abc123',
|
||||
objectCountsJson: '{}',
|
||||
sourceAppVersion: '2.0',
|
||||
filePath: '/path/to/backup.db',
|
||||
fileSize: 1024,
|
||||
};
|
||||
expect(bm.encrypted).toBe(false);
|
||||
});
|
||||
|
||||
it('ConversationWorkspaceSnapshot has required fields', () => {
|
||||
const ws: ConversationWorkspaceSnapshot = {
|
||||
searchPolicy: { enabled: false, queryMode: 'manual', resultLimit: 10 },
|
||||
toolBinding: { serverIds: [], approvalMode: 'ask' },
|
||||
knowledgeBinding: { knowledgeBaseIds: [], autoAttach: false },
|
||||
memoryPolicy: { enabled: false, writeBack: false },
|
||||
toggles: {
|
||||
searchEnabled: false,
|
||||
enabledKnowledgeBaseIds: [],
|
||||
enabledMcpServerIds: [],
|
||||
memoryEnabled: false,
|
||||
memoryWriteBack: false,
|
||||
},
|
||||
researchMode: false,
|
||||
pinnedArtifactIds: [],
|
||||
};
|
||||
expect(ws.researchMode).toBe(false);
|
||||
});
|
||||
|
||||
it('ProgramPolicy has required fields', () => {
|
||||
const pp: ProgramPolicy = {
|
||||
id: 'pp1',
|
||||
programName: 'cursor',
|
||||
allowedProviderIds: [],
|
||||
allowedModelIds: [],
|
||||
};
|
||||
expect(pp.programName).toBe('cursor');
|
||||
});
|
||||
|
||||
it('GatewayDiagnostic has required fields', () => {
|
||||
const gd: GatewayDiagnostic = {
|
||||
id: 'gd1',
|
||||
category: 'provider_latency',
|
||||
status: 'ok',
|
||||
message: 'All good',
|
||||
createdAt: '2025-01-01',
|
||||
};
|
||||
expect(gd.status).toBe('ok');
|
||||
});
|
||||
|
||||
it('GatewayTemplate has required fields', () => {
|
||||
const gt: GatewayTemplate = {
|
||||
id: 'gt1',
|
||||
name: 'Cursor',
|
||||
target: 'cursor',
|
||||
format: 'json',
|
||||
content: '{}',
|
||||
};
|
||||
expect(gt.target).toBe('cursor');
|
||||
});
|
||||
|
||||
it('DesktopCapability has required fields', () => {
|
||||
const dc: DesktopCapability = {
|
||||
key: 'tray',
|
||||
supported: true,
|
||||
};
|
||||
expect(dc.supported).toBe(true);
|
||||
});
|
||||
|
||||
it('ContextSource has required fields', () => {
|
||||
const cs: ContextSource = {
|
||||
id: 'cs1',
|
||||
conversationId: 'c1',
|
||||
type: 'search',
|
||||
refId: 'ref1',
|
||||
title: 'Search result',
|
||||
enabled: true,
|
||||
};
|
||||
expect(cs.type).toBe('search');
|
||||
});
|
||||
|
||||
it('ConversationBranch has required fields', () => {
|
||||
const cb: ConversationBranch = {
|
||||
id: 'cb1',
|
||||
conversationId: 'c1',
|
||||
parentMessageId: 'm1',
|
||||
branchLabel: 'Branch 1',
|
||||
branchIndex: 0,
|
||||
createdAt: '2025-01-01',
|
||||
};
|
||||
expect(cb.branchIndex).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
export type AgentPermissionMode = 'default' | 'accept_edits' | 'full_access';
|
||||
export type AgentRuntimeStatus = 'idle' | 'running' | 'waiting_approval' | 'completed' | 'error';
|
||||
export type ApprovalStatus = 'pending' | 'approved' | 'denied';
|
||||
|
||||
export interface AgentSession {
|
||||
id: string;
|
||||
conversation_id: string;
|
||||
cwd?: string;
|
||||
permission_mode: AgentPermissionMode;
|
||||
runtime_status: AgentRuntimeStatus;
|
||||
total_tokens: number;
|
||||
total_cost_usd: number;
|
||||
}
|
||||
|
||||
// --- Event payload types (all tool-related events carry assistantMessageId anchor) ---
|
||||
|
||||
export interface ToolUseEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
toolUseId: string;
|
||||
toolName: string;
|
||||
input: Record<string, unknown>;
|
||||
executionId?: string;
|
||||
}
|
||||
|
||||
export interface ToolStartEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
toolUseId: string;
|
||||
toolName: string;
|
||||
input: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ToolResultEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
toolUseId: string;
|
||||
toolName: string;
|
||||
content: string;
|
||||
isError: boolean;
|
||||
}
|
||||
|
||||
export interface PermissionRequestEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
toolUseId: string;
|
||||
toolName: string;
|
||||
input: Record<string, unknown>;
|
||||
riskLevel: 'read_only' | 'write' | 'execute';
|
||||
}
|
||||
|
||||
export interface AskUserEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
askId: string;
|
||||
question: string;
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
export interface AgentDoneEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
text: string;
|
||||
usage?: { input_tokens: number; output_tokens: number };
|
||||
numTurns?: number;
|
||||
costUsd?: number;
|
||||
}
|
||||
|
||||
export interface AgentErrorEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId?: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface AgentCancelledEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId?: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface AgentStatusEvent {
|
||||
conversationId: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface AgentRateLimitEvent {
|
||||
conversationId: string;
|
||||
retryAfterMs: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface AgentStreamTextEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface AgentStreamThinkingEvent {
|
||||
conversationId: string;
|
||||
assistantMessageId: string;
|
||||
thinking: string;
|
||||
}
|
||||
|
||||
// --- Frontend runtime state ---
|
||||
|
||||
export interface ToolCallState {
|
||||
toolUseId: string;
|
||||
toolName: string;
|
||||
input: Record<string, unknown>;
|
||||
assistantMessageId: string;
|
||||
executionStatus: 'queued' | 'running' | 'success' | 'failed' | 'cancelled';
|
||||
approvalStatus?: ApprovalStatus;
|
||||
output?: string;
|
||||
isError?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
export type ArtifactKind = 'draft' | 'note' | 'report' | 'snippet' | 'checklist';
|
||||
export type ArtifactFormat = 'markdown' | 'text' | 'json';
|
||||
|
||||
export type Artifact = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
kind: ArtifactKind;
|
||||
title: string;
|
||||
content: string;
|
||||
format: ArtifactFormat;
|
||||
pinned: boolean;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type CreateArtifactInput = {
|
||||
conversationId: string;
|
||||
sourceMessageId?: string;
|
||||
kind: ArtifactKind;
|
||||
title: string;
|
||||
content: string;
|
||||
format: ArtifactFormat;
|
||||
};
|
||||
|
||||
export type UpdateArtifactInput = {
|
||||
title?: string;
|
||||
content?: string;
|
||||
format?: ArtifactFormat;
|
||||
pinned?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,213 @@
|
||||
export type BackupJobKind = 'backup' | 'restore' | 'indexing';
|
||||
export type BackupJobStatus = 'pending' | 'running' | 'success' | 'failed' | 'cancelled';
|
||||
export type BackupTargetKind = 'local' | 'webdav' | 's3';
|
||||
|
||||
export type WebDavConfig = {
|
||||
host: string;
|
||||
username: string;
|
||||
password: string;
|
||||
path: string;
|
||||
acceptInvalidCerts: boolean;
|
||||
};
|
||||
|
||||
export type WebDavFileInfo = {
|
||||
fileName: string;
|
||||
size: number;
|
||||
lastModified: string;
|
||||
hostname: string;
|
||||
};
|
||||
|
||||
export type S3Config = {
|
||||
bucket: string;
|
||||
region: string;
|
||||
prefix: string;
|
||||
endpointUrl: string | null;
|
||||
forcePathStyle: boolean;
|
||||
useDefaultCredentials: boolean;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
sessionToken: string | null;
|
||||
};
|
||||
|
||||
export type S3FileInfo = {
|
||||
fileName: string;
|
||||
size: number;
|
||||
lastModified: string;
|
||||
hostname: string;
|
||||
};
|
||||
|
||||
export type BackupManifest = {
|
||||
id: string;
|
||||
version: string;
|
||||
createdAt: string;
|
||||
encrypted: boolean;
|
||||
checksum: string;
|
||||
objectCountsJson: string;
|
||||
sourceAppVersion: string;
|
||||
filePath: string | null;
|
||||
fileSize: number;
|
||||
};
|
||||
|
||||
export type AutoBackupSettings = {
|
||||
enabled: boolean;
|
||||
intervalHours: number;
|
||||
maxCount: number;
|
||||
backupDir: string | null;
|
||||
};
|
||||
|
||||
export type BackupJob = {
|
||||
id: string;
|
||||
kind: BackupJobKind;
|
||||
status: BackupJobStatus;
|
||||
progress: number;
|
||||
message?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type BackupTarget = {
|
||||
kind: BackupTargetKind;
|
||||
configJson: string;
|
||||
};
|
||||
|
||||
export type CreateBackupJobInput = {
|
||||
target: BackupTarget;
|
||||
includeAttachments: boolean;
|
||||
includeKnowledgeFiles: boolean;
|
||||
includeGatewayConfig: boolean;
|
||||
passphrase?: string;
|
||||
};
|
||||
|
||||
export type ProgramPolicy = {
|
||||
id: string;
|
||||
programName: string;
|
||||
allowedProviderIds: string[];
|
||||
allowedModelIds: string[];
|
||||
defaultProviderId?: string;
|
||||
defaultModelId?: string;
|
||||
rateLimitPerMinute?: number;
|
||||
};
|
||||
|
||||
export type GatewayDiagnosticCategory = 'provider_latency' | 'provider_error' | 'proxy' | 'auth' | 'port';
|
||||
export type GatewayDiagnosticStatus = 'ok' | 'warning' | 'error';
|
||||
|
||||
export type GatewayDiagnostic = {
|
||||
id: string;
|
||||
category: GatewayDiagnosticCategory;
|
||||
status: GatewayDiagnosticStatus;
|
||||
message: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type GatewayRequestLog = {
|
||||
id: string;
|
||||
keyId: string;
|
||||
keyName: string;
|
||||
method: string;
|
||||
path: string;
|
||||
model: string | null;
|
||||
providerId: string | null;
|
||||
statusCode: number;
|
||||
durationMs: number;
|
||||
requestTokens: number;
|
||||
responseTokens: number;
|
||||
errorMessage: string | null;
|
||||
createdAt: number;
|
||||
};
|
||||
|
||||
export type GatewayTemplateTarget = 'cursor' | 'vscode' | 'claude_code' | 'openai_compatible';
|
||||
export type GatewayTemplateFormat = 'json' | 'yaml' | 'markdown';
|
||||
|
||||
export type GatewayTemplate = {
|
||||
id: string;
|
||||
name: string;
|
||||
target: GatewayTemplateTarget;
|
||||
format: GatewayTemplateFormat;
|
||||
content: string;
|
||||
copyHint?: string;
|
||||
};
|
||||
|
||||
// CLI Tool Integration
|
||||
export type CliToolStatus = 'not_installed' | 'not_connected' | 'connected';
|
||||
export type QuickConnectProtocol = 'http' | 'https';
|
||||
|
||||
export type CliToolInfo = {
|
||||
id: string;
|
||||
name: string;
|
||||
status: CliToolStatus;
|
||||
version: string | null;
|
||||
configPath: string | null;
|
||||
hasBackup: boolean;
|
||||
connectedProtocol: QuickConnectProtocol | null;
|
||||
};
|
||||
|
||||
export type CodexSessionVisibilityRepairResult = {
|
||||
targetProvider: string;
|
||||
changedSessionFiles: number;
|
||||
skippedLockedSessionFiles: number;
|
||||
sqliteRowsUpdated: number;
|
||||
sqliteProviderRowsUpdated: number;
|
||||
sqliteUserEventRowsUpdated: number;
|
||||
sqliteCwdRowsUpdated: number;
|
||||
sqlitePresent: boolean;
|
||||
updatedWorkspaceRoots: number;
|
||||
backupDir: string | null;
|
||||
encryptedContentWarning: string | null;
|
||||
};
|
||||
|
||||
export type CodexSessionVisibilityStatusRow = {
|
||||
scope: string;
|
||||
provider: string | null;
|
||||
count: number;
|
||||
mismatchedCount: number;
|
||||
status: 'ok' | 'needs_repair' | string;
|
||||
};
|
||||
|
||||
export type CodexSessionVisibilityStatus = {
|
||||
targetProvider: string;
|
||||
codexHome: string;
|
||||
totalSessionFiles: number;
|
||||
mismatchedSessionFiles: number;
|
||||
sqlitePresent: boolean;
|
||||
sqliteRows: number;
|
||||
sqliteMismatchedRows: number;
|
||||
sqliteUserEventRowsNeedingRepair: number;
|
||||
sqliteCwdRowsNeedingRepair: number;
|
||||
workspaceRootsNeedingUpdate: number;
|
||||
statusRows: CodexSessionVisibilityStatusRow[];
|
||||
encryptedContentWarning: string | null;
|
||||
};
|
||||
|
||||
export type DesktopCapabilityKey = 'tray' | 'global_shortcut' | 'protocol_handler' | 'mini_window' | 'artifact_window' | 'notification' | 'devtools_context_menu';
|
||||
|
||||
export type DesktopCapability = {
|
||||
key: DesktopCapabilityKey;
|
||||
supported: boolean;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
export type TrayAction = 'show_main' | 'open_mini_window' | 'resume_voice_call' | 'run_quick_backup' | 'quit';
|
||||
|
||||
export type ProtocolLaunchPayload = {
|
||||
source: 'browser' | 'os_protocol';
|
||||
route: 'chat' | 'gateway' | 'settings';
|
||||
query?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type WindowStateSnapshot = {
|
||||
windowKey: 'main' | 'mini' | 'voice' | 'artifact';
|
||||
width: number;
|
||||
height: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
maximized: boolean;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
export type DesktopNotification = {
|
||||
id: string;
|
||||
level: 'info' | 'success' | 'warning' | 'error';
|
||||
title: string;
|
||||
body: string;
|
||||
actionLabel?: string;
|
||||
};
|
||||
@@ -0,0 +1,846 @@
|
||||
// === Provider System ===
|
||||
export type ProviderType =
|
||||
| 'openai'
|
||||
| 'openai_responses'
|
||||
| 'deepseek'
|
||||
| 'xai'
|
||||
| 'glm'
|
||||
| 'siliconflow'
|
||||
| 'anthropic'
|
||||
| 'gemini'
|
||||
| 'jina'
|
||||
| 'cohere'
|
||||
| 'voyage'
|
||||
| 'custom';
|
||||
|
||||
export interface ProviderConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
provider_type: ProviderType;
|
||||
api_host: string;
|
||||
api_path: string | null;
|
||||
enabled: boolean;
|
||||
models: Model[];
|
||||
keys: ProviderKey[];
|
||||
proxy_config: ProviderProxyConfig | null;
|
||||
custom_headers: string | null;
|
||||
icon: string | null;
|
||||
builtin_id: string | null;
|
||||
sort_order: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
export interface ProviderKey {
|
||||
id: string;
|
||||
provider_id: string;
|
||||
key_encrypted: string;
|
||||
key_prefix: string;
|
||||
enabled: boolean;
|
||||
last_validated_at: number | null;
|
||||
last_error: string | null;
|
||||
rotation_index: number;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
export interface ProviderProxyConfig {
|
||||
proxy_type: string | null;
|
||||
proxy_address: string | null;
|
||||
proxy_port: number | null;
|
||||
}
|
||||
|
||||
export interface CreateProviderInput {
|
||||
name: string;
|
||||
provider_type: ProviderType;
|
||||
api_host: string;
|
||||
api_path?: string | null;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateProviderInput {
|
||||
name?: string;
|
||||
provider_type?: ProviderType;
|
||||
api_host?: string;
|
||||
api_path?: string | null;
|
||||
enabled?: boolean;
|
||||
proxy_config?: ProviderProxyConfig;
|
||||
custom_headers?: string | null;
|
||||
icon?: string | null;
|
||||
sort_order?: number;
|
||||
}
|
||||
|
||||
export interface DeepLinkProviderImportInput {
|
||||
name: string;
|
||||
baseurl: string;
|
||||
apikey: string;
|
||||
type: ProviderType;
|
||||
}
|
||||
|
||||
export interface DeepLinkProviderImportResult {
|
||||
provider_id: string;
|
||||
provider_name: string;
|
||||
created_provider: boolean;
|
||||
added_key: boolean;
|
||||
reused_key: boolean;
|
||||
}
|
||||
|
||||
export type ProviderImportStatus = 'ready' | 'add_key' | 'already_exists' | 'unsupported';
|
||||
|
||||
export interface ProviderImportCandidate {
|
||||
id: string;
|
||||
source_app: string;
|
||||
name: string;
|
||||
provider_type: ProviderType;
|
||||
api_host: string;
|
||||
api_path: string | null;
|
||||
key_prefix: string;
|
||||
models: string[];
|
||||
status: ProviderImportStatus;
|
||||
reason: string | null;
|
||||
}
|
||||
|
||||
export interface ProviderImportBatchResult {
|
||||
created_count: number;
|
||||
added_key_count: number;
|
||||
reused_count: number;
|
||||
skipped_count: number;
|
||||
provider_ids: string[];
|
||||
}
|
||||
|
||||
export interface ThirdPartyImportWarning {
|
||||
code: string;
|
||||
message: string;
|
||||
sourceId: string | null;
|
||||
}
|
||||
|
||||
export interface ThirdPartyImportSummary {
|
||||
conversationCount: number;
|
||||
messageCount: number;
|
||||
fileCount: number;
|
||||
importableProviderCount: number;
|
||||
skippedEmptyTopicCount: number;
|
||||
duplicateConversationCount: number;
|
||||
warnings: ThirdPartyImportWarning[];
|
||||
}
|
||||
|
||||
export interface ThirdPartyImportOptions {
|
||||
importProviderKeys: boolean;
|
||||
}
|
||||
|
||||
export interface ThirdPartyImportResult {
|
||||
importedConversationCount: number;
|
||||
importedMessageCount: number;
|
||||
importedFileCount: number;
|
||||
importedProviderCount: number;
|
||||
skippedDuplicateConversationCount: number;
|
||||
warnings: ThirdPartyImportWarning[];
|
||||
}
|
||||
|
||||
export type CherryStudioImportWarning = ThirdPartyImportWarning;
|
||||
export type CherryStudioImportSummary = ThirdPartyImportSummary;
|
||||
export type CherryStudioImportOptions = ThirdPartyImportOptions;
|
||||
export type CherryStudioImportResult = ThirdPartyImportResult;
|
||||
|
||||
export interface ChatGptImportWarning {
|
||||
code: string;
|
||||
message: string;
|
||||
sourceId: string | null;
|
||||
}
|
||||
|
||||
export interface ChatGptImportSummary {
|
||||
conversationCount: number;
|
||||
messageCount: number;
|
||||
skippedEmptyConversationCount: number;
|
||||
duplicateConversationCount: number;
|
||||
warnings: ChatGptImportWarning[];
|
||||
}
|
||||
|
||||
export interface ChatGptImportResult {
|
||||
importedConversationCount: number;
|
||||
importedMessageCount: number;
|
||||
skippedDuplicateConversationCount: number;
|
||||
warnings: ChatGptImportWarning[];
|
||||
}
|
||||
|
||||
// === Model System ===
|
||||
export type ModelCapability = 'TextChat' | 'Vision' | 'FunctionCalling' | 'Reasoning' | 'RealtimeVoice';
|
||||
export type ModelType = 'Chat' | 'Voice' | 'Embedding' | 'Image' | 'Rerank';
|
||||
|
||||
export interface Model {
|
||||
provider_id: string;
|
||||
model_id: string;
|
||||
name: string;
|
||||
group_name?: string | null;
|
||||
model_type: ModelType;
|
||||
capabilities: ModelCapability[];
|
||||
max_tokens: number | null;
|
||||
enabled: boolean;
|
||||
param_overrides: ModelParamOverrides | null;
|
||||
}
|
||||
|
||||
export interface ModelParamOverrides {
|
||||
temperature?: number;
|
||||
max_tokens?: number;
|
||||
top_p?: number;
|
||||
frequency_penalty?: number;
|
||||
use_max_completion_tokens?: boolean;
|
||||
no_system_role?: boolean;
|
||||
force_max_tokens?: boolean;
|
||||
thinking_param_style?: string;
|
||||
reasoning_profile?: string;
|
||||
reasoning_options?: string[];
|
||||
reasoning_default?: string;
|
||||
extra_body?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// === Conversation & Message ===
|
||||
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
||||
|
||||
export interface ConversationCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
icon_type: string | null;
|
||||
icon_value: string | null;
|
||||
system_prompt: string | null;
|
||||
default_provider_id: string | null;
|
||||
default_model_id: string | null;
|
||||
default_temperature: number | null;
|
||||
default_max_tokens: number | null;
|
||||
default_top_p: number | null;
|
||||
default_frequency_penalty: number | null;
|
||||
sort_order: number;
|
||||
is_collapsed: boolean;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
export interface Conversation {
|
||||
id: string;
|
||||
title: string;
|
||||
model_id: string;
|
||||
provider_id: string;
|
||||
system_prompt: string | null;
|
||||
temperature: number | null;
|
||||
max_tokens: number | null;
|
||||
top_p: number | null;
|
||||
frequency_penalty: number | null;
|
||||
search_enabled: boolean;
|
||||
search_provider_id: string | null;
|
||||
thinking_budget: number | null;
|
||||
thinking_level?: string | null;
|
||||
enabled_mcp_server_ids: string[];
|
||||
enabled_knowledge_base_ids: string[];
|
||||
enabled_memory_namespace_ids: string[];
|
||||
is_pinned: boolean;
|
||||
is_archived: boolean;
|
||||
context_compression: boolean;
|
||||
category_id: string | null;
|
||||
parent_conversation_id: string | null;
|
||||
mode?: 'chat' | 'agent';
|
||||
message_count: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
export interface ToolCall {
|
||||
id: string;
|
||||
type: string;
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
id: string;
|
||||
conversation_id: string;
|
||||
role: MessageRole;
|
||||
content: string;
|
||||
provider_id: string | null;
|
||||
model_id: string | null;
|
||||
token_count: number | null;
|
||||
prompt_tokens?: number | null;
|
||||
completion_tokens?: number | null;
|
||||
attachments: Attachment[];
|
||||
thinking: string | null;
|
||||
tool_calls_json: string | null;
|
||||
tool_call_id: string | null;
|
||||
created_at: number;
|
||||
parent_message_id: string | null;
|
||||
version_index: number;
|
||||
is_active: boolean;
|
||||
status: 'complete' | 'partial' | 'error';
|
||||
tokens_per_second?: number | null;
|
||||
first_token_latency_ms?: number | null;
|
||||
}
|
||||
|
||||
export interface MessagePage {
|
||||
messages: Message[];
|
||||
has_older: boolean;
|
||||
oldest_message_id: string | null;
|
||||
total_active_count: number;
|
||||
}
|
||||
|
||||
export interface ConversationStats {
|
||||
total_messages: number;
|
||||
total_user_messages: number;
|
||||
total_assistant_messages: number;
|
||||
total_prompt_tokens: number;
|
||||
total_completion_tokens: number;
|
||||
total_tokens: number;
|
||||
avg_tokens_per_second: number | null;
|
||||
avg_first_token_latency_ms: number | null;
|
||||
avg_response_time_ms: number | null;
|
||||
}
|
||||
|
||||
export interface Attachment {
|
||||
id: string;
|
||||
file_type: string;
|
||||
file_name: string;
|
||||
file_path: string;
|
||||
file_size: number;
|
||||
data?: string;
|
||||
}
|
||||
|
||||
export interface AttachmentInput {
|
||||
file_name: string;
|
||||
file_type: string;
|
||||
file_size: number;
|
||||
data: string;
|
||||
}
|
||||
|
||||
export interface ConversationSearchResult {
|
||||
conversation: Conversation;
|
||||
matched_message_preview: string | null;
|
||||
}
|
||||
|
||||
export interface ConversationSummary {
|
||||
id: string;
|
||||
conversation_id: string;
|
||||
summary_text: string;
|
||||
compressed_until_message_id: string | null;
|
||||
token_count: number | null;
|
||||
model_used: string | null;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
export interface CompressionEvent {
|
||||
conversation_id: string;
|
||||
marker_message: Message;
|
||||
summary: ConversationSummary;
|
||||
}
|
||||
|
||||
export interface ContextUsage {
|
||||
used_tokens: number;
|
||||
max_tokens: number | null;
|
||||
threshold_tokens: number | null;
|
||||
has_summary: boolean;
|
||||
compressed_until_message_id: string | null;
|
||||
messages_after_boundary: number;
|
||||
}
|
||||
|
||||
export interface UpdateConversationInput {
|
||||
title?: string;
|
||||
provider_id?: string;
|
||||
model_id?: string;
|
||||
is_pinned?: boolean;
|
||||
is_archived?: boolean;
|
||||
system_prompt?: string;
|
||||
temperature?: number | null;
|
||||
max_tokens?: number | null;
|
||||
top_p?: number | null;
|
||||
frequency_penalty?: number | null;
|
||||
search_enabled?: boolean;
|
||||
search_provider_id?: string | null;
|
||||
thinking_budget?: number | null;
|
||||
thinking_level?: string | null;
|
||||
enabled_mcp_server_ids?: string[];
|
||||
enabled_knowledge_base_ids?: string[];
|
||||
enabled_memory_namespace_ids?: string[];
|
||||
context_compression?: boolean;
|
||||
category_id?: string | null;
|
||||
mode?: 'chat' | 'agent';
|
||||
}
|
||||
|
||||
// === Gateway System ===
|
||||
export interface GatewayStatus {
|
||||
is_running: boolean;
|
||||
listen_address: string;
|
||||
port: number;
|
||||
ssl_enabled: boolean;
|
||||
started_at: number | null;
|
||||
/** HTTPS listener port; `null` when SSL is disabled or not yet started. */
|
||||
https_port: number | null;
|
||||
/** When `true` the gateway redirects all HTTP traffic to HTTPS. */
|
||||
force_ssl: boolean;
|
||||
}
|
||||
|
||||
export interface GatewayKey {
|
||||
id: string;
|
||||
name: string;
|
||||
key_hash: string;
|
||||
key_prefix: string;
|
||||
enabled: boolean;
|
||||
created_at: number;
|
||||
last_used_at: number | null;
|
||||
has_encrypted_key: boolean;
|
||||
}
|
||||
|
||||
export interface CreateGatewayKeyResult {
|
||||
gateway_key: GatewayKey;
|
||||
plain_key: string;
|
||||
}
|
||||
|
||||
export interface GatewayMetrics {
|
||||
total_requests: number;
|
||||
total_tokens: number;
|
||||
total_request_tokens: number;
|
||||
total_response_tokens: number;
|
||||
active_connections: number;
|
||||
today_requests: number;
|
||||
today_tokens: number;
|
||||
today_request_tokens: number;
|
||||
today_response_tokens: number;
|
||||
}
|
||||
|
||||
export interface UsageByKey {
|
||||
key_id: string;
|
||||
key_name: string;
|
||||
request_count: number;
|
||||
token_count: number;
|
||||
request_tokens: number;
|
||||
response_tokens: number;
|
||||
}
|
||||
|
||||
export interface UsageByProvider {
|
||||
provider_id: string;
|
||||
provider_name: string;
|
||||
request_count: number;
|
||||
token_count: number;
|
||||
request_tokens: number;
|
||||
response_tokens: number;
|
||||
}
|
||||
|
||||
export interface UsageByDay {
|
||||
date: string;
|
||||
request_count: number;
|
||||
token_count: number;
|
||||
request_tokens: number;
|
||||
response_tokens: number;
|
||||
}
|
||||
|
||||
export interface ConnectedProgram {
|
||||
key_id: string;
|
||||
key_name: string;
|
||||
key_prefix: string;
|
||||
today_requests: number;
|
||||
today_tokens: number;
|
||||
today_request_tokens: number;
|
||||
today_response_tokens: number;
|
||||
last_active_at: number | null;
|
||||
is_active: boolean;
|
||||
}
|
||||
|
||||
export interface GatewayStats {
|
||||
total_requests: number;
|
||||
active_connections: number;
|
||||
uptime_seconds: number;
|
||||
requests_per_minute: number;
|
||||
}
|
||||
|
||||
export interface GatewaySettings {
|
||||
listen_address: string;
|
||||
port: number;
|
||||
load_balance_strategy: 'round_robin';
|
||||
}
|
||||
|
||||
// === Settings ===
|
||||
export const DEFAULT_MCP_TOOL_LOOP_MAX_ITERATIONS = 100;
|
||||
export const DEFAULT_AGENT_WORKSPACE_NAME_STRATEGY = 'uuid';
|
||||
export const DEFAULT_AGENT_WORKSPACE_DATETIME_FORMAT = 'YYYY-MM-DD-HH-mm-ss';
|
||||
export type AgentWorkspaceNameStrategy =
|
||||
| 'uuid'
|
||||
| 'conversation_id'
|
||||
| 'created_timestamp'
|
||||
| 'created_datetime';
|
||||
|
||||
export interface AppSettings {
|
||||
language: string;
|
||||
theme_mode: string;
|
||||
primary_color: string;
|
||||
border_radius: number;
|
||||
auto_start: boolean;
|
||||
show_on_start: boolean;
|
||||
minimize_to_tray: boolean;
|
||||
font_size: number;
|
||||
font_weight: number;
|
||||
font_family: string;
|
||||
code_font_family: string;
|
||||
chat_font_size: number;
|
||||
chat_line_height: number;
|
||||
chat_font_family: string;
|
||||
chat_font_weight: number;
|
||||
bubble_style: string;
|
||||
code_theme: string;
|
||||
code_theme_light: string;
|
||||
default_provider_id: string | null;
|
||||
default_model_id: string | null;
|
||||
default_temperature: number | null;
|
||||
default_max_tokens: number | null;
|
||||
default_top_p: number | null;
|
||||
default_frequency_penalty: number | null;
|
||||
default_context_count: number | null;
|
||||
title_summary_provider_id: string | null;
|
||||
title_summary_model_id: string | null;
|
||||
title_summary_temperature: number | null;
|
||||
title_summary_max_tokens: number | null;
|
||||
title_summary_top_p: number | null;
|
||||
title_summary_frequency_penalty: number | null;
|
||||
title_summary_context_count: number | null;
|
||||
title_summary_prompt: string | null;
|
||||
compression_provider_id: string | null;
|
||||
compression_model_id: string | null;
|
||||
compression_temperature: number | null;
|
||||
compression_max_tokens: number | null;
|
||||
compression_top_p: number | null;
|
||||
compression_frequency_penalty: number | null;
|
||||
compression_prompt: string | null;
|
||||
proxy_type: string | null;
|
||||
proxy_address: string | null;
|
||||
proxy_port: number | null;
|
||||
global_shortcut: string;
|
||||
shortcut_toggle_current_window: string;
|
||||
shortcut_toggle_all_windows: string;
|
||||
shortcut_close_window: string;
|
||||
shortcut_new_conversation: string;
|
||||
shortcut_send_message: string;
|
||||
shortcut_open_settings: string;
|
||||
shortcut_toggle_model_selector: string;
|
||||
shortcut_toggle_chat_sidebar: string;
|
||||
shortcut_fill_last_message: string;
|
||||
shortcut_clear_context: string;
|
||||
shortcut_clear_conversation_messages: string;
|
||||
shortcut_toggle_gateway: string;
|
||||
shortcut_toggle_mode: string;
|
||||
gateway_auto_start: boolean;
|
||||
gateway_listen_address: string;
|
||||
gateway_port: number;
|
||||
gateway_ssl_enabled: boolean;
|
||||
gateway_ssl_mode: string;
|
||||
gateway_ssl_cert_path: string | null;
|
||||
gateway_ssl_key_path: string | null;
|
||||
gateway_ssl_port: number;
|
||||
gateway_force_ssl: boolean;
|
||||
// Desktop integration
|
||||
always_on_top?: boolean;
|
||||
tray_enabled?: boolean;
|
||||
global_shortcuts_enabled?: boolean;
|
||||
shortcut_registration_logs_enabled?: boolean;
|
||||
shortcut_trigger_toast_enabled?: boolean;
|
||||
notifications_enabled?: boolean;
|
||||
mini_window_enabled?: boolean;
|
||||
start_minimized?: boolean;
|
||||
close_to_tray?: boolean;
|
||||
release_webview_on_tray?: boolean;
|
||||
notify_backup?: boolean;
|
||||
notify_import?: boolean;
|
||||
notify_errors?: boolean;
|
||||
// WebDAV sync settings
|
||||
webdav_host?: string | null;
|
||||
webdav_username?: string | null;
|
||||
webdav_path?: string | null;
|
||||
webdav_accept_invalid_certs?: boolean;
|
||||
webdav_sync_enabled?: boolean;
|
||||
webdav_sync_interval_minutes?: number;
|
||||
webdav_max_remote_backups?: number;
|
||||
webdav_include_documents?: boolean;
|
||||
// S3 sync settings
|
||||
s3_bucket?: string | null;
|
||||
s3_region?: string | null;
|
||||
s3_endpoint?: string | null;
|
||||
s3_prefix?: string | null;
|
||||
s3_force_path_style?: boolean;
|
||||
s3_use_default_credentials?: boolean;
|
||||
s3_sync_enabled?: boolean;
|
||||
s3_sync_interval_minutes?: number;
|
||||
s3_max_remote_backups?: number;
|
||||
s3_include_documents?: boolean;
|
||||
last_selected_conversation_id?: string | null;
|
||||
/** Custom documents root override (overrides ~/Documents/boosapi/) */
|
||||
documents_root_override?: string | null;
|
||||
/** Auto update check interval in minutes (default 60, min 1) */
|
||||
update_check_interval?: number;
|
||||
/** Global system prompt fallback — used when a conversation has no custom system prompt */
|
||||
default_system_prompt?: string | null;
|
||||
/** Chat minimap / navigation overlay */
|
||||
chat_minimap_enabled?: boolean;
|
||||
chat_minimap_style?: 'faq' | 'sticky';
|
||||
/** Collapse the chat page's secondary conversation sidebar. Default: false */
|
||||
chat_sidebar_collapsed?: boolean;
|
||||
/** Inherit current conversation capability preferences when creating a new conversation. Default: true */
|
||||
inherit_conversation_preferences_on_create?: boolean;
|
||||
/** Timeout before the first chat stream packet in seconds. 0 disables. */
|
||||
chat_stream_first_packet_timeout_secs?: number;
|
||||
/** Timeout between chat stream packets in seconds. 0 disables. */
|
||||
chat_stream_idle_timeout_secs?: number;
|
||||
/** Maximum provider/tool iterations in one MCP tool loop. Default: 100. */
|
||||
mcp_tool_loop_max_iterations?: number;
|
||||
/** Parse PDF/DOC/DOCX attachments and send extracted text to the model. Default: false */
|
||||
document_attachment_reading_enabled?: boolean;
|
||||
/** Include Image models in the conversation model selector. Default: false */
|
||||
show_image_models_in_model_selector?: boolean;
|
||||
/** Multi-model response display mode */
|
||||
multi_model_display_mode?: 'tabs' | 'side-by-side' | 'stacked';
|
||||
/** Render user messages as Markdown (like AI messages). Default: false */
|
||||
render_user_markdown?: boolean;
|
||||
/** Agent default workspace root. Null uses ~/.boosapi/workspace. */
|
||||
agent_workspace_root?: string | null;
|
||||
/** Agent workspace subdirectory naming strategy. Default: uuid. */
|
||||
agent_workspace_name_strategy?: AgentWorkspaceNameStrategy;
|
||||
/** Agent workspace datetime naming format. Default: YYYY-MM-DD-HH-mm-ss. */
|
||||
agent_workspace_datetime_format?: string | null;
|
||||
}
|
||||
|
||||
// === Streaming ===
|
||||
export interface ChatStreamChunk {
|
||||
content: string | null;
|
||||
thinking: string | null;
|
||||
tool_calls: ToolCall[] | null;
|
||||
done: boolean;
|
||||
is_final?: boolean | null;
|
||||
usage: TokenUsage | null;
|
||||
}
|
||||
|
||||
export interface ChatStreamEvent {
|
||||
conversation_id: string;
|
||||
message_id: string;
|
||||
stream_id?: string | null;
|
||||
model_id?: string;
|
||||
provider_id?: string;
|
||||
chunk: ChatStreamChunk;
|
||||
}
|
||||
|
||||
export interface ChatStreamErrorEvent {
|
||||
conversation_id: string;
|
||||
message_id: string;
|
||||
stream_id?: string | null;
|
||||
model_id?: string;
|
||||
provider_id?: string;
|
||||
error: string;
|
||||
kind?: 'first_packet_timeout' | 'idle_timeout' | 'provider_error' | 'empty_response' | string;
|
||||
timeout_secs?: number;
|
||||
}
|
||||
|
||||
export interface TokenUsage {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
total_tokens: number;
|
||||
}
|
||||
|
||||
// === Voice ===
|
||||
export type VoiceSessionState = 'Idle' | 'Connecting' | 'Connected' | 'Speaking' | 'Listening' | 'Disconnecting';
|
||||
|
||||
export type AudioEncoding = 'Pcm16' | 'Opus';
|
||||
|
||||
export interface AudioFormat {
|
||||
sample_rate: number;
|
||||
channels: number;
|
||||
encoding: AudioEncoding;
|
||||
}
|
||||
|
||||
export interface RealtimeConfig {
|
||||
model_id: string;
|
||||
voice: string | null;
|
||||
audio_format: AudioFormat;
|
||||
}
|
||||
|
||||
// === UI State ===
|
||||
export type PageKey = 'chat' | 'drawing' | 'knowledge' | 'memory' | 'gateway' | 'files' | 'settings' | 'skills';
|
||||
|
||||
// === Drawing ===
|
||||
export type DrawingModelId = 'gpt-image-2' | 'gpt-image-1.5' | 'gpt-image-1' | 'gpt-image-1-mini';
|
||||
export type DrawingAction = 'generate' | 'reference_generate' | 'edit' | 'mask_edit';
|
||||
export type DrawingStatus = 'running' | 'succeeded' | 'failed' | 'stopped';
|
||||
export type DrawingQuality = 'low' | 'medium' | 'high' | 'auto';
|
||||
export type DrawingOutputFormat = 'png' | 'jpeg' | 'webp';
|
||||
export type DrawingBackground = 'auto' | 'opaque' | 'transparent';
|
||||
export type DrawingReferenceImageMode = 'multipart' | 'base64';
|
||||
export type DrawingReferenceImageFormat = 'object' | 'string';
|
||||
|
||||
export interface DrawingSettings {
|
||||
providerId: string;
|
||||
modelId: DrawingModelId;
|
||||
size: string;
|
||||
quality: DrawingQuality;
|
||||
outputFormat: DrawingOutputFormat;
|
||||
background: DrawingBackground;
|
||||
outputCompression?: number;
|
||||
referenceImageMode: DrawingReferenceImageMode;
|
||||
referenceImageFormat: DrawingReferenceImageFormat;
|
||||
referenceImageParamName: string;
|
||||
n: number;
|
||||
generationApiPath: string;
|
||||
editApiPath: string;
|
||||
}
|
||||
|
||||
export interface DrawingStoredFile {
|
||||
id: string;
|
||||
original_name: string;
|
||||
mime_type: string;
|
||||
size_bytes: number;
|
||||
storage_path: string;
|
||||
}
|
||||
|
||||
export interface DrawingImage {
|
||||
id: string;
|
||||
generation_id: string;
|
||||
stored_file_id: string;
|
||||
storage_path: string;
|
||||
mime_type: string;
|
||||
width: number | null;
|
||||
height: number | null;
|
||||
revised_prompt: string | null;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
export interface DrawingGeneration {
|
||||
id: string;
|
||||
parent_generation_id: string | null;
|
||||
provider_id: string;
|
||||
key_id: string;
|
||||
model_id: DrawingModelId | string;
|
||||
api_kind: 'image_api';
|
||||
action: DrawingAction;
|
||||
prompt: string;
|
||||
parameters_json: string;
|
||||
reference_file_ids_json: string;
|
||||
source_image_ids_json: string;
|
||||
mask_file_id: string | null;
|
||||
status: DrawingStatus;
|
||||
error_message: string | null;
|
||||
response_id: string | null;
|
||||
usage_json: string | null;
|
||||
created_at: number;
|
||||
completed_at: number | null;
|
||||
images: DrawingImage[];
|
||||
reference_files?: DrawingStoredFile[];
|
||||
source_images?: DrawingImage[];
|
||||
mask_file?: DrawingStoredFile | null;
|
||||
}
|
||||
|
||||
export interface DrawingGenerateInput {
|
||||
provider_id: string;
|
||||
model_id: DrawingModelId;
|
||||
prompt: string;
|
||||
size: string;
|
||||
quality: DrawingQuality;
|
||||
output_format: DrawingOutputFormat;
|
||||
background: DrawingBackground;
|
||||
output_compression?: number;
|
||||
n: number;
|
||||
reference_image_mode: DrawingReferenceImageMode;
|
||||
reference_image_format: DrawingReferenceImageFormat;
|
||||
reference_image_param_name: string;
|
||||
generation_api_path?: string;
|
||||
edit_api_path?: string;
|
||||
reference_file_ids: string[];
|
||||
}
|
||||
|
||||
export interface DrawingEditInput extends DrawingGenerateInput {
|
||||
source_image_id: string;
|
||||
}
|
||||
|
||||
export interface DrawingMaskEditInput extends DrawingEditInput {
|
||||
mask_file_id: string;
|
||||
}
|
||||
export type SettingsSection = 'providers' | 'defaultModel' | 'conversationSettings' | 'general' | 'display' | 'proxy' | 'shortcuts' | 'data' | 'storage' | 'about' | 'searchProviders' | 'mcpServers' | 'backup';
|
||||
|
||||
// === Files Module ===
|
||||
export type FileCategory = 'images' | 'files';
|
||||
|
||||
export type FileSortKey = 'createdAt' | 'size' | 'name';
|
||||
|
||||
export interface FileRow {
|
||||
id: string;
|
||||
name: string;
|
||||
path: string;
|
||||
storagePath?: string;
|
||||
size?: number;
|
||||
createdAt?: string;
|
||||
category?: FileCategory;
|
||||
hasThumbnail?: boolean;
|
||||
previewUrl?: string;
|
||||
missing?: boolean;
|
||||
}
|
||||
|
||||
export interface FilesPageEntry {
|
||||
id: string;
|
||||
sourceKind: string;
|
||||
category: FileCategory;
|
||||
displayName: string;
|
||||
path: string;
|
||||
storagePath?: string | null;
|
||||
sizeBytes: number;
|
||||
createdAt: string;
|
||||
missing: boolean;
|
||||
previewUrl?: string | null;
|
||||
}
|
||||
|
||||
// ── Skills ─────────────────────────────────────────────────────────────
|
||||
export interface Skill {
|
||||
name: string;
|
||||
description: string;
|
||||
author?: string;
|
||||
version?: string;
|
||||
source: 'builtin' | 'boosapi' | 'claude' | 'agents' | 'project';
|
||||
sourcePath: string;
|
||||
enabled: boolean;
|
||||
hasUpdate: boolean;
|
||||
userInvocable: boolean;
|
||||
argumentHint?: string;
|
||||
whenToUse?: string;
|
||||
group?: string;
|
||||
}
|
||||
|
||||
export interface SkillDetail {
|
||||
info: Skill;
|
||||
content: string;
|
||||
files: string[];
|
||||
manifest?: SkillManifest;
|
||||
}
|
||||
|
||||
export interface SkillManifest {
|
||||
sourceKind: string;
|
||||
sourceRef?: string;
|
||||
branch?: string;
|
||||
commit?: string;
|
||||
installedAt: string;
|
||||
installedVia?: string;
|
||||
}
|
||||
|
||||
export interface MarketplaceSkill {
|
||||
name: string;
|
||||
description: string;
|
||||
repo: string;
|
||||
stars: number;
|
||||
installs: number;
|
||||
installed: boolean;
|
||||
}
|
||||
|
||||
export interface SkillUpdateInfo {
|
||||
name: string;
|
||||
currentCommit: string;
|
||||
latestCommit: string;
|
||||
sourceRef: string;
|
||||
}
|
||||
|
||||
// Phase-2 type modules
|
||||
export * from './search';
|
||||
export * from './mcp';
|
||||
export * from './knowledge';
|
||||
export * from './memory';
|
||||
export * from './artifact';
|
||||
export * from './backup';
|
||||
export * from './workspace';
|
||||
export * from './agent';
|
||||
@@ -0,0 +1,80 @@
|
||||
export type IndexingStatus = 'pending' | 'indexing' | 'ready' | 'failed';
|
||||
export type MemoryScope = 'global' | 'project';
|
||||
export type MemorySource = 'manual' | 'auto_extract';
|
||||
|
||||
export type KnowledgeBase = {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
embeddingProvider?: string;
|
||||
enabled: boolean;
|
||||
iconType?: string;
|
||||
iconValue?: string;
|
||||
sortOrder: number;
|
||||
embeddingDimensions?: number;
|
||||
retrievalThreshold?: number;
|
||||
retrievalTopK?: number;
|
||||
rerankProvider?: string;
|
||||
rerankCandidateK?: number;
|
||||
chunkSize?: number;
|
||||
chunkOverlap?: number;
|
||||
separator?: string;
|
||||
indexConcurrency?: number;
|
||||
indexIntervalMs?: number;
|
||||
};
|
||||
|
||||
export type KnowledgeDocument = {
|
||||
id: string;
|
||||
knowledgeBaseId: string;
|
||||
title: string;
|
||||
sourcePath: string;
|
||||
mimeType: string;
|
||||
sizeBytes: number;
|
||||
indexingStatus: IndexingStatus;
|
||||
docType: string;
|
||||
indexError?: string;
|
||||
};
|
||||
|
||||
export type RetrievalHit = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
messageId: string;
|
||||
knowledgeBaseId: string;
|
||||
documentId: string;
|
||||
chunkRef: string;
|
||||
score: number;
|
||||
preview: string;
|
||||
};
|
||||
|
||||
export type CreateKnowledgeBaseInput = {
|
||||
name: string;
|
||||
description?: string;
|
||||
embeddingProvider?: string;
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
export type UpdateKnowledgeBaseInput = Partial<CreateKnowledgeBaseInput> & {
|
||||
iconType?: string | null;
|
||||
iconValue?: string | null;
|
||||
updateIcon?: boolean;
|
||||
embeddingDimensions?: number;
|
||||
updateEmbeddingDimensions?: boolean;
|
||||
retrievalThreshold?: number;
|
||||
updateRetrievalThreshold?: boolean;
|
||||
retrievalTopK?: number;
|
||||
updateRetrievalTopK?: boolean;
|
||||
rerankProvider?: string;
|
||||
updateRerankProvider?: boolean;
|
||||
rerankCandidateK?: number;
|
||||
updateRerankCandidateK?: boolean;
|
||||
chunkSize?: number;
|
||||
updateChunkSize?: boolean;
|
||||
chunkOverlap?: number;
|
||||
updateChunkOverlap?: boolean;
|
||||
separator?: string;
|
||||
updateSeparator?: boolean;
|
||||
indexConcurrency?: number;
|
||||
updateIndexConcurrency?: boolean;
|
||||
indexIntervalMs?: number;
|
||||
updateIndexIntervalMs?: boolean;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
export type McpTransport = 'stdio' | 'http' | 'sse';
|
||||
export type McpPermissionPolicy = 'ask' | 'allow_safe' | 'allow_all';
|
||||
export type ToolExecutionStatus = 'pending' | 'running' | 'success' | 'failed' | 'cancelled';
|
||||
|
||||
export type McpServerSource = 'builtin' | 'custom';
|
||||
|
||||
export type McpServer = {
|
||||
id: string;
|
||||
name: string;
|
||||
transport: McpTransport;
|
||||
command?: string | null;
|
||||
argsJson?: string | null;
|
||||
endpoint?: string | null;
|
||||
envJson?: string | null;
|
||||
enabled: boolean;
|
||||
permissionPolicy: McpPermissionPolicy;
|
||||
source: McpServerSource;
|
||||
discoverTimeoutSecs?: number | null;
|
||||
executeTimeoutSecs?: number | null;
|
||||
headersJson?: string | null;
|
||||
iconType?: string | null;
|
||||
iconValue?: string | null;
|
||||
};
|
||||
|
||||
export type ToolDescriptor = {
|
||||
id: string;
|
||||
serverId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
inputSchemaJson?: string;
|
||||
};
|
||||
|
||||
export type ToolExecution = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
messageId?: string;
|
||||
serverId: string;
|
||||
toolName: string;
|
||||
status: ToolExecutionStatus;
|
||||
inputPreview?: string;
|
||||
outputPreview?: string;
|
||||
errorMessage?: string;
|
||||
durationMs?: number;
|
||||
createdAt: string;
|
||||
approvalStatus?: string;
|
||||
};
|
||||
|
||||
export type CreateMcpServerInput = {
|
||||
name: string;
|
||||
transport: McpTransport;
|
||||
command?: string;
|
||||
args?: string[];
|
||||
endpoint?: string;
|
||||
env?: Record<string, string>;
|
||||
enabled?: boolean;
|
||||
permissionPolicy?: McpPermissionPolicy;
|
||||
discoverTimeoutSecs?: number;
|
||||
executeTimeoutSecs?: number;
|
||||
headersJson?: string;
|
||||
iconType?: string;
|
||||
iconValue?: string;
|
||||
};
|
||||
|
||||
export type UpdateMcpServerInput = {
|
||||
name?: string;
|
||||
transport?: McpTransport;
|
||||
command?: string | null;
|
||||
args?: string[] | null;
|
||||
endpoint?: string | null;
|
||||
env?: Record<string, string> | null;
|
||||
enabled?: boolean;
|
||||
permissionPolicy?: McpPermissionPolicy;
|
||||
discoverTimeoutSecs?: number | null;
|
||||
executeTimeoutSecs?: number | null;
|
||||
headersJson?: string | null;
|
||||
iconType?: string | null;
|
||||
iconValue?: string | null;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { MemoryScope, MemorySource } from './knowledge';
|
||||
|
||||
export type MemoryNamespace = {
|
||||
id: string;
|
||||
name: string;
|
||||
scope: MemoryScope;
|
||||
embeddingProvider?: string;
|
||||
embeddingDimensions?: number;
|
||||
retrievalThreshold?: number;
|
||||
retrievalTopK?: number;
|
||||
iconType?: string;
|
||||
iconValue?: string;
|
||||
sortOrder: number;
|
||||
};
|
||||
|
||||
export type MemoryItem = {
|
||||
id: string;
|
||||
namespaceId: string;
|
||||
title: string;
|
||||
content: string;
|
||||
source: MemorySource;
|
||||
indexStatus: string; // pending | indexing | ready | failed | skipped
|
||||
indexError?: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type CreateMemoryNamespaceInput = {
|
||||
name: string;
|
||||
scope: MemoryScope;
|
||||
embeddingProvider?: string;
|
||||
embeddingDimensions?: number;
|
||||
retrievalThreshold?: number;
|
||||
retrievalTopK?: number;
|
||||
};
|
||||
|
||||
export type CreateMemoryItemInput = {
|
||||
namespaceId: string;
|
||||
title: string;
|
||||
content: string;
|
||||
source?: MemorySource;
|
||||
};
|
||||
|
||||
export type UpdateMemoryItemInput = {
|
||||
title?: string;
|
||||
content?: string;
|
||||
};
|
||||
|
||||
export type UpdateMemoryNamespaceInput = {
|
||||
name?: string;
|
||||
embeddingProvider?: string;
|
||||
updateEmbeddingProvider?: boolean;
|
||||
embeddingDimensions?: number;
|
||||
updateEmbeddingDimensions?: boolean;
|
||||
retrievalThreshold?: number;
|
||||
updateRetrievalThreshold?: boolean;
|
||||
retrievalTopK?: number;
|
||||
updateRetrievalTopK?: boolean;
|
||||
iconType?: string;
|
||||
iconValue?: string;
|
||||
updateIcon?: boolean;
|
||||
sortOrder?: number;
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
export type SearchProviderType = 'tavily' | 'zhipu' | 'bocha';
|
||||
|
||||
export type SearchProvider = {
|
||||
id: string;
|
||||
name: string;
|
||||
providerType: SearchProviderType;
|
||||
endpoint?: string;
|
||||
hasApiKey: boolean;
|
||||
enabled: boolean;
|
||||
region?: string;
|
||||
language?: string;
|
||||
safeSearch?: boolean;
|
||||
resultLimit: number;
|
||||
timeoutMs: number;
|
||||
};
|
||||
|
||||
export type SearchCitation = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
messageId: string;
|
||||
title: string;
|
||||
url: string;
|
||||
snippet?: string;
|
||||
providerId: string;
|
||||
rank: number;
|
||||
};
|
||||
|
||||
export type CreateSearchProviderInput = {
|
||||
name: string;
|
||||
providerType: SearchProviderType;
|
||||
endpoint?: string;
|
||||
apiKey?: string;
|
||||
enabled?: boolean;
|
||||
region?: string;
|
||||
language?: string;
|
||||
safeSearch?: boolean;
|
||||
resultLimit?: number;
|
||||
timeoutMs?: number;
|
||||
};
|
||||
|
||||
export type UpdateSearchProviderInput = Partial<CreateSearchProviderInput>;
|
||||
|
||||
/** A single search result item returned by execute_search */
|
||||
export type SearchResultItem = {
|
||||
title: string;
|
||||
content: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
/** Response from the execute_search Tauri command */
|
||||
export type SearchExecuteResponse = {
|
||||
ok: boolean;
|
||||
query: string;
|
||||
results: SearchResultItem[];
|
||||
latencyMs: number;
|
||||
error?: string;
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
export type ContextSourceType = 'attachment' | 'search' | 'knowledge' | 'memory' | 'tool';
|
||||
|
||||
export type ContextSource = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
messageId?: string;
|
||||
type: ContextSourceType;
|
||||
refId: string;
|
||||
title: string;
|
||||
enabled: boolean;
|
||||
summary?: string;
|
||||
};
|
||||
|
||||
export type ConversationBranch = {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
parentMessageId: string;
|
||||
branchLabel: string;
|
||||
branchIndex: number;
|
||||
comparedMessageIds?: string[];
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type SearchPolicy = {
|
||||
enabled: boolean;
|
||||
searchProviderId?: string;
|
||||
queryMode: 'manual' | 'auto';
|
||||
resultLimit: number;
|
||||
};
|
||||
|
||||
export type ToolBinding = {
|
||||
serverIds: string[];
|
||||
defaultTools?: string[];
|
||||
approvalMode: 'inherit' | 'ask' | 'allow_safe';
|
||||
};
|
||||
|
||||
export type KnowledgeBinding = {
|
||||
knowledgeBaseIds: string[];
|
||||
autoAttach: boolean;
|
||||
};
|
||||
|
||||
export type MemoryPolicy = {
|
||||
enabled: boolean;
|
||||
namespaceId?: string;
|
||||
writeBack: boolean;
|
||||
};
|
||||
|
||||
export type ContextToggleState = {
|
||||
searchEnabled: boolean;
|
||||
searchProviderId?: string;
|
||||
enabledKnowledgeBaseIds: string[];
|
||||
enabledMcpServerIds: string[];
|
||||
enabledToolNames?: string[];
|
||||
memoryEnabled: boolean;
|
||||
memoryNamespaceId?: string;
|
||||
memoryWriteBack: boolean;
|
||||
disabledContextSourceIds?: string[];
|
||||
};
|
||||
|
||||
export type ConversationWorkspaceSnapshot = {
|
||||
searchPolicy: SearchPolicy;
|
||||
toolBinding: ToolBinding;
|
||||
knowledgeBinding: KnowledgeBinding;
|
||||
memoryPolicy: MemoryPolicy;
|
||||
toggles: ContextToggleState;
|
||||
researchMode: boolean;
|
||||
pinnedArtifactIds: string[];
|
||||
};
|
||||
|
||||
export type ContextOverrideInput = {
|
||||
searchEnabled?: boolean;
|
||||
searchProviderId?: string | null;
|
||||
enabledKnowledgeBaseIds?: string[];
|
||||
enabledMcpServerIds?: string[];
|
||||
enabledToolNames?: string[];
|
||||
memoryEnabled?: boolean;
|
||||
memoryNamespaceId?: string | null;
|
||||
memoryWriteBack?: boolean;
|
||||
disabledContextSourceIds?: string[];
|
||||
researchMode?: boolean;
|
||||
};
|
||||
|
||||
export type CreateConversationInput = {
|
||||
title: string;
|
||||
providerId: string;
|
||||
modelId: string;
|
||||
systemPrompt?: string;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
topP?: number;
|
||||
frequencyPenalty?: number;
|
||||
workspaceSnapshot?: ConversationWorkspaceSnapshot;
|
||||
};
|
||||
|
||||
export type UpdateConversationInput = {
|
||||
title?: string;
|
||||
providerId?: string;
|
||||
modelId?: string;
|
||||
workspaceSnapshot?: ConversationWorkspaceSnapshot;
|
||||
activeBranchId?: string | null;
|
||||
activeArtifactId?: string | null;
|
||||
researchMode?: boolean;
|
||||
};
|
||||
|
||||
export type SendMessageInput = {
|
||||
conversationId: string;
|
||||
content: string;
|
||||
attachments?: AttachmentInput[];
|
||||
contextOverride?: ContextOverrideInput;
|
||||
};
|
||||
|
||||
export type AttachmentInput = {
|
||||
name: string;
|
||||
path: string;
|
||||
mimeType: string;
|
||||
sizeBytes: number;
|
||||
};
|
||||
|
||||
export type CompareResponsesResult = {
|
||||
leftMessage: { id: string; content: string };
|
||||
rightMessage: { id: string; content: string };
|
||||
};
|
||||
Reference in New Issue
Block a user