<!-- AI SUMMARY -->
## 快速了解

按 message.role 分发到用户、助手、工具、推理、活动、中断等消息组件。 源码位置：src/components/chat-message/message-render/message-render.vue。

### 关联组件
- **message-container** — 在 MessageContainer 中按组调用以渲染每条消息
- **assistant-message** — role 为 assistant 时渲染 AI 回复与工具调用
- **user-message** — role 为 user 时渲染用户消息
- **interrupt-message** — role 为 interrupt 时渲染 InterruptMessageRender

---
<!-- FULL DOC -->

# MessageRender 消息渲染器
## 源码事实

- **源码位置**：`src/components/chat-message/message-render/message-render.vue`
- **能力域**：消息系统
- **能力说明**：按 message.role 分发到用户、助手、工具、推理、活动、中断等消息组件。

> **能力域**：消息系统

统一的消息渲染入口，通过 `message.role` 字段自动派发到对应的子组件。整个渲染过程由一个 `computed` 属性完成，无额外状态。

## 渲染架构

```
MessageRender
│
├── props.message.role
│     │
│     ├── 'user'       → UserMessage（转发 message + onAction / onInputConfirm /
│     │                               onShortcutConfirm / messageToolsStatus / tippyOptions）
│     │
│     ├── 'assistant'  → AssistantMessage（转发 message + default slot）
│     │                    └── default slot 默认回退到 ContentRender
│     │
│     ├── 'info'       → InfoMessage（转发 message）
│     ├── 'reasoning'  → ReasoningMessage（转发 message）
│     ├── 'tool'       → ToolMessage（转发 message）
│     ├── 'activity'   → ActivityMessage（转发 message + onInterruptResume）
│     ├── 'loading'    → LoadingMessage（转发 message）
│     ├── 'interrupt'  → InterruptMessageRender（转发 message + onInterruptResume）
│     │
│     └── 其他 / 未知   → null（不渲染任何内容）
```

> **重要**：`onAction`、`onInputConfirm`、`onShortcutConfirm`、`messageToolsStatus`、`tippyOptions` 这五个 prop **只转发给 `UserMessage`**。`AssistantMessage` 的工具栏由 `MessageContainer` 的 `MessageTools` 组件管理，`MessageRender` 不负责传递。

## 基础用法

```vue
<template>
  <MessageRender
    :message="message"
    :on-action="handleAction"
  />
</template>

<script setup lang="ts">
  import { MessageRender, MessageRole, MessageStatus, type Message, type IToolBtn } from '@blueking/chat-x';

  const message = {
    id: '1',
    messageId: '1',
    role: MessageRole.Assistant,
    content: '你好！我是 AI 助手，有什么可以帮你的吗？',
    status: MessageStatus.Complete,
  };

  const handleAction = async (tool: IToolBtn) => {
    console.log('消息操作:', tool.id);
  };
</script>
```

**渲染效果**

## 各角色消息

### 用户消息（user）

`onAction`、`onInputConfirm`、`onShortcutConfirm`、`messageToolsStatus` 在此角色下生效。

```vue
<script setup lang="ts">
  import { MessageRole, MessageStatus, type Message, type IToolBtn, type TagSchema } from '@blueking/chat-x';

  const message = {
    id: '1',
    messageId: '1',
    role: MessageRole.User,
    content: '你好，请帮我解释一下什么是 Vue 3 的组合式 API',
    status: MessageStatus.Complete,
  };

  const handleAction = async (tool: IToolBtn) => {
    console.log('用户消息操作:', tool.id); // delete / copy 等
  };
  const handleInputConfirm = async (content: Message['content'], docSchema: TagSchema) => {
    console.log('编辑确认:', content);
  };
  const handleShortcutConfirm = async (formModel: Record<string, unknown>) => {
    console.log('快捷指令提交:', formModel);
  };
</script>
```

**渲染效果**

### AI 助手消息（assistant）

`message` 中的全部字段（含 `toolCalls`）直接透传给 `AssistantMessage`。

```vue
<script setup lang="ts">
  import { MessageRole, MessageStatus } from '@blueking/chat-x';

  const message = {
    id: '2',
    messageId: '2',
    role: MessageRole.Assistant,
    content: `## Vue 3 组合式 API\n\n**组合式 API** 是 Vue 3 引入的一种新方式...`,
    status: MessageStatus.Complete,
  };
