Skip to content

Commit bd5a321

Browse files
committed
Merge branch 'main' into electronUpgrade
2 parents 25cabec + 5ceb2af commit bd5a321

File tree

179 files changed

+11140
-5105
lines changed

Some content is hidden

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

179 files changed

+11140
-5105
lines changed

.yarn/patches/app-builder-lib-npm-26.0.13-a064c9e1d0.patch

Lines changed: 0 additions & 92 deletions
This file was deleted.

.yarn/patches/electron-updater-npm-6.6.3-9269dbaf84.patch

Lines changed: 0 additions & 51 deletions
This file was deleted.

.yarn/patches/openai-npm-4.87.3-2b30a7685f.patch renamed to .yarn/patches/openai-npm-4.96.0-0665b05cb9.patch

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
diff --git a/core.js b/core.js
2-
index ebb071d31cd5a14792b62814df072c5971e83300..31e1062d4a7f2422ffec79cf96a35dbb69fe89cb 100644
2+
index 862d66101f441fb4f47dfc8cff5e2d39e1f5a11e..6464bebbf696c39d35f0368f061ea4236225c162 100644
33
--- a/core.js
44
+++ b/core.js
5-
@@ -157,7 +157,7 @@ class APIClient {
5+
@@ -159,7 +159,7 @@ class APIClient {
66
Accept: 'application/json',
77
'Content-Type': 'application/json',
88
'User-Agent': this.getUserAgent(),
@@ -12,10 +12,10 @@ index ebb071d31cd5a14792b62814df072c5971e83300..31e1062d4a7f2422ffec79cf96a35dbb
1212
};
1313
}
1414
diff --git a/core.mjs b/core.mjs
15-
index 9c1a0264dcd73a85de1cf81df4efab9ce9ee2ab7..33f9f1f237f2eb2667a05dae1a7e3dc916f6bfff 100644
15+
index 05dbc6cfde51589a2b100d4e4b5b3c1a33b32b89..789fbb4985eb952a0349b779fa83b1a068af6e7e 100644
1616
--- a/core.mjs
1717
+++ b/core.mjs
18-
@@ -150,7 +150,7 @@ export class APIClient {
18+
@@ -152,7 +152,7 @@ export class APIClient {
1919
Accept: 'application/json',
2020
'Content-Type': 'application/json',
2121
'User-Agent': this.getUserAgent(),

docs/technical/Message.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# 消息的生命周期
2+
3+
![image](./message-lifecycle.png)
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# messageBlock.ts 使用指南
2+
3+
该文件定义了用于管理应用程序中所有 `MessageBlock` 实体的 Redux Slice。它使用 Redux Toolkit 的 `createSlice``createEntityAdapter` 来高效地处理规范化的状态,并提供了一系列 actions 和 selectors 用于与消息块数据交互。
4+
5+
## 核心目标
6+
7+
- **状态管理**: 集中管理所有 `MessageBlock` 的状态。`MessageBlock` 代表消息中的不同内容单元(如文本、代码、图片、引用等)。
8+
- **规范化**: 使用 `createEntityAdapter``MessageBlock` 数据存储在规范化的结构中(`{ ids: [], entities: {} }`),这有助于提高性能和简化更新逻辑。
9+
- **可预测性**: 提供明确的 actions 来修改状态,并通过 selectors 安全地访问状态。
10+
11+
## 关键概念
12+
13+
- **Slice (`createSlice`)**: Redux Toolkit 的核心 API,用于创建包含 reducer 逻辑、action creators 和初始状态的 Redux 模块。
14+
- **Entity Adapter (`createEntityAdapter`)**: Redux Toolkit 提供的工具,用于简化对规范化数据的 CRUD(创建、读取、更新、删除)操作。它会自动生成 reducer 函数和 selectors。
15+
- **Selectors**: 用于从 Redux store 中派生和计算数据的函数。Selectors 可以被记忆化(memoized),以提高性能。
16+
17+
## State 结构
18+
19+
`messageBlocks` slice 的状态结构由 `createEntityAdapter` 定义,大致如下:
20+
21+
```typescript
22+
{
23+
ids: string[]; // 存储所有 MessageBlock ID 的有序列表
24+
entities: { [id: string]: MessageBlock }; // 按 ID 存储 MessageBlock 对象的字典
25+
loadingState: 'idle' | 'loading' | 'succeeded' | 'failed'; // (可选) 其他状态,如加载状态
26+
error: string | null; // (可选) 错误信息
27+
}
28+
```
29+
30+
## Actions
31+
32+
该 slice 导出以下 actions (由 `createSlice``createEntityAdapter` 自动生成或自定义):
33+
34+
- **`upsertOneBlock(payload: MessageBlock)`**:
35+
36+
- 添加一个新的 `MessageBlock` 或更新一个已存在的 `MessageBlock`。如果 payload 中的 `id` 已存在,则执行更新;否则执行插入。
37+
38+
- **`upsertManyBlocks(payload: MessageBlock[])`**:
39+
40+
- 添加或更新多个 `MessageBlock`。常用于批量加载数据(例如,加载一个 Topic 的所有消息块)。
41+
42+
- **`removeOneBlock(payload: string)`**:
43+
44+
- 根据提供的 `id` (payload) 移除单个 `MessageBlock`
45+
46+
- **`removeManyBlocks(payload: string[])`**:
47+
48+
- 根据提供的 `id` 数组 (payload) 移除多个 `MessageBlock`。常用于删除消息或清空 Topic 时清理相关的块。
49+
50+
- **`removeAllBlocks()`**:
51+
52+
- 移除 state 中的所有 `MessageBlock` 实体。
53+
54+
- **`updateOneBlock(payload: { id: string; changes: Partial<MessageBlock> })`**:
55+
56+
- 更新一个已存在的 `MessageBlock``payload` 需要包含块的 `id` 和一个包含要更改的字段的 `changes` 对象。
57+
58+
- **`setMessageBlocksLoading(payload: 'idle' | 'loading')`**:
59+
60+
- (自定义) 设置 `loadingState` 属性。
61+
62+
- **`setMessageBlocksError(payload: string)`**:
63+
- (自定义) 设置 `loadingState``'failed'` 并记录错误信息。
64+
65+
**使用示例 (在 Thunk 或其他 Dispatch 的地方):**
66+
67+
```typescript
68+
import { upsertOneBlock, removeManyBlocks, updateOneBlock } from './messageBlock'
69+
import store from './store' // 假设这是你的 Redux store 实例
70+
71+
// 添加或更新一个块
72+
const newBlock: MessageBlock = {
73+
/* ... block data ... */
74+
}
75+
store.dispatch(upsertOneBlock(newBlock))
76+
77+
// 更新一个块的内容
78+
store.dispatch(updateOneBlock({ id: blockId, changes: { content: 'New content' } }))
79+
80+
// 删除多个块
81+
const blockIdsToRemove = ['id1', 'id2']
82+
store.dispatch(removeManyBlocks(blockIdsToRemove))
83+
```
84+
85+
## Selectors
86+
87+
该 slice 导出由 `createEntityAdapter` 生成的基础 selectors,并通过 `messageBlocksSelectors` 对象访问:
88+
89+
- **`messageBlocksSelectors.selectIds(state: RootState): string[]`**: 返回包含所有块 ID 的数组。
90+
- **`messageBlocksSelectors.selectEntities(state: RootState): { [id: string]: MessageBlock }`**: 返回块 ID 到块对象的映射字典。
91+
- **`messageBlocksSelectors.selectAll(state: RootState): MessageBlock[]`**: 返回包含所有块对象的数组。
92+
- **`messageBlocksSelectors.selectTotal(state: RootState): number`**: 返回块的总数。
93+
- **`messageBlocksSelectors.selectById(state: RootState, id: string): MessageBlock | undefined`**: 根据 ID 返回单个块对象,如果找不到则返回 `undefined`
94+
95+
**此外,还提供了一个自定义的、记忆化的 selector:**
96+
97+
- **`selectFormattedCitationsByBlockId(state: RootState, blockId: string | undefined): Citation[]`**:
98+
- 接收一个 `blockId`
99+
- 如果该 ID 对应的块是 `CITATION` 类型,则提取并格式化其包含的引用信息(来自网页搜索、知识库等),进行去重和重新编号,最后返回一个 `Citation[]` 数组,用于在 UI 中显示。
100+
- 如果块不存在或类型不匹配,返回空数组 `[]`
101+
- 这个 selector 封装了处理不同引用来源(Gemini, OpenAI, OpenRouter, Zhipu 等)的复杂逻辑。
102+
103+
**使用示例 (在 React 组件或 `useSelector` 中):**
104+
105+
```typescript
106+
import { useSelector } from 'react-redux'
107+
import { messageBlocksSelectors, selectFormattedCitationsByBlockId } from './messageBlock'
108+
import type { RootState } from './store'
109+
110+
// 获取所有块
111+
const allBlocks = useSelector(messageBlocksSelectors.selectAll)
112+
113+
// 获取特定 ID 的块
114+
const specificBlock = useSelector((state: RootState) => messageBlocksSelectors.selectById(state, someBlockId))
115+
116+
// 获取特定引用块格式化后的引用列表
117+
const formattedCitations = useSelector((state: RootState) => selectFormattedCitationsByBlockId(state, citationBlockId))
118+
119+
// 在组件中使用引用数据
120+
// {formattedCitations.map(citation => ...)}
121+
```
122+
123+
## 集成
124+
125+
`messageBlock.ts` slice 通常与 `messageThunk.ts` 中的 Thunks 紧密协作。Thunks 负责处理异步逻辑(如 API 调用、数据库操作),并在需要时 dispatch `messageBlock` slice 的 actions 来更新状态。例如,当 `messageThunk` 接收到流式响应时,它会 dispatch `upsertOneBlock``updateOneBlock` 来实时更新对应的 `MessageBlock`。同样,删除消息的 Thunk 会 dispatch `removeManyBlocks`
126+
127+
理解 `messageBlock.ts` 的职责是管理**状态本身**,而 `messageThunk.ts` 负责**触发状态变更**的异步流程,这对于维护清晰的应用架构至关重要。

0 commit comments

Comments
 (0)