Velo / src /shared /ipc-channels.ts
Leon4gr45's picture
Upload folder using huggingface_hub (part 2)
deedb97 verified
Raw History Blame Contribute Delete
19.7 kB
/**
* Vela IPC 频道定义 — 渲染进程与主进程的类型安全通信契约
* 所有 IPC 调用都通过此文件定义频道名和参数/返回值类型
*/
// ===== 全局配置 =====
export interface ConfigChannels {
'config:get': {
args: []
return: GlobalConfig
}
'config:set': {
args: [config: Partial<GlobalConfig>]
return: { success: boolean; error?: string }
}
'config:get-vela-home': {
args: []
return: string
}
}
export interface GlobalConfig {
theme: string
defaultModelId: string | null
defaultEmbeddingModelId?: string | null
editorFontSize: number
editorFontFamily: string
autoSaveInterval: number
proxy?: {
enabled: boolean
type: 'http' | 'socks5'
host: string
port: number
}
}
// ===== 项目管理 =====
export interface ProjectChannels {
'project:create': {
args: [config: { name: string; path: string; genre: string; targetAudience: string }]
return: { success: boolean; projectId: string; projectPath?: string; error?: string }
}
'project:open': {
args: [projectPath: string]
return: { success: boolean; project: ProjectData | null; error?: string }
}
'project:save': {
args: [projectId: string, data: Partial<ProjectData>]
return: { success: boolean; error?: string }
}
'project:update-config': {
args: [projectId: string, data: Partial<ProjectData>]
return: { success: boolean; error?: string }
}
'project:recent-list': {
args: []
return: Array<{ name: string; path: string; updatedAt: string }>
}
'dialog:select-folder': {
args: []
return: string | null
}
}
// ===== 文件系统 =====
export interface FileChannels {
'fs:read-file': {
args: [filePath: string]
return: { success: boolean; content: string; error?: string }
}
'fs:write-file': {
args: [filePath: string, content: string]
return: { success: boolean; error?: string }
}
'fs:list-dir': {
args: [dirPath: string]
return: FileNode[]
}
'fs:mkdir': {
args: [dirPath: string]
return: { success: boolean; error?: string }
}
'fs:check-exists': {
args: [filePath: string]
return: boolean
}
'fs:read-json': {
args: [filePath: string]
return: { success: boolean; data: unknown; error?: string }
}
'fs:write-json': {
args: [filePath: string, data: unknown]
return: { success: boolean; error?: string }
}
}
// ===== LLM 调用 =====
export interface LLMChannels {
'llm:generate': {
args: [request: LLMRequest]
return: LLMResponse
}
'llm:generate-stream': {
args: [requestId: string, request: LLMRequest]
return: { requestId: string; started: boolean }
}
'llm:cancel': {
args: [requestId: string]
return: { success: boolean }
}
'llm:list-models': {
args: []
return: ModelProfile[]
}
'llm:save-model': {
args: [model: ModelProfile]
return: { success: boolean }
}
'llm:delete-model': {
args: [modelId: string]
return: { success: boolean }
}
'llm:set-default-model': {
args: [modelId: string | null]
return: { success: boolean; error?: string }
}
'llm:get-default-model': {
args: []
return: string | null
}
'llm:set-default-embedding-model': {
args: [modelId: string | null]
return: { success: boolean; error?: string }
}
'llm:get-default-embedding-model': {
args: []
return: string | null
}
'llm:test-connection': {
args: [model: ModelProfile]
return: { success: boolean; error?: string }
}
}
export interface LLMStreamEvents {
'llm:stream-chunk': { requestId: string; chunk: string }
'llm:stream-done': { requestId: string; fullText: string; usage?: TokenUsage }
'llm:stream-error': { requestId: string; error: string }
}
// ===== 公共数据类型 =====
export interface ProjectData {
id: string
name: string
path: string
novelConfig: NovelConfig
characterStates: string
createdAt: string
updatedAt: string
}
export interface NovelConfig {
genre: string
subGenre: string
targetAudience: string
totalChapters: number
wordsPerChapter: number
plotStructure: 'three_act' | 'heros_journey' | 'save_the_cat' | 'kishotenketsu' | 'multi_thread' | 'freeform'
narrativePOV: 'third_limited' | 'first_person' | 'third_omniscient' | 'multi_pov'
coreOutline: string
worldSetting: string
goldenFinger: string
protagonistProfile: string
globalGuidance: string
writingStyle?: string
referenceWorks?: string
}
export interface FileNode {
name: string
path: string
isDir: boolean
children?: FileNode[]
}
export interface LLMRequest {
modelId: string
messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>
temperature?: number
maxTokens?: number
stream?: boolean
responseFormat?: { type: 'json_object' | 'text' }
thinking?: boolean
}
export interface LLMResponse {
success: boolean
content: string
usage?: TokenUsage
error?: string
}
export interface TokenUsage {
promptTokens: number
completionTokens: number
totalTokens: number
}
export interface ModelProfile {
id: string
name: string
provider: 'openai' | 'gemini' | 'deepseek' | 'ollama' | 'bigmodel' | 'custom'
protocol: 'openai' | 'gemini'
modelName: string
apiKey: string
baseUrl: string
temperature: number
maxTokens: number
purposes: Array<'generation' | 'refinement' | 'summary' | 'embedding'>
}
// ===== 引入 DB 类型 =====
import type { ProjectCoreData } from '../../electron/repositories/project-core-repository'
import type { BlueprintData } from '../../electron/repositories/blueprint-repository'
import type { CharacterData, CharacterStateData } from '../../electron/repositories/character-repository'
import type { DraftMeta, DraftFull } from '../../electron/repositories/draft-repository'
import type { RevisionMeta, RevisionFull } from '../../electron/repositories/revision-repository'
import type { ReviewMeta, ReviewFull } from '../../electron/repositories/review-repository'
import type { PostProcessRunData, PostProcessStepData } from '../../electron/repositories/post-process-repository'
// ===== 数据库操作 =====
export interface DatabaseChannels {
'db:close': { args: []; return: { success: boolean } }
// 1. project_core
'db:project-core-get': { args: []; return: ProjectCoreData | null }
'db:project-core-update': { args: [data: Partial<ProjectCoreData>]; return: { success: boolean; error?: string } }
// 2. blueprints
'db:blueprint-get-all': { args: []; return: BlueprintData[] }
'db:blueprint-get': { args: [chapterNumber: number]; return: BlueprintData | null }
'db:blueprint-upsert': { args: [data: BlueprintData]; return: { success: boolean; error?: string } }
'db:blueprint-upsert-many': { args: [items: BlueprintData[]]; return: { success: boolean; error?: string } }
'db:blueprint-update-notes': { args: [chapterNumber: number, notes: string]; return: { success: boolean; error?: string } }
// 3. characters
'db:character-get-all': { args: []; return: CharacterData[] }
'db:character-upsert': { args: [data: CharacterData]; return: { success: boolean; error?: string } }
'db:character-save-all': { args: [items: CharacterData[]]; return: { success: boolean; error?: string } }
'db:character-delete': { args: [name: string]; return: { success: boolean; error?: string } }
'db:character-update-state': { args: [name: string, state: CharacterStateData]; return: { success: boolean; error?: string } }
// 4. drafts
'db:draft-create': { args: [params: { chapterNumber: number; version: number; source: 'write' | 'rewrite'; content: string; wordCount: number }]; return: { success: boolean; id?: number; error?: string } }
'db:draft-list': { args: [chapterNumber: number]; return: DraftMeta[] }
'db:draft-get-meta': { args: [id: number]; return: DraftMeta | null }
'db:draft-get-full': { args: [id: number]; return: DraftFull | null }
'db:draft-get-latest': { args: [chapterNumber: number]; return: DraftMeta | null }
'db:draft-get-finalized': { args: [chapterNumber: number]; return: DraftMeta | null }
'db:draft-get-max-finalized-chapter': { args: []; return: number }
'db:draft-next-version': { args: [chapterNumber: number]; return: number }
'db:draft-update-status': { args: [id: number, status: string, wordCount?: number]; return: { success: boolean; error?: string } }
'db:draft-update-content': { args: [id: number, content: string, wordCount: number]; return: { success: boolean; error?: string } }
// 5. revisions
'db:revision-create': { args: [params: { baseDraftId: number; revisionIndex: number; revisionType: 'refine' | 'review-fix'; userPrompt?: string; reviewSourceId?: number; content: string; wordCount: number }]; return: { success: boolean; id?: number; error?: string } }
'db:revision-list': { args: [baseDraftId: number]; return: RevisionMeta[] }
'db:revision-get-pending': { args: [baseDraftId: number]; return: RevisionMeta[] }
'db:revision-get-full': { args: [id: number]; return: RevisionFull | null }
'db:revision-next-index': { args: [baseDraftId: number]; return: number }
'db:revision-mark-merged': { args: [id: number, mergedToDraftId: number]; return: { success: boolean; error?: string } }
'db:revision-mark-discarded': { args: [id: number]; return: { success: boolean; error?: string } }
// 6. reviews
'db:review-create': { args: [params: { baseDraftId: number; reviewIndex: number; content: string }]; return: { success: boolean; id?: number; error?: string } }
'db:review-list': { args: [baseDraftId: number]; return: ReviewMeta[] }
'db:review-get-latest': { args: [baseDraftId: number]; return: ReviewFull | null }
'db:review-get-full': { args: [id: number]; return: ReviewFull | null }
'db:review-next-index': { args: [baseDraftId: number]; return: number }
// 7. post_process
'db:post-process-create-run': { args: [params: { triggerSourceType: string; triggerSourceId: string; sourceLabel: string; steps: Array<{ key: string; label: string; critical: boolean }> }]; return: { success: boolean; id?: string; error?: string } }
'db:post-process-get-latest-run': { args: [sourceType: string, sourceId: string]; return: PostProcessRunData | null }
'db:post-process-get-steps': { args: [runId: string]; return: PostProcessStepData[] }
'db:post-process-mark-step-ok': { args: [runId: string, stepKey: string]; return: { success: boolean; error?: string } }
'db:post-process-mark-step-failed': { args: [runId: string, stepKey: string, errorMsg: string]; return: { success: boolean; error?: string } }
'db:post-process-is-all-passed': { args: [sourceType: string, sourceId: string]; return: boolean }
// 沿用旧表
'db:log-llm-call': { args: [call: Record<string, unknown>]; return: { success: boolean } }
'db:get-llm-stats': { args: []; return: { totalCalls: number; totalTokens: number; totalPromptTokens: number; totalCompletionTokens: number } }
'db:get-llm-history': { args: [limit?: number]; return: unknown[] }
'db:save-summary-snapshot': { args: [chapterNumber: number, characterStates: string]; return: { success: boolean } }
'db:get-latest-summary': { args: []; return: { characterStates: string; chapterNumber: number } | null }
// ===== Canon Store (叙事一致性) =====
'db:canon-timeline-get': { args: [maxChapter: number, includeFlashback?: boolean]; return: CanonTimelineEvent[] }
'db:canon-timeline-get-chapter': { args: [chapterNumber: number]; return: CanonTimelineEvent[] }
'db:canon-timeline-append': { args: [event: CanonTimelineEventInput]; return: { success: boolean; id?: number; error?: string } }
'db:canon-timeline-clear-chapter': { args: [chapterNumber: number]; return: { success: boolean } }
'db:canon-character-state-get-all': { args: []; return: CanonCharacterStateSnapshot[] }
'db:canon-character-state-get': { args: [character: string]; return: CanonCharacterStateSnapshot | null }
'db:canon-character-state-upsert': { args: [snapshot: CanonCharacterStateSnapshot]; return: { success: boolean; error?: string } }
'db:canon-plot-list': { args: [status?: 'active' | 'resolved' | 'paused']; return: CanonPlotLine[] }
'db:canon-plot-add': { args: [line: CanonPlotLineInput]; return: { success: boolean; id?: number; error?: string } }
'db:canon-plot-advance': { args: [id: number, currentState: string, lastAdvancedAt: number]; return: { success: boolean } }
'db:canon-plot-resolve': { args: [id: number, chapterNumber: number]; return: { success: boolean } }
'db:canon-fact-list': { args: []; return: CanonFact[] }
'db:canon-fact-add': { args: [fact: CanonFactInput]; return: { success: boolean; id?: number; error?: string } }
'db:canon-fact-clear-chapter': { args: [chapterNumber: number]; return: { success: boolean } }
'db:canon-summary-get': { args: [chapterNumber: number]; return: CanonChapterSummary | null }
'db:canon-summary-list-recent': { args: [limit?: number]; return: CanonChapterSummary[] }
'db:canon-summary-upsert': { args: [summary: CanonChapterSummary]; return: { success: boolean; error?: string } }
// 原子写回(推荐路径:单次事务)
'db:canon-writeback-atomic': {
args: [payload: CanonWritebackPayload]
return: { success: boolean; error?: string; timelineIds?: number[]; characterStatesWritten?: number; plotIds?: number[]; factIds?: number[] }
}
}
// CanonWritebackPayload 与主进程 CanonRepository.writebackAtomically 入参兼容
export interface CanonWritebackPayload {
chapterNumber: number
newEvents: Array<{
chapterNumber: number
sequence: number
characters: string[]
location: string
timeFlow: 'sequential' | 'flashback'
summary: string
impact: string
}>
characterDeltas: Array<{
character: string
chapterNumber: number
after: {
location?: string
powerLevel?: string
physicalState?: string
mentalState?: string
keyItems?: string
currentGoal?: string
knowledge?: string[]
relationships?: Record<string, string>
recentEvents?: string
}
}>
plotLineChanges?: {
added?: Array<{
name: string
status: 'active' | 'resolved' | 'paused'
startedAt: number
lastAdvancedAt: number
resolvedAt?: number
characters: string[]
currentState: string
description: string
}>
advanced?: Array<{ id: number; currentState: string; lastAdvancedAt: number }>
resolved?: number[]
}
newFacts: Array<{
category: 'world' | 'location' | 'item' | 'event' | 'relationship' | 'identity'
statement: string
introducedAt: number
characters: string[]
evidence?: string
}>
}
// ===== Canon Store 类型别名(避免 ipc-channels.ts 直接依赖 narrative-consistency) =====
export interface CanonTimelineEvent {
id?: number
chapterNumber: number
sequence: number
characters: string[]
location: string
timeFlow: 'sequential' | 'flashback'
summary: string
impact: string
createdAt?: string
}
export interface CanonTimelineEventInput {
chapterNumber: number
sequence: number
characters: string[]
location: string
timeFlow: 'sequential' | 'flashback'
summary: string
impact: string
}
export interface CanonCharacterStateSnapshot {
character: string
location: string
powerLevel: string
physicalState: string
mentalState: string
keyItems: string
currentGoal: string
knowledge: string[]
relationships: Record<string, string>
recentEvents: string
updatedAtChapter: number
updatedAt: string
}
export interface CanonPlotLine {
id?: number
name: string
status: 'active' | 'resolved' | 'paused'
startedAt: number
lastAdvancedAt: number
resolvedAt?: number
characters: string[]
currentState: string
description: string
}
export interface CanonPlotLineInput {
name: string
status: 'active' | 'resolved' | 'paused'
startedAt: number
lastAdvancedAt: number
resolvedAt?: number
characters: string[]
currentState: string
description: string
}
export interface CanonFact {
id?: number
category: 'world' | 'location' | 'item' | 'event' | 'relationship' | 'identity'
statement: string
introducedAt: number
characters: string[]
evidence?: string
}
export interface CanonFactInput {
category: 'world' | 'location' | 'item' | 'event' | 'relationship' | 'identity'
statement: string
introducedAt: number
characters: string[]
evidence?: string
}
export interface CanonChapterSummary {
chapterNumber: number
title: string
summary: string
createdAt: string
}
// ===== 知识库频道 =====
export interface KnowledgeBaseChannels {
'kb:import-document': { args: [filePath: string]; return: { success: boolean; docId?: string; chunkCount?: number; error?: string } }
'kb:import-folder': { args: [folderPath: string]; return: { success: boolean; importedCount: number; failedFiles: string[]; error?: string } }
'kb:import-text': { args: [text: string, fileName: string, projectPath: string]; return: { success: boolean; docId?: string; chunkCount?: number; error?: string } }
'kb:search': { args: [query: string, topK?: number]; return: Array<{ text: string; score: number; fileName: string }> }
'kb:search-with-scope': { args: [query: string, fromChapter: number, toChapter: number, topK?: number]; return: Array<{ text: string; score: number; fileName: string }> }
'kb:list-documents': { args: []; return: Array<{ id: string; fileName: string; importedAt: string; chunkCount: number; filePath: string }> }
'kb:remove-document': { args: [docId: string]; return: { success: boolean } }
'kb:stats': { args: []; return: { documentCount: number; totalChunks: number; vectorDimension: number } }
'dialog:select-files': { args: []; return: string[] | null }
'dialog:select-import-folder': { args: []; return: string | null }
'kb:get-vectorless-count': { args: []; return: { count: number } }
'kb:backfill-vectors': { args: []; return: { success: boolean; processed: number; failed: number; error?: string } }
}
// ===== 导入小说 =====
export interface ImportChannels {
'dialog:select-novel-files': { args: []; return: string[] | null }
'import:split-chapters': {
args: [filePaths: string[], options?: { separator?: string }]
return: {
success: boolean
chapters: Array<{ number: number; title: string; content: string; wordCount: number }>
totalWords: number
error?: string
}
}
}
// ===== MCP =====
export interface MCPChannels {
'mcp:load-config': { args: [configPath?: string]; return: { success: boolean; configs: unknown[]; error?: string } }
'mcp:connect': { args: [config: Record<string, unknown>]; return: { success: boolean; error?: string } }
'mcp:disconnect': { args: [serverId: string]; return: { success: boolean; error?: string } }
'mcp:disconnect-all': { args: []; return: { success: boolean; error?: string } }
'mcp:list-tools': { args: []; return: unknown[] }
'mcp:list-resources': { args: []; return: unknown[] }
'mcp:call-tool': { args: [serverId: string, toolName: string, args: Record<string, unknown>]; return: { success: boolean; content: string; error?: string } }
'mcp:get-servers-status': { args: []; return: unknown[] }
'mcp:get-config-path': { args: []; return: string }
}
// ===== 合并所有频道 =====
export type AllInvokeChannels = ConfigChannels & ProjectChannels & FileChannels & LLMChannels & DatabaseChannels & KnowledgeBaseChannels & ImportChannels & MCPChannels
export type AllEventChannels = LLMStreamEvents
/** 提取 invoke 频道名 */
export type InvokeChannel = keyof AllInvokeChannels
/** 提取 event 频道名 */
export type EventChannel = keyof AllEventChannels