</script>
```

**渲染效果**

### 信息消息（info）

`content` 为字符串或字符串数组，渲染居中虚线分隔条。

### 推理消息（reasoning）

`content` 为字符串数组，`duration` 为推理耗时（毫秒）。

### 工具调用结果（tool）

在 `MessageContainer` 中通常不独立渲染（被注入到 AssistantMessage），单独使用时如下：

### 活动消息（activity）

### 加载消息（loading）

由 `MessageContainer` 自动注入，无需手动使用。

## 消息状态

### 流式输出（streaming）

`status: 'streaming'` 时，`AssistantMessage` 内部展示打字光标，内容可实时追加：

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import { MessageRole, MessageStatus, type Message } from '@blueking/chat-x';

  const message = ref<Message>({
    id: '1',
    messageId: '1',
    role: MessageRole.Assistant,
    content: '',
    status: MessageStatus.Streaming,
  });

  // 模拟流式输出：逐步追加内容
  const chunks = ['正在', '为你', '生成', '答案...'];
  let i = 0;
  const timer = setInterval(() => {
    if (i < chunks.length) {
      message.value.content += chunks[i++];
    } else {
      message.value.status = MessageStatus.Complete;
      clearInterval(timer);
    }
  }, 300);
</script>
```

**渲染效果**

### 错误状态（error）

```vue
<script setup lang="ts">
  import { MessageRole, MessageStatus } from '@blueking/chat-x';

  const message = {
    id: '1',
    messageId: '1',
    role: MessageRole.Assistant,
    content: '抱歉，生成回答时发生了错误，请重试。',
    status: MessageStatus.Error,
  };
</script>
```

**渲染效果**

## 自定义内容渲染（default slot）

`default` slot **仅对 `role: 'assistant'` 生效**，用于替换默认的 `ContentRender`。未提供 slot 时回退渲染 `<ContentRender :content="message.content" :status="message.status" />`。

```vue
<template>
  <MessageRender
    :message="message"
    :on-action="handleAction"
  >
    <template #default="{ content, status }">
      <!-- 完全接管内容区域渲染 -->
      <MyMarkdownRenderer
        :content="content"
        :streaming="status === 'streaming'"
      />
    </template>
  </MessageRender>
</template>
```

slot 参数类型与 `AssistantMessage` 的 slot 保持一致（`Partial<AssistantMessage>`），主要使用：

| 参数      | 类型            | 说明         |
| --------- | --------------- | ------------ |
| `content` | `string`        | 消息内容     |
| `status`  | `MessageStatus` | 当前消息状态 |

## 与 MessageContainer 配合

在 `MessageContainer` 的 `default` slot 中使用，可替换默认的 `MessageRender` 渲染逻辑：

```vue
<template>
  <MessageContainer
    :messages="messages"
    :message-status="messageStatus"
    :on-agent-action="handleAgentAction"
    :on-user-action="handleUserAction"
    @stop-streaming="handleStopStreaming"
  >
    <template #default="{ message, messageToolsStatus }">
      <!-- 自定义 MessageRender 的行为 -->
      <MessageRender
        :message="message"
        :message-tools-status="messageToolsStatus"
        :on-action="handleUserAction"
        :on-input-confirm="handleInputConfirm"
      >
        <template
          v-if="message.role === 'assistant'"
          #default="{ content, status }"
        >
          <MyCustomContent
            :content="content"
            :status="status"
          />
        </template>
      </MessageRender>
    </template>
  </MessageContainer>
</template>
```

## API

### Props

