@blueking/chat-x 0.0.42 → 0.0.45-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/ag-ui/types/constants.d.ts +16 -0
- package/dist/ag-ui/types/contents.d.ts +0 -2
- package/dist/ag-ui/types/index.d.ts +2 -0
- package/dist/ag-ui/types/interrupt.d.ts +107 -0
- package/dist/ag-ui/types/messages.d.ts +2 -0
- package/dist/ag-ui/types/schema.d.ts +42 -0
- package/dist/components/ai-questions/questions-container.vue.d.ts +3 -0
- package/dist/components/ai-questions/selection-question.vue.d.ts +3 -0
- package/dist/components/chat-content/flow-agent-content/flow-agent-node-detail.vue.d.ts +0 -2
- package/dist/components/chat-input/ai-slash-input/ai-slash-input.vue.d.ts +1 -3
- package/dist/components/chat-input/chat-input.vue.d.ts +10 -9
- package/dist/components/chat-input/input-attachment/input-attachment.vue.d.ts +1 -0
- package/dist/components/chat-input/{ai-slash-input/ai-skill-list/ai-skill-list.vue.d.ts → input-info-alert.vue.d.ts} +1 -3
- package/dist/components/chat-message/interrupt-message/index.d.ts +2 -0
- package/dist/components/chat-message/interrupt-message/interrupt-message.vue.d.ts +17 -0
- package/dist/components/chat-message/interrupt-message/tool-approval-card.vue.d.ts +8 -0
- package/dist/components/chat-message/interrupt-message/user-question/index.d.ts +5 -0
- package/dist/components/chat-message/interrupt-message/user-question/use-user-question.d.ts +35 -0
- package/dist/components/chat-message/interrupt-message/user-question/user-question-answered-card.vue.d.ts +25 -0
- package/dist/components/chat-message/interrupt-message/user-question/user-question-card.vue.d.ts +25 -0
- package/dist/components/chat-message/interrupt-message/user-question/user-question-choice.vue.d.ts +13 -0
- package/dist/components/chat-message/interrupt-message/user-question/user-question-option.vue.d.ts +17 -0
- package/dist/components/chat-message/message-container/message-container.vue.d.ts +14 -7
- package/dist/components/chat-message/message-render/message-render.vue.d.ts +4 -0
- package/dist/components/index.d.ts +2 -6
- package/dist/composables/use-common.d.ts +1 -1
- package/dist/composables/use-custom-tab.d.ts +1 -1
- package/dist/composables/use-message-group.d.ts +2004 -224
- package/dist/directives/overflow-tips.d.ts +1 -1
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/interrupt.d.ts +24 -0
- package/dist/index.css +1 -1
- package/dist/index.js +5906 -5346
- package/dist/index.js.map +1 -1
- package/dist/lang/lang.d.ts +33 -2
- package/dist/mcp/generated/docs/activity-layout.md +138 -0
- package/dist/mcp/generated/docs/activity-message.md +18 -28
- package/dist/mcp/generated/docs/ai-image.md +9 -4
- package/dist/mcp/generated/docs/ai-loading.md +11 -6
- package/dist/mcp/generated/docs/ai-prompt-list.md +42 -0
- package/dist/mcp/generated/docs/ai-selection.md +10 -5
- package/dist/mcp/generated/docs/ai-slash-editor.md +43 -0
- package/dist/mcp/generated/docs/ai-slash-input.md +43 -0
- package/dist/mcp/generated/docs/ai-slash-menu.md +42 -0
- package/dist/mcp/generated/docs/animation-text.md +9 -4
- package/dist/mcp/generated/docs/assistant-message.md +10 -5
- package/dist/mcp/generated/docs/chat-container.md +136 -68
- package/dist/mcp/generated/docs/chat-input.md +45 -9
- package/dist/mcp/generated/docs/cite-content.md +8 -3
- package/dist/mcp/generated/docs/code-content.md +9 -4
- package/dist/mcp/generated/docs/common-error-content.md +10 -5
- package/dist/mcp/generated/docs/constants.md +68 -3
- package/dist/mcp/generated/docs/content-render.md +10 -5
- package/dist/mcp/generated/docs/delete-tool.md +9 -4
- package/dist/mcp/generated/docs/desc-panel.md +9 -4
- package/dist/mcp/generated/docs/detail-section.md +93 -0
- package/dist/mcp/generated/docs/execution-summary.md +10 -5
- package/dist/mcp/generated/docs/file-content.md +9 -4
- package/dist/mcp/generated/docs/file-upload-btn.md +11 -6
- package/dist/mcp/generated/docs/flow-agent-content.md +212 -0
- package/dist/mcp/generated/docs/flow-agent-node-detail.md +240 -0
- package/dist/mcp/generated/docs/highlight-keyword.md +10 -5
- package/dist/mcp/generated/docs/image-content.md +9 -4
- package/dist/mcp/generated/docs/image-preview-group.md +9 -4
- package/dist/mcp/generated/docs/image-preview.md +10 -5
- package/dist/mcp/generated/docs/info-message.md +7 -2
- package/dist/mcp/generated/docs/input-attachment.md +43 -0
- package/dist/mcp/generated/docs/input-info-alert.md +42 -0
- package/dist/mcp/generated/docs/interrupt-message.md +204 -0
- package/dist/mcp/generated/docs/interrupt.md +282 -0
- package/dist/mcp/generated/docs/key-value-content.md +9 -4
- package/dist/mcp/generated/docs/knowledge-rag-content.md +126 -0
- package/dist/mcp/generated/docs/latex-content.md +9 -4
- package/dist/mcp/generated/docs/loading-message.md +11 -6
- package/dist/mcp/generated/docs/markdown-container.md +1 -1
- package/dist/mcp/generated/docs/markdown-content.md +13 -31
- package/dist/mcp/generated/docs/markdown-latex.md +3 -3
- package/dist/mcp/generated/docs/markdown-mermaid.md +3 -3
- package/dist/mcp/generated/docs/mermaid-content.md +9 -4
- package/dist/mcp/generated/docs/message-container.md +70 -12
- package/dist/mcp/generated/docs/message-loading.md +120 -0
- package/dist/mcp/generated/docs/message-render.md +21 -9
- package/dist/mcp/generated/docs/message-tools.md +10 -5
- package/dist/mcp/generated/docs/messages.md +75 -11
- package/dist/mcp/generated/docs/overflow-tips.md +4 -4
- package/dist/mcp/generated/docs/preview-toolbar.md +42 -0
- package/dist/mcp/generated/docs/questions-container.md +88 -0
- package/dist/mcp/generated/docs/reasoning-message.md +10 -5
- package/dist/mcp/generated/docs/reference-content.md +10 -5
- package/dist/mcp/generated/docs/reference-doc-content.md +112 -0
- package/dist/mcp/generated/docs/schema.md +93 -0
- package/dist/mcp/generated/docs/scroll-btn.md +8 -3
- package/dist/mcp/generated/docs/selection-footer.md +9 -4
- package/dist/mcp/generated/docs/selection-question.md +91 -0
- package/dist/mcp/generated/docs/shortcut-btn.md +10 -5
- package/dist/mcp/generated/docs/shortcut-btns.md +10 -5
- package/dist/mcp/generated/docs/shortcut-render.md +11 -10
- package/dist/mcp/generated/docs/simple-table.md +103 -0
- package/dist/mcp/generated/docs/text-content.md +9 -4
- package/dist/mcp/generated/docs/theme.md +3 -3
- package/dist/mcp/generated/docs/tool-approval-card.md +148 -0
- package/dist/mcp/generated/docs/tool-btn.md +9 -4
- package/dist/mcp/generated/docs/tool-message.md +10 -5
- package/dist/mcp/generated/docs/toolcall-render.md +10 -5
- package/dist/mcp/generated/docs/use-animation-text.md +4 -4
- package/dist/mcp/generated/docs/use-clipboard.md +3 -3
- package/dist/mcp/generated/docs/use-command-selection.md +1 -1
- package/dist/mcp/generated/docs/use-custom-tab.md +1 -1
- package/dist/mcp/generated/docs/use-global-config.md +1 -1
- package/dist/mcp/generated/docs/use-menu-keydown.md +1 -1
- package/dist/mcp/generated/docs/use-message-group.md +40 -9
- package/dist/mcp/generated/docs/use-observer-visible-list.md +1 -1
- package/dist/mcp/generated/docs/user-feedback.md +8 -3
- package/dist/mcp/generated/docs/user-message.md +10 -5
- package/dist/mcp/generated/docs/user-question-answered-card.md +106 -0
- package/dist/mcp/generated/docs/user-question-card.md +211 -0
- package/dist/mcp/generated/docs/user-question-choice.md +108 -0
- package/dist/mcp/generated/docs/user-question-option.md +42 -0
- package/dist/mcp/generated/docs/vnode-renderer.md +126 -0
- package/dist/mcp/generated/index.json +1061 -532
- package/dist/mcp/index.js +0 -0
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/list-components.d.ts +7 -6
- package/dist/mcp/tools/list-components.js +23 -29
- package/dist/mcp/tools/list-components.js.map +1 -1
- package/dist/mcp/tools/search-docs.js +1 -1
- package/dist/mcp/tools/search-docs.js.map +1 -1
- package/dist/mcp/utils/doc-loader.d.ts +1 -1
- package/dist/plugins/index.d.ts +0 -1
- package/dist/types/custom.d.ts +0 -1
- package/dist/types/editor.d.ts +0 -6
- package/dist/types/input.d.ts +1 -1
- package/dist/types/tool.d.ts +2 -2
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/utils.d.ts +0 -1
- package/package.json +23 -21
- package/dist/plugins/markdown-bk-inline-style.d.ts +0 -20
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
渲染 UserQuestion 中断的待回答面板,支持单选、多选、Others 与跳过。 源码位置:src/components/chat-message/interrupt-message/user-question/user-question-card.vue。
|
|
5
|
+
|
|
6
|
+
### 关联组件
|
|
7
|
+
- **interrupt-message** — outcome.success 时挂载 UserQuestionAnsweredCard 回显回答
|
|
8
|
+
- **chat-container** — 检测最近待回答 UserQuestion 并把 UserQuestionCard 放在输入区上方
|
|
9
|
+
- **interrupt** — 定义 UserQuestionInterrupt 与 UserQuestionResume 协议
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
<!-- FULL DOC -->
|
|
13
|
+
|
|
14
|
+
# UserQuestionCard 用户问题中断
|
|
15
|
+
## 源码事实
|
|
16
|
+
|
|
17
|
+
- **源码位置**:`src/components/chat-message/interrupt-message/user-question/user-question-card.vue`
|
|
18
|
+
- **能力域**:Agent 能力
|
|
19
|
+
- **能力说明**:渲染 UserQuestion 中断的待回答面板,支持单选、多选、Others 与跳过。
|
|
20
|
+
|
|
21
|
+
> **能力域**:Agent 能力
|
|
22
|
+
|
|
23
|
+
`UserQuestionCard` 用于渲染 `InterruptReason.UserQuestion`(`'aidev:user_question'`)中断。它通常由 `ChatContainer` 自动挂载到 `ChatInput` 上方,用户回答后通过 `onInterruptResume(payload, interrupt)` 回传 `UserQuestionResume`。
|
|
24
|
+
|
|
25
|
+
## 交互能力
|
|
26
|
+
|
|
27
|
+
- **单选 / 多选**:每道题通过 `multiSelect` 控制选择行为;未传时不展示单选/多选标签,默认仍按单选处理。
|
|
28
|
+
- **Others 自由输入**:默认 [UserQuestionChoice](/components/agent/user-question-choice) 为每道题追加 `label: 'others'` 输入项,输入文本写入 `answer[].description`。
|
|
29
|
+
- **自定义作答形态**:通过 `#question` slot 可替换默认选择题,渲染任意表单;作答有效时调用 `setAnswer` 回传 `UserQuestionAnswerItem`,无效时传 `undefined`。
|
|
30
|
+
- **完成校验**:所有题目均已作答(`setAnswer` 收到有效答案)后才允许点击「完成」。
|
|
31
|
+
- **跳过**:点击「跳过」返回 `status: 'cancelled'` 与空 `answers`。
|
|
32
|
+
- **自由文本兜底**:当存在待回答 UserQuestion 且业务配置了 `onInterruptResume` 时,用户也可以直接在 `ChatInput` 输入文本;容器会将文本转换为单条 Others 回答。
|
|
33
|
+
|
|
34
|
+
## 数据协议
|
|
35
|
+
|
|
36
|
+
待回答中断:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const interrupt = {
|
|
40
|
+
id: 'interrupt_user_question',
|
|
41
|
+
reason: InterruptReason.UserQuestion,
|
|
42
|
+
toolCallId: 'tool_call_user_question',
|
|
43
|
+
message: '请选择实现方案',
|
|
44
|
+
metadata: {
|
|
45
|
+
questions: [
|
|
46
|
+
{
|
|
47
|
+
header: '请选择实现方案',
|
|
48
|
+
multiSelect: false,
|
|
49
|
+
question: '你希望采用哪种冒泡排序实现?',
|
|
50
|
+
options: [
|
|
51
|
+
{ label: 'basic', description: '基础冒泡排序' },
|
|
52
|
+
{ label: 'optimized', description: '优化版冒泡排序' },
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
完成回答后生成的 resume:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const payload = {
|
|
64
|
+
interruptId: 'interrupt_user_question',
|
|
65
|
+
reason: InterruptReason.UserQuestion,
|
|
66
|
+
status: 'resolved',
|
|
67
|
+
payload: {
|
|
68
|
+
answers: [
|
|
69
|
+
{
|
|
70
|
+
question: '你希望采用哪种冒泡排序实现?',
|
|
71
|
+
multiSelect: false,
|
|
72
|
+
answer: [{ label: 'optimized', description: '优化版冒泡排序' }],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 基础用法
|
|
80
|
+
|
|
81
|
+
> 业务侧通常不直接使用本组件;推荐构造 `InterruptMessage` 后交给 `ChatContainer` / `MessageContainer` 渲染。下面示例用于说明组件 API 和 payload 形状。
|
|
82
|
+
|
|
83
|
+
```vue
|
|
84
|
+
<template>
|
|
85
|
+
<UserQuestionCard
|
|
86
|
+
:interrupt="pendingInterrupt"
|
|
87
|
+
:on-resume="handleResume"
|
|
88
|
+
/>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
import { InterruptReason, UserQuestionCard, type OnInterruptResume } from '@blueking/chat-x';
|
|
93
|
+
|
|
94
|
+
const pendingInterrupt = {
|
|
95
|
+
id: 'interrupt_user_question',
|
|
96
|
+
reason: InterruptReason.UserQuestion,
|
|
97
|
+
toolCallId: 'tool_call_user_question',
|
|
98
|
+
metadata: {
|
|
99
|
+
questions: [
|
|
100
|
+
{
|
|
101
|
+
header: '请选择实现方案',
|
|
102
|
+
multiSelect: false,
|
|
103
|
+
question: '你希望采用哪种实现?',
|
|
104
|
+
options: [{ label: 'basic', description: '基础冒泡排序' }],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleResume: OnInterruptResume = async (payload, interrupt) => {
|
|
111
|
+
console.log(interrupt.id, payload);
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**渲染效果**
|
|
117
|
+
|
|
118
|
+
## 已回答回显
|
|
119
|
+
|
|
120
|
+
`InterruptMessageRender` 在 `content.outcome.type === 'success'` 且 `content.result.reason === InterruptReason.UserQuestion` 时,会在会话内渲染 `UserQuestionAnsweredCard`。
|
|
121
|
+
|
|
122
|
+
```vue
|
|
123
|
+
<UserQuestionAnsweredCard
|
|
124
|
+
:answers="answers"
|
|
125
|
+
status="resolved"
|
|
126
|
+
/>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**渲染效果**
|
|
130
|
+
|
|
131
|
+
## ChatContainer 自动挂载
|
|
132
|
+
|
|
133
|
+
`ChatContainer` 内部通过 `useMessageGroup` 查找最近一条 `outcome.type === 'interrupt'` 的 `UserQuestion`,并在 `ChatInput` 的 `#interrupt` 插槽中渲染 `UserQuestionCard`:
|
|
134
|
+
|
|
135
|
+
```vue
|
|
136
|
+
<ChatContainer
|
|
137
|
+
v-model="inputValue"
|
|
138
|
+
:messages="messages"
|
|
139
|
+
:on-interrupt-resume="handleResume"
|
|
140
|
+
:on-send-message="handleSendMessage"
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
如果没有配置 `onInterruptResume`,自由文本输入不会被截获,仍按普通 `onSendMessage` 发送,避免用户输入被静默清空。
|
|
145
|
+
|
|
146
|
+
## 自定义题目渲染(#question slot)
|
|
147
|
+
|
|
148
|
+
默认每道题由 [UserQuestionChoice](/components/agent/user-question-choice) 渲染;业务可覆盖 `#question` slot 接入自定义表单:
|
|
149
|
+
|
|
150
|
+
```vue
|
|
151
|
+
<template>
|
|
152
|
+
<UserQuestionCard
|
|
153
|
+
:interrupt="pendingInterrupt"
|
|
154
|
+
:on-resume="handleResume"
|
|
155
|
+
>
|
|
156
|
+
<template #question="{ question, qIndex, answer, setAnswer, confirm }">
|
|
157
|
+
<!-- 自定义表单:作答有效时 setAnswer(answerItem),无效时 setAnswer(undefined) -->
|
|
158
|
+
<MyCustomForm
|
|
159
|
+
:model="question"
|
|
160
|
+
@change="setAnswer"
|
|
161
|
+
@submit="confirm"
|
|
162
|
+
/>
|
|
163
|
+
</template>
|
|
164
|
+
</UserQuestionCard>
|
|
165
|
+
</template>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`ChatContainer` 提供同名 `#interruptQuestion` slot,参数与 `#question` 一致,透传自输入区上方的 `UserQuestionCard`。
|
|
169
|
+
|
|
170
|
+
## API
|
|
171
|
+
|
|
172
|
+
### UserQuestionCard Props
|
|
173
|
+
|
|
174
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
175
|
+
| --------- | ----------------------- | ------ | -------------------------------------- |
|
|
176
|
+
| interrupt | `UserQuestionInterrupt` | — | **必填**,含 `metadata.questions` |
|
|
177
|
+
| onResume | `OnInterruptResume` | — | 完成 / 跳过时触发,签名为 `(payload, interrupt)` |
|
|
178
|
+
|
|
179
|
+
### UserQuestionAnsweredCard Props
|
|
180
|
+
|
|
181
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
182
|
+
| ------- | ---------------------------- | ------------ | ---------------------------- |
|
|
183
|
+
| answers | `UserQuestionAnswerItem[]` | — | 已回答内容列表 |
|
|
184
|
+
| status | `'resolved' \| 'cancelled'` | `'resolved'` | 回显状态,决定展示已回复/已取消 |
|
|
185
|
+
|
|
186
|
+
### UserQuestionCard Slots
|
|
187
|
+
|
|
188
|
+
| 插槽名 | 参数 | 说明 |
|
|
189
|
+
| -------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
190
|
+
| question | `{ question, qIndex, answer, setAnswer, confirm }` | 自定义单题渲染;未覆盖时回退 [UserQuestionChoice](/components/agent/user-question-choice) |
|
|
191
|
+
|
|
192
|
+
slot 参数说明:
|
|
193
|
+
|
|
194
|
+
| 参数 | 类型 | 说明 |
|
|
195
|
+
| ---------- | ------------------------------------------------- | ---------------------------------------------- |
|
|
196
|
+
| question | `UserQuestionItem` | 原始题目数据 |
|
|
197
|
+
| qIndex | `number` | 题目序号(从 0 开始) |
|
|
198
|
+
| answer | `UserQuestionAnswerItem \| undefined` | 当前题已组装答案,`undefined` 表示未作答 |
|
|
199
|
+
| setAnswer | `(answer: UserQuestionAnswerItem \| undefined) => void` | 写入/清空当前题答案 |
|
|
200
|
+
| confirm | `() => void` | 触发「完成」,等价点击底部完成按钮(需全部已答) |
|
|
201
|
+
|
|
202
|
+
### Events / Expose
|
|
203
|
+
|
|
204
|
+
无。
|
|
205
|
+
|
|
206
|
+
## 关联文档
|
|
207
|
+
|
|
208
|
+
- [中断类型 Interrupt](../../types/interrupt.md)
|
|
209
|
+
- [UserQuestionChoice 选择题](/components/agent/user-question-choice)
|
|
210
|
+
- [InterruptMessage 中断消息](/components/agent/interrupt-message)
|
|
211
|
+
- [ChatContainer 聊天容器](/components/setup/chat-container)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
UserQuestionCard 默认的选择题渲染组件,封装单选/多选、Others 输入与答案组装。 源码位置:src/components/chat-message/interrupt-message/user-question/user-question-choice.vue。
|
|
5
|
+
|
|
6
|
+
### 关联组件
|
|
7
|
+
- **user-question-card** — 默认通过
|
|
8
|
+
- **user-question-option** — 内部逐条渲染选项行
|
|
9
|
+
- **interrupt** — 答案结构遵循 UserQuestionAnswerItem
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
<!-- FULL DOC -->
|
|
13
|
+
|
|
14
|
+
# UserQuestionChoice 用户问题选择题
|
|
15
|
+
|
|
16
|
+
> **能力域**:Agent 能力
|
|
17
|
+
|
|
18
|
+
## 源码事实
|
|
19
|
+
|
|
20
|
+
- **源码位置**:`src/components/chat-message/interrupt-message/user-question/user-question-choice.vue`
|
|
21
|
+
- **能力说明**:封装 UserQuestion 的选择题交互,负责选项归一化、单选/多选切换、Others 输入校验与 `UserQuestionAnswerItem` 组装。
|
|
22
|
+
|
|
23
|
+
`UserQuestionChoice` 是 [UserQuestionCard](/components/agent/user-question-card) 在 `#question` slot 未覆盖时的**默认渲染**。业务侧也可单独使用,配合 `useUserQuestion` 的 `setAnswer` 接入自定义面板。
|
|
24
|
+
|
|
25
|
+
## 交互能力
|
|
26
|
+
|
|
27
|
+
- **单选 / 多选**:由 `question.multiSelect` 控制;未传时不展示单选/多选标签,但仍按单选行为处理。
|
|
28
|
+
- **Others 自由输入**:前端自动在选项末尾追加 `label: 'others'` 输入项。
|
|
29
|
+
- **实时同步答案**:选择或输入变化时 emit `answer`;作答有效时回传已组装的 `UserQuestionAnswerItem`,无效时回传 `undefined`。
|
|
30
|
+
- **Enter 确认**:Others 输入框按 Enter 触发 `confirm`,等价于点击「完成」按钮(需上层已全部作答)。
|
|
31
|
+
|
|
32
|
+
## 基础用法(单选)
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<template>
|
|
36
|
+
<UserQuestionChoice
|
|
37
|
+
:question="singleQuestion"
|
|
38
|
+
@answer="handleAnswer"
|
|
39
|
+
@confirm="handleConfirm"
|
|
40
|
+
/>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup lang="ts">
|
|
44
|
+
import { UserQuestionChoice, type UserQuestionAnswerItem } from '@blueking/chat-x';
|
|
45
|
+
|
|
46
|
+
const singleQuestion = {
|
|
47
|
+
header: '请选择实现方案',
|
|
48
|
+
multiSelect: false,
|
|
49
|
+
question: '你希望采用哪种冒泡排序实现?',
|
|
50
|
+
options: [
|
|
51
|
+
{ label: 'basic', description: '基础冒泡排序' },
|
|
52
|
+
{ label: 'optimized', description: '优化版冒泡排序' },
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleAnswer = (answer: UserQuestionAnswerItem | undefined) => {
|
|
57
|
+
console.log(answer);
|
|
58
|
+
};
|
|
59
|
+
</script>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**渲染效果**
|
|
63
|
+
|
|
64
|
+
## 多选
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<UserQuestionChoice
|
|
68
|
+
:question="multiQuestion"
|
|
69
|
+
@answer="handleAnswer"
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**渲染效果**
|
|
74
|
+
|
|
75
|
+
## 在 UserQuestionCard 中使用
|
|
76
|
+
|
|
77
|
+
通常无需直接使用本组件;`UserQuestionCard` 默认已在 `#question` slot 回退中挂载:
|
|
78
|
+
|
|
79
|
+
```vue
|
|
80
|
+
<UserQuestionCard :interrupt="interrupt" :on-resume="handleResume" />
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
如需替换某一题的渲染,覆盖 `#question` slot 即可;未覆盖时仍回退到 `UserQuestionChoice`。
|
|
84
|
+
|
|
85
|
+
## API
|
|
86
|
+
|
|
87
|
+
### Props
|
|
88
|
+
|
|
89
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
90
|
+
| -------- | ------------------ | ------ | ---------------------------- |
|
|
91
|
+
| question | `UserQuestionItem` | — | **必填**,含 `options` 等字段 |
|
|
92
|
+
|
|
93
|
+
### Events
|
|
94
|
+
|
|
95
|
+
| 事件名 | 参数 | 说明 |
|
|
96
|
+
| ------- | ----------------------------------------- | ------------------------------------------------------------ |
|
|
97
|
+
| answer | `(answer: UserQuestionAnswerItem \| undefined)` | 作答变化;有效时回传已组装答案,无效(未选/ Others 空)时 `undefined` |
|
|
98
|
+
| confirm | — | 用户在 Others 输入框按 Enter 时触发,上层可绑定「完成」逻辑 |
|
|
99
|
+
|
|
100
|
+
### Slots / Expose
|
|
101
|
+
|
|
102
|
+
无。
|
|
103
|
+
|
|
104
|
+
## 关联文档
|
|
105
|
+
|
|
106
|
+
- [UserQuestionCard 用户问题中断](/components/agent/user-question-card)
|
|
107
|
+
- [UserQuestionOption 用户问题选项](/components/agent/user-question-option)
|
|
108
|
+
- [中断类型 Interrupt](../../types/interrupt.md)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
UserQuestionChoice 内部选项行,处理单选/多选状态和 Others 输入。 源码位置:src/components/chat-message/interrupt-message/user-question/user-question-option.vue。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
<!-- FULL DOC -->
|
|
8
|
+
|
|
9
|
+
# UserQuestionOption 用户问题选项
|
|
10
|
+
|
|
11
|
+
> **能力域**:Agent 能力
|
|
12
|
+
|
|
13
|
+
## 源码事实
|
|
14
|
+
|
|
15
|
+
- **源码位置**:`src/components/chat-message/interrupt-message/user-question/user-question-option.vue`
|
|
16
|
+
- **能力说明**:UserQuestionChoice 内部选项行,处理单选/多选状态和 Others 输入。
|
|
17
|
+
|
|
18
|
+
## API 摘要
|
|
19
|
+
|
|
20
|
+
### Props
|
|
21
|
+
|
|
22
|
+
- `{ option: NormalizedUserQuestionOption; othersText?: string; selected: boolean; }`
|
|
23
|
+
|
|
24
|
+
### Emits
|
|
25
|
+
|
|
26
|
+
- `{ (e: 'confirm'): void; (e: 'select'): void; (e: 'update:othersText', value: string): void; }`
|
|
27
|
+
|
|
28
|
+
### Slots
|
|
29
|
+
|
|
30
|
+
- 无。
|
|
31
|
+
|
|
32
|
+
### Expose
|
|
33
|
+
|
|
34
|
+
- 无。
|
|
35
|
+
|
|
36
|
+
## 组件依赖
|
|
37
|
+
|
|
38
|
+
- 无组件依赖或仅依赖基础库。
|
|
39
|
+
|
|
40
|
+
## 使用建议
|
|
41
|
+
|
|
42
|
+
- 优先通过 [UserQuestionChoice](/components/agent/user-question-choice) 或 [UserQuestionCard](/components/agent/user-question-card) 使用;直接使用前请确认 props 数据结构来自对应类型定义。
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!-- AI SUMMARY -->
|
|
2
|
+
## 快速了解
|
|
3
|
+
|
|
4
|
+
将 Markdown token 转成 VNode 的内部渲染桥。 源码位置:src/components/chat-content/vnode-renderer.ts。
|
|
5
|
+
|
|
6
|
+
### 关联组件
|
|
7
|
+
- **markdown-content** — MarkdownContent 对普通 token 分组使用本组件渲染
|
|
8
|
+
- **code-content** — fence/code_block 代码块通常会被 MarkdownContent 提前分流到 CodeContent
|
|
9
|
+
- **mermaid-content** — mermaid 代码块通常会被 MarkdownContent 提前分流到 MermaidContent
|
|
10
|
+
- **image-content** — 图片 token 由 tokensToVNodes 转为 ImageContent
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
<!-- FULL DOC -->
|
|
14
|
+
|
|
15
|
+
# VNodeRenderer VNode 渲染器
|
|
16
|
+
|
|
17
|
+
> **能力域**:辅助能力
|
|
18
|
+
|
|
19
|
+
`VNodeRenderer` 是 Markdown 渲染链路里的内部桥接组件。它接收 markdown-it 解析出的 `Token[]`,调用 `tokensToVNodes` 转成 Vue VNode,并返回渲染函数结果。
|
|
20
|
+
|
|
21
|
+
通常不需要业务侧直接使用。完整 Markdown 内容请优先使用 [MarkdownContent](../rendering/markdown-content.md),它会先识别 Mermaid、LaTeX、代码块等特殊 token,再把普通 token 分组交给 `VNodeRenderer`。
|
|
22
|
+
|
|
23
|
+
## 源码事实
|
|
24
|
+
|
|
25
|
+
- **源码位置**:`src/components/chat-content/vnode-renderer.ts`
|
|
26
|
+
- **能力说明**:将 Markdown token 转成 VNode 的内部渲染桥。
|
|
27
|
+
|
|
28
|
+
## 核心能力
|
|
29
|
+
|
|
30
|
+
- **Token 到 VNode**:将 markdown-it 的 block、inline、text、link、image、html 等 token 转为 Vue VNode
|
|
31
|
+
- **稳定 key**:`tokensToVNodes` 基于 token 类型、标签和内容 hash 生成 key,降低流式渲染时 DOM 误复用风险
|
|
32
|
+
- **HTML 安全入口**:`options.html` 开启时可渲染 HTML token,实际安全过滤依赖 `options.sanitize`
|
|
33
|
+
- **渲染规则复用**:支持传入 markdown-it `renderer` 与 `mditOptions`,复用自定义 renderer rule
|
|
34
|
+
- **特殊 token 兜底**:图片 token 转成 `ImageContent`,链接自动补充 `target="_blank"` 与 `rel="noopener noreferrer"`
|
|
35
|
+
|
|
36
|
+
## 基础用法
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<template>
|
|
40
|
+
<VNodeRenderer :tokens="tokens" />
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup lang="ts">
|
|
44
|
+
import MarkdownIt from '@blueking/chat-x/src/markdown-it/index';
|
|
45
|
+
import VNodeRenderer from '@blueking/chat-x/src/components/chat-content/vnode-renderer';
|
|
46
|
+
|
|
47
|
+
const md = new MarkdownIt();
|
|
48
|
+
const tokens = md.parse('这是一段 **加粗文本**。', {});
|
|
49
|
+
</script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**渲染效果**
|
|
53
|
+
|
|
54
|
+
## 空 Tokens
|
|
55
|
+
|
|
56
|
+
`tokens` 为空数组时,`tokensToVNodes` 返回空数组,不渲染任何内容。
|
|
57
|
+
|
|
58
|
+
## 与 MarkdownContent 的关系
|
|
59
|
+
|
|
60
|
+
`MarkdownContent` 会先按 token 类型分流,再将普通 token 交给 `VNodeRenderer`:
|
|
61
|
+
|
|
62
|
+
```vue
|
|
63
|
+
<template v-else>
|
|
64
|
+
<VNodeRenderer
|
|
65
|
+
:options="vnodeOptions"
|
|
66
|
+
:tokens="groupedToken"
|
|
67
|
+
/>
|
|
68
|
+
</template>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
其中 `vnodeOptions` 会携带 HTML 净化函数、markdown-it renderer 和 parser options:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const vnodeOptions = {
|
|
75
|
+
html: true,
|
|
76
|
+
mditOptions: md.options,
|
|
77
|
+
renderer: md.renderer,
|
|
78
|
+
sanitize: (html: string) => dompurify.sanitize(html, domPurifyConfig),
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API
|
|
83
|
+
|
|
84
|
+
### Props
|
|
85
|
+
|
|
86
|
+
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
|
|
87
|
+
| ------- | --------------------- | ---- | ------ | ---------------------------- |
|
|
88
|
+
| tokens | `Token[]` | 是 | — | markdown-it token 数组 |
|
|
89
|
+
| options | `TokenToVNodeOptions` | 否 | `{}` | token 转 VNode 的渲染选项 |
|
|
90
|
+
|
|
91
|
+
### Emits
|
|
92
|
+
|
|
93
|
+
- 无。
|
|
94
|
+
|
|
95
|
+
### Slots
|
|
96
|
+
|
|
97
|
+
- 无。
|
|
98
|
+
|
|
99
|
+
### Expose
|
|
100
|
+
|
|
101
|
+
- 无。
|
|
102
|
+
|
|
103
|
+
## 类型定义
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
export interface TokenToVNodeOptions {
|
|
107
|
+
highlight?: ((str: string, lang: string, attrs?: unknown) => string) | null;
|
|
108
|
+
html?: boolean;
|
|
109
|
+
mditOptions?: Options;
|
|
110
|
+
renderer?: Renderer;
|
|
111
|
+
sanitize?: (html: string) => string;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 使用建议
|
|
116
|
+
|
|
117
|
+
- 业务侧不要绕过 `MarkdownContent` 直接渲染完整 Markdown 字符串;`VNodeRenderer` 只接收已经解析好的 token。
|
|
118
|
+
- 如果启用 `options.html`,必须同步传入 `sanitize`,否则 HTML token 会直接进入 `innerHTML`。
|
|
119
|
+
- 特殊内容如代码块、Mermaid、LaTeX 推荐继续走 `MarkdownContent` 的分流逻辑。
|
|
120
|
+
|
|
121
|
+
## 关联组件
|
|
122
|
+
|
|
123
|
+
- [MarkdownContent](../rendering/markdown-content.md) — Markdown 主渲染器。
|
|
124
|
+
- [CodeContent](../rendering/code-content.md) — 代码块渲染。
|
|
125
|
+
- [MermaidContent](../rendering/mermaid-content.md) — Mermaid 图表渲染。
|
|
126
|
+
- [ImageContent](../medias/image-content.md) — 图片 token 渲染。
|