/** * 主进程 / 渲染进程共享的类型与 IPC 契约。 * * 已存 API Key 不返回渲染进程;用户可在模型表单编辑地址和新密钥。 * 对话由主进程 Claude Code 内核完成;模型配置与连接测试仍在主进程。 */ /** 会话内的一条消息(对外视图) */ import type { ArtifactContent, ChatAttachment, ChatInteraction, MessageQuote, PlanContent, TaskContent, UserContentBlock } from './conversation' export interface ChatMessage { id: string role: 'user' | 'assistant' content: string /** 助手消息携带的工具调用记录 */ tools?: ToolCallRecord[] /** 按事件顺序记录正文与工具位置;旧会话没有此字段时按兼容方式渲染。 */ parts?: MessagePart[] attachments?: ChatAttachment[] resources?: string[] /** 发送时引用进对话的表格等内容块快照(WorkBuddy messageQuote)。 */ quotes?: MessageQuote[] /** Ordered inline presentation, validated against content and its actual payload collections. */ userContent?: UserContentBlock[] skills?: Array<{ id: string; name: string; uri: string }> assistantDisplay?: import('./capabilities').ExpertBinding /** The model selected when this assistant turn started; kept with history. */ modelId?: string modelName?: string /** Last actual upstream request sample, with that turn's frozen window. Never a session sum. */ contextUsage?: ContextUsageSnapshot /** Independent local counts of one prepared provider input; never a split of billed usage. */ contextBreakdown?: ContextUsageBreakdown interactions?: ChatInteraction[] requestId?: string /** Last top-level Claude chain entry for this assistant turn, used only as a fork point. */ claudeEntryId?: string planId?: string feedback?: 'like' | 'dislike' interrupted?: boolean createdAt: number /** User-submit timestamp shared by the live timer and terminal turn duration. */ turnStartedAt?: number /** Measured user-send to terminal-event duration, used by the source completed fold. */ turnDurationMs?: number /** 本回合的终态 */ status?: 'streaming' | 'done' | 'error' | 'cancelled' error?: string /** 渲染进程专用的启动占位阶段(新任务发送后、主进程回合就绪前);不参与持久化。 */ prepareStage?: string } export interface ToolCallRecord { id: string name: string /** Human-readable action description supplied by the tool runtime, when available. */ intent?: string /** 已解析的参数(原始 JSON 字符串的解析结果,解析失败则保留原文) */ args: unknown argsRaw: string status: 'running' | 'ok' | 'error' | 'cancelled' /** 完整的文本输出;summary 仅供折叠态摘要,不能替代原文。 */ output?: string /** 展示用摘要(截断后的结果) */ summary?: string durationMs?: number /** Native structured result and renderer metadata are retained separately from text. */ result?: unknown metadata?: Record } export type MessagePart = | { type: 'text'; text: string } | { type: 'tool'; toolId: string } | { type: 'reasoning'; id: string; text: string; finished?: boolean } | { type: 'plan'; plan: PlanContent } | { type: 'task'; task: TaskContent } | { type: 'artifact'; artifact: ArtifactContent } | { type: 'image'; id: string; url: string; alt?: string } /** 面向模型暴露的工具描述(OpenAI function tool 格式) */ export interface ToolSpec { type: 'function' function: { name: string description: string parameters: Record } } /** Main-process resolved upstream protocol and credentials. */ export interface GatewayConfig { api?: import('./models').ModelApi supportsReasoning?: boolean temperatureSupported?: boolean thinkingLevel?: import('./workspaces').ThinkingLevel reasoningBudget?: number reasoningOptions?: import('./models').ModelReasoningOption[] speechBaseUrl?: string speechModel?: string /** 上游 baseUrl,例如 https://api.deepseek.com/v1 */ baseUrl: string /** 模型名,例如 deepseek-chat */ model: string /** API Key(仅存在于主进程) */ apiKey: string /** 采样温度 */ temperature: number /** 单回合最大工具轮次 */ maxToolRounds: number authMode?: 'api-key' | 'none' maxOutputTokens?: number } /** 渲染进程可见的配置视图(不含 apiKey) */ export interface GatewayConfigView { speechBaseUrl?: string speechModel?: string baseUrl: string model: string temperature: number maxToolRounds: number /** 是否已配置 Key(不回传明文) */ hasApiKey: boolean /** Key 来源:safeStorage 加密 / 明文降级 */ keyStorage: 'encrypted' | 'plaintext' | 'none' } /** 设置 → 通用:真实状态视图(未接入项不下发数据)。 */ export interface GeneralSettingsView { /** 系统登录项的真实状态 */ autoLaunch: boolean /** 运行任务时阻止系统休眠(偏好) */ preventSleep: boolean /** 当前是否有 powerSaveBlocker 生效 */ preventSleepActive: boolean /** 数据目录(存放对话记录、运行缓存与临时文件) */ dataDir: string /** 数据目录占用字节 */ dataBytes: number /** 扫描是否因预算被截断 */ dataUsagePartial: boolean /** 数据目录所在磁盘容量 */ disk: { totalBytes: number; freeBytes: number } /** 默认工作空间存储路径 */ workspaceRoot: string } export interface GeneralSettingsPatch { autoLaunch?: boolean preventSleep?: boolean } /** 设置 → 个性化的回复风格(REA ev_af920…:默认/专业严谨/亲和友善/直言不讳/天马行空/高效务实/毒舌吐槽/启发引导)。 */ export type PersonalizationTone = 'default' | 'professional' | 'friendly' | 'direct' | 'imaginative' | 'efficient' | 'sarcastic' | 'socratic' /** * 设置 → 个性化的持久化数据。 * * 已接入运行链路:userCallName / aiName / tone / customPrompt / persona / longTermMemory 会拼进 * 每次对话的请求上下文;loadingTips 控制流式加载提示的欢迎语是否显示。 * showFileChanges 已在原版页面呈现,但 YCode 的「逐步展示文件修改过程」渲染尚未接入,UI 标记为不可用。 */ export interface PersonalizationSettings { /** WorkBuddy 对你的称呼(YCode 品牌化为「YCode 对你的称呼」)。 */ userCallName: string /** WorkBuddy 的名字(YCode 品牌化为「YCode 的名字」)。 */ aiName: string tone: PersonalizationTone /** 欢迎语:对话加载较慢时显示的问候/提示。 */ loadingTips: boolean /** 显示文件修改过程(尚未接入渲染链路)。 */ showFileChanges: boolean /** 给 WorkBuddy 的指令(长期生效的附加要求)。 */ customPrompt: string /** 人设设定。 */ persona: string /** 长期记忆。 */ longTermMemory: string } export type PersonalizationPatch = Partial /** * 设置 → 智能体(TODO 15)。 * 智能体团队管理为本地子智能体调度总开关;经济模式与浏览器操控已按用户要求移除。 */ export interface AgentSettings { /** 开启后复杂任务自动拆分多个智能体协作完成(原版默认开启)。 */ teamManagement: boolean } export type AgentSettingsPatch = Partial /** * 设置 → 记忆与进化(TODO 14)。 * * 原版把“对话记忆”保存到账户侧,“本地记忆与技能”保存在本地存储 * (REA 回收 MemorySettingsPanel-BU1K5nn4.js / local-skills-memory-Bb3Kqaxi.js)。 * YCode 将两项偏好统一写入 config.json;页面展示的数据不会补造。 */ export interface MemoryPreferences { /** 允许已保存的长期记忆进入后续对话上下文。 */ conversationMemory: boolean /** 本地记忆与技能偏好;自动记录执行器尚未接入。 */ localMemorySkills: boolean } export interface MemorySettingsView extends MemoryPreferences { /** 当前长期记忆正文(由个性化设置的真实长期记忆字段提供)。 */ content: string } export type MemoryPreferencesPatch = Partial /** 主进程 → 渲染进程的流式事件 */ export type ChatEvent = { sessionId?: string; turnDurationMs?: number; sequence?: number } & ( | { runId: string; type: 'started'; messageId: string } | { runId: string; type: 'text'; delta: string } | { runId: string; type: 'part'; part: Exclude } | { runId: string; type: 'interaction'; interaction: ChatInteraction } | { runId: string; type: 'tool_call'; call: ToolCallRecord } | { runId: string; type: 'tool_result'; call: ToolCallRecord } | { runId: string; type: 'usage'; usage: TokenUsage; contextWindow?: number; sampledAt?: number; modelId?: string; source?: ContextUsageSnapshot['source'] } | { runId: string; type: 'context_breakdown'; breakdown: ContextUsageBreakdown } | { runId: string; type: 'done'; content: string; tools: ToolCallRecord[] } | { runId: string; type: 'cancelled' } | { runId: string; type: 'error'; message: string } ) /** * 上游返回的真实 token 用量(Responses `response.completed.usage`)。 * 只做透传,不做估算:拿不到就不产生该事件。 */ export interface TokenUsage { inputTokens: number outputTokens: number totalTokens: number cachedTokens?: number } export interface ContextUsageSnapshot { usage: TokenUsage /** Missing when the selected profile never declared a real context window. */ contextWindow?: number source?: 'upstream' sampledAt?: number requestId?: string modelId?: string } export type ContextUsageCategory = 'system' | 'tools' | 'conversation' | 'mcp' | 'skills' | 'other' export interface ContextUsageBreakdown { requestId: string /** Monotonic within a turn, so a late older request cannot replace a newer one. */ sequence: number sampledAt: number modelId?: string contextWindow?: number method: 'model-tokenizer' | 'o200k_base' | 'utf8-estimate' scope: 'provider-request' | 'prepared-request' counts: Record inputTokens: number /** Images or an unavailable provider layer mean these counts are partial. */ partial: boolean } /** A read-only query never creates or switches an agent to obtain a number. */ export interface ContextUsageInfo { sample?: ContextUsageSnapshot breakdown?: ContextUsageBreakdown status: 'latest' | 'previous' | 'unavailable' reason?: string } /** * 会话工作目录的 Git 信息(用于对话框的分支标签)。 * `repo: false` 表示该目录不在 Git 仓库内;`detached: true` 时 `branch` 为空、`head` 为短 SHA。 */ export interface GitBranchInfo { /** 目录是否位于 Git 工作树内 */ repo: boolean /** 分支名;detached HEAD 或尚无提交时为 null */ branch: string | null detached: boolean /** detached HEAD 的短 SHA;无提交时为 null */ head: string | null /** git 可执行文件缺失或命令超时时为 true,UI 不显示分支标签 */ unavailable?: boolean } /** 一次会话的元信息 */ export interface SessionMeta { projectId?: string id: string title: string createdAt: number updatedAt: number workspaceId?: string cwd?: string modelId?: string expertId?: string | null agentMode?: import('./conversation').AgentMode thinkingLevel?: import('./workspaces').ThinkingLevel /** Claude Code session used for this YCode conversation. */ claudeSessionId?: string /** Pending Claude fork point for edit/regenerate. */ claudeForkAt?: string /** 置顶时间(毫秒)。有值即视为已置顶,用于侧栏任务排序,不改变 createdAt/updatedAt 语义。 */ pinnedAt?: number /** 归档时间(毫秒)。归档任务从默认任务列表移出,但不删除消息与工作目录。 */ archivedAt?: number } /** 工作目录信息 */ export interface WorkspaceInfo { root: string } /** 无边框窗口状态 */ export interface WindowState { maximized: boolean fullscreen: boolean } /** 应用信息(关于对话框用) */ export interface AppInfo { name: string version: string electron: string chrome: string node: string configDir: string /** Claude Code 内核状态(未探测到时 available 为 false) */ claude: { available: boolean exePath: string | null sessionDir: string version?: string } }