Skip to content

Commit a96f3f8

Browse files
authored
Merge pull request #1813 from Mai-with-u/dev
1.0.3 发布准备
2 parents 0a6c324 + 5d8fe00 commit a96f3f8

147 files changed

Lines changed: 15580 additions & 8572 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

changelogs/changelog.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@
22

33
测试版更新日志见 [changelog_dev.md](changelog_dev.md)
44

5+
# [1.0.3] - 2026-6-14
6+
7+
## 用户感知功能侧
8+
9+
### Maisaka
10+
11+
- 新增聊天配置“自身消息特殊标注”,会在上下文中更明确标出麦麦自己发送的消息,减少模型把自己说过的话认成其他用户发言的情况。
12+
- 优化中期记忆与 Maisaka 上下文处理,减少无关历史消息进入回复链路,让长对话中的上下文引用更稳定。
13+
- 优化行为学习的场景匹配、反馈沉淀与行为参考表达,让麦麦更容易复用有效经验,并降低行为参考对回复风格的干扰。
14+
15+
### WebUI / Dashboard
16+
17+
- 聊天页新增头像缓存与展示支持,聊天列表、顶部栏和消息流会更稳定地显示用户与聊天对象头像。
18+
- 推理过程页面增强记录筛选、动作筛选、结构化 prompt 展示、工具调用折叠和消息头像映射,排查回复过程时更容易定位关键上下文。
19+
- 插件详情页 README 加载体验优化,切换插件时内容刷新更稳定;复古主题底纹显示效果也做了微调。
20+
21+
## 开发侧 / 修复
22+
23+
### WebUI 架构
24+
25+
- WebUI 多个页面继续下沉页面状态与数据请求逻辑,统一 API 抛错契约,并补充关键页面的特征化测试;这部分主要是内部架构整理,对用户功能入口影响较小。
26+
27+
### 调试与实验
28+
29+
- 新增行为学习相关离线 abtest 脚本,用于对比场景 embedding 匹配、学习合并与摘要字段效果,方便后续继续调优行为系统。
30+
531
# [1.0.2] - 2026-6-13
632

733
## 用户感知功能侧

dashboard/CONTEXT.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@ _Avoid_: ApiResponse(迁移期遗留的判别联合,最终淘汰)
4343
对服务端集合的「分页 + 搜索 + 筛选 + 多选」视图,由 `useDataList` hook 统一承载。hook 内部包一个列表 **查询**(queryKey 从分页/搜索/筛选状态派生),对外给出 items/total 与全部控件状态;筛选/搜索/翻页变化时自动重置页码并清空选中集。对话框与具体渲染(表格/卡片)留在各页面,不进 hook。
4444
_Avoid_: 列表容器、表格组件(DataList 是状态/数据 hook,不是 UI 组件)
4545

