Code Reader
首页
帮助
设计文档
首页
帮助
设计文档
  • Message (MessageV2)

Message (MessageV2)

MessageV2 是当前使用的消息架构,支持多种角色和丰富的元数据。

概述

Message 表示会话中的一次对话交换,分为 User 和 Assistant 两种角色。Message 本身只包含元数据,实际内容通过 Part 数组承载。这种设计允许灵活的消息内容组合(文本、文件、工具调用等)。

定义位置

packages/opencode/src/session/message-v2.ts:1-740

核心特性

  • 灵活的内容结构:通过 Part 数组支持多种内容类型
  • 独立的元数据:Message 存储会话级别信息,Part 存储详细内容
  • 流式更新:支持 Part 的增量和增量更新
  • 模型转换:toModelMessages() 自动转换为 LLM 格式
  • 错误处理:支持多种错误类型和重试机制

User Message

用户消息结构,表示用户的输入。

属性名类型必填说明
idstring是消息唯一标识符
sessionIDstring是所属会话ID
role"user"是角色固定为 "user"
timeobject是时间信息
time.creatednumber-创建时间(Unix时间戳)
summaryobject否摘要信息
summary.titlestring-摘要标题
summary.bodystring-摘要内容
summary.diffsFileDiff[]-文件差异列表
agentstring是使用的Agent名称
modelobject是模型配置
model.providerIDstring-提供商ID
model.modelIDstring-模型ID
systemstring否系统提示词
toolsRecord<string, boolean>否工具配置
variantstring否变体标识

Assistant Message

AI 助手消息结构,表示 AI 的响应。

属性名类型必填说明
idstring是消息唯一标识符
sessionIDstring是所属会话ID
role"assistant"是角色固定为 "assistant"
timeobject是时间信息
time.creatednumber-创建时间(Unix时间戳)
time.completednumber否完成时间(Unix时间戳)
errorError否错误信息
parentIDstring是父消息ID(对应的用户消息)
modelIDstring是使用的模型ID
providerIDstring是提供商ID
modestring是模式(已标记为废弃)
agentstring是Agent名称
pathobject是路径信息
path.cwdstring-当前工作目录
path.rootstring-项目根目录
summaryboolean否是否为摘要消息
costnumber是产生的成本(美元)
tokensobject是Token使用统计
tokens.inputnumber-输入Token数
tokens.outputnumber-输出Token数
tokens.reasoningnumber-推理Token数
tokens.cacheobject-缓存Token统计
tokens.cache.readnumber-读取缓存Token数
tokens.cache.writenumber-写入缓存Token数
finishstring否完成原因

TypeScript 类型定义

export type User = {
  id: string
  sessionID: string
  role: "user"
  time: {
    created: number
  }
  summary?: {
    title?: string
    body?: string
    diffs: FileDiff[]
  }
  agent: string
  model: {
    providerID: string
    modelID: string
  }
  system?: string
  tools?: Record<string, boolean>
  variant?: string
}

export type Assistant = {
  id: string
  sessionID: string
  role: "assistant"
  time: {
    created: number
    completed?: number
  }
  error?: AuthError | UnknownError | OutputLengthError | AbortedError | APIError
  parentID: string
  modelID: string
  providerID: string
  mode: string
  agent: string
  path: {
    cwd: string
    root: string
  }
  summary?: boolean
  cost: number
  tokens: {
    input: number
    output: number
    reasoning: number
    cache: {
      read: number
      write: number
    }
  }
  finish?: string
}

export type Message = User | Assistant

系统操作

创建消息

const messageID = Identifier.ascending("message")
const userMessage: MessageV2.User = {
  id: messageID,
  sessionID: session.id,
  role: "user",
  time: { created: Date.now() },
  agent: "fixer",
  model: { providerID: "anthropic", modelID: "claude-3-5-sonnet" },
}

await MessageV2.updateMessage(userMessage)

更新消息

await MessageV2.updateMessage(messageID, (draft) => {
  draft.time.completed = Date.now()
  draft.finish = "stop"
})

删除消息

await MessageV2.removeMessage({
  sessionID: session.id,
  messageID: messageID,
})

获取消息

const message = await MessageV2.get({
  sessionID: session.id,
  messageID: messageID,
})

流式读取消息

for await (const msg of MessageV2.stream(session.id)) {
  console.log(\`Message \${msg.info.id}: \${msg.info.role}\`)
  for (const part of msg.parts) {
    console.log(\`  - Part: \${part.type}\`)
  }
}

转换为 LLM 格式

const messages = await MessageV2.messages({ sessionID: session.id })
const modelMessages = MessageV2.toModelMessages(messages, model)

过滤已压缩消息

const messages = await MessageV2.messages({ sessionID: session.id })
const filtered = await MessageV2.filterCompacted(MessageV2.stream(session.id))

错误类型

Assistant Message 可能包含以下错误类型:

错误类型说明
AuthError提供商认证失败
UnknownError未知错误
OutputLengthError输出长度超出限制
AbortedError操作被中止
APIErrorAPI调用错误(可重试或不可重试)

Part 类型关联

每个 Message 包含 Part 数组,Part 类型详见 Part 文档。

Part 类型说明文档
TextPart文本内容Part
SubtaskPart子任务Part
ReasoningPart推理内容Part
FilePart文件内容Part
ToolPart工具调用Part
StepStartPart步骤开始Part
StepFinishPart步骤完成Part
SnapshotPart快照引用Part
PatchPart补丁信息Part
AgentPartAgent 切换Part
RetryPart重试操作Part
CompactionPart压缩标记Part

消息创建流程

存储键结构

;["message", sessionID, messageID]
;["part", messageID, partID]

典型使用场景

场景 1:创建带摘要的用户消息

const userMessage: MessageV2.User = {
  id: messageID,
  sessionID: session.id,
  role: "user",
  time: { created: Date.now() },
  agent: "fixer",
  model: { providerID: "anthropic", modelID: "claude-3-5-sonnet" },
  summary: {
    title: "修复登录 bug",
    body: "用户报告登录失败,需要修复认证逻辑",
  },
}

await MessageV2.updateMessage(userMessage)

场景 2:创建助手消息并跟踪 Token

const assistantMessage: MessageV2.Assistant = {
  id: assistantMessageID,
  sessionID: session.id,
  role: "assistant",
  time: { created: Date.now() },
  parentID: userMessageID,
  modelID: "claude-3-5-sonnet",
  providerID: "anthropic",
  agent: "fixer",
  path: {
    cwd: "/home/user/project",
    root: "/home/user/project",
  },
  cost: 0.0023,
  tokens: {
    input: 1200,
    output: 500,
    reasoning: 100,
    cache: {
      read: 50,
      write: 20,
    },
  },
}

await MessageV2.updateMessage(assistantMessage)

场景 3:流式读取和过滤

// 读取所有消息
const allMessages = []
for await (const msg of MessageV2.stream(session.id)) {
  allMessages.push(msg)
}

// 过滤已压缩的消息
const filteredMessages = []
for await (const msg of MessageV2.filterCompacted(MessageV2.stream(session.id))) {
  filteredMessages.push(msg)
}

console.log(\`Total messages: \${allMessages.length}\`)
console.log(\`Filtered messages: \${filteredMessages.length}\`)

对象关系

相关文档

  • Part - 消息部分详解
  • Session - 会话对象
  • Storage - 存储架构
  • Snapshot - 快照系统

变更历史

版本变更内容日期
v2引入MessageV2 架构,支持更细粒度的Part类型-