| 属性名             | 类型                                                                       | 默认值 | 说明                                              |
| ------------------ | -------------------------------------------------------------------------- | ------ | ------------------------------------------------- |
| message            | `Partial<Message>`                                                         | —      | **必填**，消息对象，`role` 字段决定渲染哪个子组件 |
| messageToolsStatus | `MessageToolsStatus`                                                       | —      | 工具按钮状态；**仅转发给 `UserMessage`**          |
| onAction           | `(tool: IToolBtn) => Promise<string[] \| void>`                            | —      | 工具操作回调；**仅转发给 `UserMessage`**          |
| onInputConfirm     | `(content: UserMessage['content'], docSchema: TagSchema) => Promise<void>` | —      | 用户编辑确认回调；**仅转发给 `UserMessage`**      |
| onInterruptResume  | `(payload: InterruptResume, interrupt?: Interrupt) => Promise<void>`         | —      | 中断 / FlowAgent 节点操作回调；转发给 `InterruptMessageRender` 与 `ActivityMessage`（后者仅 `flow_agent` 子组件消费） |
| onShortcutConfirm  | `(formModel: Record<string, unknown>) => Promise<void>`                    | —      | 用户快捷指令提交回调；**仅转发给 `UserMessage`**  |
| tippyOptions       | `Partial<Omit<TippyOptions, 'getReferenceClientRect' \| 'triggerTarget'>>` | —      | 自定义 Tippy 配置；**仅转发给 `UserMessage`**     |

### Slots

| 插槽名           | 参数                                         | 说明                                                                                                    |
| ---------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| answeredQuestion | `{ item, index, status }`                    | 自定义 UserQuestion 已回答回显，透传给 InterruptMessageRender → UserQuestionAnsweredCard 的 `#answer`   |
| codeHeader       | `{ language: string; token: Token[] }`       | 代码块头部自定义操作区域，透传给 ContentRender → MarkdownContent → CodeContent；**仅对 assistant 生效** |
| default          | `{ content: string, status: MessageStatus }` | 替换 AssistantMessage 的内容区域渲染；**仅对 `role: 'assistant'` 生效**                                 |

## 消息类型映射

| `MessageRole` | 渲染组件           | prop 路由                                                                                               | 说明                  |
| ------------- | ------------------ | ------------------------------------------------------------------------------------------------------- | --------------------- |
| `user`        | `UserMessage`      | `message` + `onAction` + `onInputConfirm` + `onShortcutConfirm` + `messageToolsStatus` + `tippyOptions` | 用户发送的消息        |
| `assistant`   | `AssistantMessage` | `message` + `default slot`                                                                              | AI 助手回复消息       |
| `info`        | `InfoMessage`      | `message`                                                                                               | 系统信息 / 会话分隔符 |
| `reasoning`   | `ReasoningMessage` | `message`                                                                                               | AI 思考过程（可折叠） |
| `tool`        | `ToolMessage`      | `message`                                                                                               | 工具调用返回结果      |
| `activity`    | `ActivityMessage`  | `message` + `onInterruptResume`                                                                         | 知识检索 / 引用文档 / FlowAgent 执行（节点重试 / 跳过） |
| `loading`     | `LoadingMessage`   | `message`（字段被忽略，组件无 Props）                                                                   | 等待响应的加载占位    |
| `interrupt`   | `InterruptMessageRender` | `message` + `onInterruptResume`                                                                         | human-in-the-loop 中断 |
| 其他 / 未知   | —                  | —                                                                                                       | 返回 `null`，不渲染   |

## 类型定义

```typescript
import { MessageRole, MessageStatus, MessageToolsStatus, type Message, type IToolBtn } from '@blueking/chat-x';

// 消息角色
enum MessageRole {
  User = 'user',
  Assistant = 'assistant',
  Info = 'info',
  Reasoning = 'reasoning',
  Tool = 'tool',
  Activity = 'activity',
  Loading = 'loading',
}

// 消息状态
enum MessageStatus {
  Pending = 'pending',
  Streaming = 'streaming',
  Complete = 'complete',
  Error = 'error',
  Stop = 'stop',
  Disabled = 'disabled',
}

// 工具按钮状态（仅转发给 UserMessage）
enum MessageToolsStatus {
  Disabled = 'disabled',
  Hidden = 'hidden',
}
```

## 关联组件

- [MessageContainer](/components/setup/message-container) — 内部按组调用以渲染每条消息
- [AssistantMessage](/components/message/assistant-message) — assistant 角色派发目标
- [UserMessage](/components/message/user-message) — user 角色派发目标
- [InterruptMessage 中断消息](/components/agent/interrupt-message) — interrupt 角色派发目标
- [ToolApprovalCard 审批卡片](/components/agent/tool-approval-card) — AI Dev 审批中断子卡片