46+
### 页面逻辑下沉
47+
48+
**领域 hook(Domain Hook)**
49+
从巨型页面抽出的、承载某一 tab/领域完整状态机(state + 副作用 + API)的 hook;抽出后页面/tab 退化为消费 hook 的展示层。读多的服务端态走 TanStack Query,本地草稿态留在 hook 内。
50+
51+
**导入队列(useImportQueue)**
52+
知识库导入任务的服务端态领域 hook——任务列表、详情、取消/重试。列表用 useQuery;进度更新以 WebSocket 推送(`memoryProgressClient`)为主,轮询仅在 WS 断线时兜底。
53+
54+
**导入表单(useImportForm)**
55+
知识库导入创建的本地草稿领域 hook——7 种导入模式的参数 + 提交。参数默认值在 `importSettings` 首次到达时 seed 一次,之后用户编辑始终生效。
56+
57+
**待定操作(usePendingOperation)**
58+
「submit 待定 → 对话框确认 → 执行」同构流程的通用模块(embedding 换模型、向量重建预览、删除预览均属此类);提供 submit/confirm/cancel/pending,替代散落的 `pendingXxxRef + dialogOpen` 双 state。
59+
60+
**配置表单编排(useConfigForm)**
61+
「并行加载配置 + schema → seed 可编辑草稿 → 脏跟踪」这条配置编辑脊梁的通用模块。内部自持两个**查询**——config(必需,驱动草稿)与 schema(可选,仅供渲染字段,失败不阻塞);以 config 查询的 `dataUpdatedAt` 作版本标记在**渲染期**重置草稿(规避 effect 内 setState),是本模块的核心 leverage。对外给出 `draft/schema/setDraft/isDirty/reset/reload/isLoading/error``isDirty``JSON.stringify(draft) !== seededSnapshot`**保存、自动保存、源码(raw)模式、级联删除留在各页面**,不进 hook。
62+
63+
**当前仅 mcp-settings 接入**(单节草稿 + 手动保存,干净全适配)。落地时发现其余配置页均非干净适配,暂不强接:config/bot 是 24 个分节草稿 + 按节 autosave + 手动 `hasUnsavedChanges`(单快照 isDirty 无法表达"已 autosave 的节",且并节为单 TDraft 是无测试页上的大改);plugin-config 是 visual config + source raw 双草稿、mode-dependent dirty(useConfigForm 只能覆盖 config+schema,raw 仍要重复 seed 模式);config/model 多草稿 + 按草稿快照,由 `useModelConfig` 承载。按"两个适配器才算真 seam",本模块暂为单适配器(假设性 seam),待下一个"单节草稿 + 手动保存"配置页出现再坐实。
64+
_Avoid_: 把保存/autosave/raw/第二草稿塞进来变成开关汤(那会让它退化为浅壳,删除测试不通过);为凑适配器把 bot/plugin 强接成部分适配
65+
4666
### 配置与设置
4767

4868
**配置(Config)**

dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "maibot-dashboard",
33
"private": true,
4-
"version": "1.4.2",
4+
"version": "1.4.3",
55
"type": "module",
66
"main": "./out/main/index.js",
77
"scripts": {

dashboard/src/components/expression-reviewer.tsx

Lines changed: 33 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,11 @@ export function ExpressionReviewer({
136136
const loadStats = useCallback(async () => {
137137
try {
138138
const result = await getReviewStats()
139-
if (result.success) {
140-
setStats(result.data)
141-
} else {
142-
toast({
143-
title: '错误',
144-
description: result.error,
145-
variant: 'destructive',
146-
})
147-
}
139+
setStats(result)
148140
} catch (error) {
149141
console.error('加载统计失败:', error)
150142
}
151-
}, [toast])
143+
}, [])
152144

153145
// 加载列表
154146
const loadList = useCallback(async () => {
@@ -160,16 +152,8 @@ export function ExpressionReviewer({
160152
filter_type: filterType,
161153
search: search || undefined,
162154
})
163-
if (result.success) {
164-
setExpressions(result.data.data)
165-
setTotal(result.data.total)
166-
} else {
167-
toast({
168-
title: '加载失败',
169-
description: result.error,
170-
variant: 'destructive',
171-
})
172-
}
155+
setExpressions(result.data)
156+
setTotal(result.total)
173157
} catch (error) {
174158
toast({
175159
title: '加载失败',
@@ -185,13 +169,11 @@ export function ExpressionReviewer({
185169
const loadChatNames = useCallback(async () => {
186170
try {
187171
const result = await getChatList()
188-
if (result.success) {
189-
const nameMap = new Map<string, string>()
190-
result.data.forEach((chat: ChatInfo) => {
191-
nameMap.set(chat.chat_id, chat.chat_name)
192-
})
193-
setChatNameMap(nameMap)
194-
}
172+
const nameMap = new Map<string, string>()
173+
result.forEach((chat: ChatInfo) => {
174+
nameMap.set(chat.chat_id, chat.chat_name)
175+
})
176+
setChatNameMap(nameMap)
195177
} catch (error) {
196178
console.error('加载聚天名称失败:', error)
197179
}
@@ -214,34 +196,26 @@ export function ExpressionReviewer({
214196
exclude_ids: excludedIds.length > 0 ? excludedIds : undefined,
215197
})
216198

217-
if (result.success) {
218-
if (append) {
219-
const loadedCount = quickExpressionsRef.current.length
220-
const existingIds = new Set(quickExpressionsRef.current.map((e) => e.id))
221-
const newItems = result.data.data.filter((e: Expression) => !existingIds.has(e.id))
222-
newItems.forEach((expr: Expression) => quickExcludedIdsRef.current.add(expr.id))
223-
224-
setQuickExpressions((prev) => [...prev, ...newItems])
225-
setQuickTotal(loadedCount + result.data.total)
226-
setQuickHasMore(newItems.length > 0 && result.data.total > newItems.length)
227-
} else {
228-
quickExcludedIdsRef.current = new Set(
229-
result.data.data.map((expr: Expression) => expr.id)
230-
)
231-
setQuickExpressions(result.data.data)
232-
setQuickTotal(result.data.total)
233-
setQuickHasMore(result.data.total > result.data.data.length)
234-
}
235-
236-
if (resetIndex) {
237-
setQuickCurrentIndex(0)
238-
}
199+
if (append) {
200+
const loadedCount = quickExpressionsRef.current.length
201+
const existingIds = new Set(quickExpressionsRef.current.map((e) => e.id))
202+
const newItems = result.data.filter((e: Expression) => !existingIds.has(e.id))
203+
newItems.forEach((expr: Expression) => quickExcludedIdsRef.current.add(expr.id))
204+
205+
setQuickExpressions((prev) => [...prev, ...newItems])
206+
setQuickTotal(loadedCount + result.total)
207+
setQuickHasMore(newItems.length > 0 && result.total > newItems.length)
239208
} else {
240-
toast({
241-
title: '加载失败',
242-
description: result.error,
243-
variant: 'destructive',
244-
})
209+
quickExcludedIdsRef.current = new Set(
210+
result.data.map((expr: Expression) => expr.id)
211+
)
212+
setQuickExpressions(result.data)
213+
setQuickTotal(result.total)
214+
setQuickHasMore(result.total > result.data.length)
215+
}
216+
217+
if (resetIndex) {
218+
setQuickCurrentIndex(0)
245219
}
246220
} catch (error) {
247221
toast({
@@ -324,16 +298,7 @@ export function ExpressionReviewer({
324298
},
325299
])
326300

327-
if (!result.success) {
328-
toast({
329-
title: '操作失败',
330-
description: result.error,
331-
variant: 'destructive',
332-
})
333-
return
334-
}
335-
336-
if (result.data.results[0]?.success) {
301+
if (result.results[0]?.success) {
337302
toast({
338303
title: approved ? '已通过' : '已删除',
339304
description: `表达方式 #${currentExpr.id} ${approved ? '已通过' : '已删除'}`,
@@ -676,16 +641,7 @@ export function ExpressionReviewer({
676641
{ id, approved, require_unchecked: filterType === 'unchecked' },
677642
])
678643

679-
if (!result.success) {
680-
toast({
681-
title: '操作失败',
682-
description: result.error,
683-
variant: 'destructive',
684-
})
685-
return
686-
}
687-
688-
if (result.data.results[0]?.success) {
644+
if (result.results[0]?.success) {
689645
toast({
690646
title: approved ? '已通过' : '已删除',
691647
description: `表达方式 #${id} ${approved ? '已通过' : '已删除'}`,
@@ -697,7 +653,7 @@ export function ExpressionReviewer({
697653
} else {
698654
toast({
699655
title: '操作失败',
700-
description: result.data.results[0]?.message || '未知错误',
656+
description: result.results[0]?.message || '未知错误',
701657
variant: 'destructive',
702658
})
703659
}
@@ -738,19 +694,10 @@ export function ExpressionReviewer({
738694

739695
const result = await batchReviewExpressions(items)
740696

741-
if (!result.success) {
742-
toast({
743-
title: '批量审核失败',
744-
description: result.error,
745-
variant: 'destructive',
746-
})
747-
return
748-
}
749-
750697
toast({
751698
title: '批量审核完成',
752-
description: `成功 ${result.data.succeeded} 条,失败 ${result.data.failed} 条`,
753-
variant: result.data.failed > 0 ? 'destructive' : 'default',
699+
description: `成功 ${result.succeeded} 条,失败 ${result.failed} 条`,
700+
variant: result.failed > 0 ? 'destructive' : 'default',
754701
})
755702

756703
// 清空选择并刷新

dashboard/src/components/layout/use-menu-sections.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export function useMenuSections(): MenuSection[] {
4242
const refreshFeatureFlags = () => {
4343
getBotConfigCached()
4444
.then((result) => {
45-
if (!cancelled && result.success) {
46-
setFeatureFlags(resolveMenuFeatureFlags(result.data ?? null))
45+
if (!cancelled) {
46+
setFeatureFlags(resolveMenuFeatureFlags(result ?? null))
4747
}
4848
})
4949
.catch(() => {

dashboard/src/components/search-dialog.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ export function SearchDialog({ open, onOpenChange }: SearchDialogProps) {
157157
let cancelled = false
158158

159159
const loadConfigSearchItems = async () => {
160-
const [botSchemaResult, modelSchemaResult] = await Promise.all([
160+
// 用 allSettled:任一 schema 失败仍以另一 schema 建立搜索索引(保留原 best-effort 行为)
161+
const [botSchemaResult, modelSchemaResult] = await Promise.allSettled([
161162
getBotConfigSchema(),
162163
getModelConfigSchema(),
163164
])
@@ -167,8 +168,8 @@ export function SearchDialog({ open, onOpenChange }: SearchDialogProps) {
167168
}
168169

169170
const nextItems: SearchItem[] = []
170-
if (botSchemaResult.success) {
171-
const botSchema = unwrapConfigSchema(botSchemaResult.data)
171+
if (botSchemaResult.status === 'fulfilled') {
172+
const botSchema = unwrapConfigSchema(botSchemaResult.value)
172173
if (botSchema) {
173174
nextItems.push(...collectConfigFields(
174175
botSchema,
@@ -179,8 +180,8 @@ export function SearchDialog({ open, onOpenChange }: SearchDialogProps) {
179180
))
180181
}
181182
}
182-
if (modelSchemaResult.success) {
183-
const modelSchema = unwrapConfigSchema(modelSchemaResult.data)
183+
if (modelSchemaResult.status === 'fulfilled') {
184+
const modelSchema = unwrapConfigSchema(modelSchemaResult.value)
184185
if (modelSchema) {
185186
nextItems.push(...collectConfigFields(
186187
modelSchema,

dashboard/src/components/theme-provider.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ export function ThemeProvider({
106106

107107
try {
108108
const result = await getBotConfig()
109-
if (!result.success) {
110-
return
111-
}
112-
113-
const webuiConfig = result.data.webui as Record<string, unknown> | undefined
109+
const webuiConfig = result.webui as Record<string, unknown> | undefined
114110
if (!webuiConfig || !('webui_style' in webuiConfig)) {
115111
return
116112
}
@@ -130,10 +126,7 @@ export function ThemeProvider({
130126
pendingWebUIStyleRef.current = webuiStyle
131127

132128
try {
133-
const result = await updateBotConfigSection('webui', { webui_style: webuiStyle })
134-
if (!result.success) {
135-
console.warn('保存 WebUI 风格配置失败:', result.error)
136-
}
129+
await updateBotConfigSection('webui', { webui_style: webuiStyle })
137130
} catch (error) {
138131
console.warn('保存 WebUI 风格配置失败:', error)
139132
} finally {

0 commit comments

Comments
 (0)