Files
ycode/src/shared/types.ts
T

343 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 主进程 / 渲染进程共享的类型与 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<string, unknown>
}
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<string, unknown>
}
}
/** 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<PersonalizationSettings>
/**
* 设置 → 智能体(TODO 15)。
* 智能体团队管理为本地子智能体调度总开关;经济模式与浏览器操控已按用户要求移除。
*/
export interface AgentSettings {
/** 开启后复杂任务自动拆分多个智能体协作完成(原版默认开启)。 */
teamManagement: boolean
}
export type AgentSettingsPatch = Partial<AgentSettings>
/**
* 设置 → 记忆与进化(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<MemoryPreferences>
/** 主进程 → 渲染进程的流式事件 */
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<MessagePart, { type: 'text' } | { type: 'tool' }> }
| { 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<ContextUsageCategory, number>
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
}
}