@lobehub/chat 0.31.0 → 0.33.0
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/CHANGELOG.md +50 -0
- package/package.json +1 -1
- package/src/pages/chat/SessionList/List/SessionItem.tsx +18 -5
- package/src/store/session/slices/chat/actions/message.ts +39 -9
- package/src/store/session/slices/session/action.ts +20 -8
- package/src/store/session/slices/session/reducers/session.ts +17 -1
- package/src/store/session/slices/session/selectors/list.ts +13 -2
- package/src/types/session.ts +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.33.0](https://github.com/lobehub/lobe-chat/compare/v0.32.0...v0.33.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-07-30**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: 支持输入模板预处理.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: 支持输入模板预处理 ([84082c1](https://github.com/lobehub/lobe-chat/commit/84082c1))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 0.32.0](https://github.com/lobehub/lobe-chat/compare/v0.31.0...v0.32.0)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-07-30**</sup>
|
|
33
|
+
|
|
34
|
+
#### ✨ Features
|
|
35
|
+
|
|
36
|
+
- **misc**: 支持会话置顶.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's improved
|
|
44
|
+
|
|
45
|
+
- **misc**: 支持会话置顶, closes [#32](https://github.com/lobehub/lobe-chat/issues/32) ([fc44b5d](https://github.com/lobehub/lobe-chat/commit/fc44b5d))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 0.31.0](https://github.com/lobehub/lobe-chat/compare/v0.30.1...v0.31.0)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-07-30**</sup>
|
package/package.json
CHANGED
|
@@ -19,10 +19,9 @@ interface SessionItemProps {
|
|
|
19
19
|
active?: boolean;
|
|
20
20
|
id: string;
|
|
21
21
|
loading?: boolean;
|
|
22
|
-
pin?: boolean;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading
|
|
24
|
+
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading }) => {
|
|
26
25
|
const ref = useRef(null);
|
|
27
26
|
const isHovering = useHover(ref);
|
|
28
27
|
|
|
@@ -33,6 +32,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
|
|
|
33
32
|
const [defaultModel] = useSettings((s) => [s.settings.model], shallow);
|
|
34
33
|
|
|
35
34
|
const [
|
|
35
|
+
pin,
|
|
36
36
|
title,
|
|
37
37
|
description,
|
|
38
38
|
systemRole,
|
|
@@ -42,11 +42,13 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
|
|
|
42
42
|
model,
|
|
43
43
|
chatLength,
|
|
44
44
|
removeSession,
|
|
45
|
+
pinSession,
|
|
45
46
|
] = useSessionStore((s) => {
|
|
46
47
|
const session = sessionSelectors.getSessionById(id)(s);
|
|
47
48
|
const meta = session.meta;
|
|
48
49
|
const systemRole = session.config.systemRole;
|
|
49
50
|
return [
|
|
51
|
+
session.pinned,
|
|
50
52
|
agentSelectors.getTitle(meta),
|
|
51
53
|
meta.description,
|
|
52
54
|
systemRole,
|
|
@@ -56,6 +58,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
|
|
|
56
58
|
session.config.model,
|
|
57
59
|
chatSelectors.currentChats(s).length,
|
|
58
60
|
s.removeSession,
|
|
61
|
+
s.pinSession,
|
|
59
62
|
];
|
|
60
63
|
}, shallow);
|
|
61
64
|
|
|
@@ -66,8 +69,9 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
|
|
|
66
69
|
icon: <Icon icon={pin ? PinOff : Pin} />,
|
|
67
70
|
key: 'pin',
|
|
68
71
|
label: t(pin ? 'pinOff' : 'pin'),
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
onClick: () => {
|
|
73
|
+
pinSession(id, !pin);
|
|
74
|
+
},
|
|
71
75
|
},
|
|
72
76
|
{
|
|
73
77
|
children: [
|
|
@@ -154,7 +158,16 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
|
|
|
154
158
|
style={{ color: theme.colorText }}
|
|
155
159
|
title={title}
|
|
156
160
|
/>
|
|
157
|
-
<Dropdown
|
|
161
|
+
<Dropdown
|
|
162
|
+
arrow={false}
|
|
163
|
+
menu={{
|
|
164
|
+
items,
|
|
165
|
+
onClick: ({ domEvent }) => {
|
|
166
|
+
domEvent.stopPropagation();
|
|
167
|
+
},
|
|
168
|
+
}}
|
|
169
|
+
trigger={['click']}
|
|
170
|
+
>
|
|
158
171
|
<ActionIcon
|
|
159
172
|
className="session-remove"
|
|
160
173
|
icon={MoreVertical}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { template } from 'lodash-es';
|
|
1
2
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
3
|
|
|
3
4
|
import { LOADING_FLAT } from '@/const/message';
|
|
@@ -113,8 +114,41 @@ export const chatMessage: StateCreator<
|
|
|
113
114
|
set({ chatLoadingId: assistantId });
|
|
114
115
|
const config = agentSelectors.currentAgentConfigSafe(get());
|
|
115
116
|
|
|
117
|
+
const compiler = template(config.inputTemplate, { interpolate: /{{([\S\s]+?)}}/g });
|
|
118
|
+
|
|
119
|
+
// 对 message 做统一预处理
|
|
120
|
+
|
|
121
|
+
// 1. 替换 inputMessage 模板
|
|
122
|
+
const postMessages = !config.inputTemplate
|
|
123
|
+
? messages
|
|
124
|
+
: messages.map((m) => {
|
|
125
|
+
if (m.role === 'user') {
|
|
126
|
+
try {
|
|
127
|
+
return { ...m, content: compiler({ text: m.content }) };
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(error);
|
|
130
|
+
|
|
131
|
+
return m;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return m;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// 2. TODO 按参数设定截断长度
|
|
138
|
+
|
|
139
|
+
// 3. 添加 systemRole
|
|
140
|
+
const { systemRole } = agentSelectors.currentAgentConfigSafe(get());
|
|
141
|
+
if (systemRole) {
|
|
142
|
+
postMessages.unshift({ content: systemRole, role: 'system' } as ChatMessage);
|
|
143
|
+
}
|
|
144
|
+
|
|
116
145
|
const fetcher = () =>
|
|
117
|
-
fetchChatModel({
|
|
146
|
+
fetchChatModel({
|
|
147
|
+
messages: postMessages,
|
|
148
|
+
model: config.model,
|
|
149
|
+
...config.params,
|
|
150
|
+
plugins: config.plugins,
|
|
151
|
+
});
|
|
118
152
|
|
|
119
153
|
let output = '';
|
|
120
154
|
let isFunctionCall = false;
|
|
@@ -154,13 +188,9 @@ export const chatMessage: StateCreator<
|
|
|
154
188
|
realFetchAIResponse: async (messages, userMessageId) => {
|
|
155
189
|
const { dispatchMessage, generateMessage, triggerFunctionCall, activeTopicId } = get();
|
|
156
190
|
|
|
157
|
-
|
|
158
|
-
const { systemRole, model } = agentSelectors.currentAgentConfigSafe(get());
|
|
159
|
-
if (systemRole) {
|
|
160
|
-
messages.unshift({ content: systemRole, role: 'system' } as ChatMessage);
|
|
161
|
-
}
|
|
191
|
+
const { model } = agentSelectors.currentAgentConfigSafe(get());
|
|
162
192
|
|
|
163
|
-
//
|
|
193
|
+
// 添加一个空的信息用于放置 ai 响应,注意顺序不能反
|
|
164
194
|
// 因为如果顺序反了,messages 中将包含新增的 ai message
|
|
165
195
|
const mid = nanoid();
|
|
166
196
|
|
|
@@ -283,10 +313,10 @@ export const chatMessage: StateCreator<
|
|
|
283
313
|
|
|
284
314
|
const mid = nanoid();
|
|
285
315
|
|
|
286
|
-
dispatchMessage({ id: mid, message: LOADING_FLAT, role: 'assistant', type: 'addMessage' });
|
|
287
|
-
|
|
288
316
|
const chats = chatSelectors.currentChats(get());
|
|
289
317
|
|
|
318
|
+
dispatchMessage({ id: mid, message: LOADING_FLAT, role: 'assistant', type: 'addMessage' });
|
|
319
|
+
|
|
290
320
|
await generateMessage(chats, mid);
|
|
291
321
|
},
|
|
292
322
|
});
|
|
@@ -31,6 +31,11 @@ export interface SessionAction {
|
|
|
31
31
|
*/
|
|
32
32
|
importSessions: (sessions: LobeSessions) => void;
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* 置顶会话
|
|
36
|
+
* @param sessionId
|
|
37
|
+
*/
|
|
38
|
+
pinSession: (sessionId: string, pinned?: boolean) => void;
|
|
34
39
|
/**
|
|
35
40
|
* 生成压缩后的消息
|
|
36
41
|
* @returns 压缩后的消息
|
|
@@ -42,12 +47,13 @@ export interface SessionAction {
|
|
|
42
47
|
* @returns void
|
|
43
48
|
*/
|
|
44
49
|
removeSession: (sessionId: string) => void;
|
|
50
|
+
|
|
45
51
|
/**
|
|
46
52
|
* @title 切换会话
|
|
47
53
|
* @param sessionId - 会话索引
|
|
48
54
|
* @returns void
|
|
49
55
|
*/
|
|
50
|
-
switchSession: (sessionId?: string
|
|
56
|
+
switchSession: (sessionId?: string) => Promise<void>;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
export const createSessionSlice: StateCreator<
|
|
@@ -104,6 +110,19 @@ export const createSessionSlice: StateCreator<
|
|
|
104
110
|
}),
|
|
105
111
|
});
|
|
106
112
|
},
|
|
113
|
+
// genShareUrl: () => {
|
|
114
|
+
// const session = sessionSelectors.currentSession(get());
|
|
115
|
+
// if (!session) return '';
|
|
116
|
+
//
|
|
117
|
+
// const agent = session.config;
|
|
118
|
+
// return genShareMessagesUrl(session.chats, agent.systemRole);
|
|
119
|
+
// },
|
|
120
|
+
pinSession: (sessionId, pinned) => {
|
|
121
|
+
const nextValue = typeof pinned === 'boolean' ? pinned : !get().sessions[sessionId].pinned;
|
|
122
|
+
|
|
123
|
+
get().dispatchSession({ id: sessionId, pinned: nextValue, type: 'toggleSessionPinned' });
|
|
124
|
+
},
|
|
125
|
+
|
|
107
126
|
removeSession: (sessionId) => {
|
|
108
127
|
get().dispatchSession({ id: sessionId, type: 'removeSession' });
|
|
109
128
|
|
|
@@ -122,11 +141,4 @@ export const createSessionSlice: StateCreator<
|
|
|
122
141
|
// 新会话
|
|
123
142
|
await Router.push(`/chat/${sessionId}`);
|
|
124
143
|
},
|
|
125
|
-
// genShareUrl: () => {
|
|
126
|
-
// const session = sessionSelectors.currentSession(get());
|
|
127
|
-
// if (!session) return '';
|
|
128
|
-
//
|
|
129
|
-
// const agent = session.config;
|
|
130
|
-
// return genShareMessagesUrl(session.chats, agent.systemRole);
|
|
131
|
-
// },
|
|
132
144
|
});
|
|
@@ -63,6 +63,11 @@ interface UpdateSessionAgentConfig {
|
|
|
63
63
|
id: string;
|
|
64
64
|
type: 'updateSessionConfig';
|
|
65
65
|
}
|
|
66
|
+
interface ToggleSessionPinned {
|
|
67
|
+
id: string;
|
|
68
|
+
pinned: boolean;
|
|
69
|
+
type: 'toggleSessionPinned';
|
|
70
|
+
}
|
|
66
71
|
|
|
67
72
|
export type SessionDispatch =
|
|
68
73
|
| AddSession
|
|
@@ -70,7 +75,8 @@ export type SessionDispatch =
|
|
|
70
75
|
| RemoveSession
|
|
71
76
|
| UpdateSessionMeta
|
|
72
77
|
| UpdateSessionAgentConfig
|
|
73
|
-
| UpdateSessionTopic
|
|
78
|
+
| UpdateSessionTopic
|
|
79
|
+
| ToggleSessionPinned;
|
|
74
80
|
|
|
75
81
|
export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch): LobeSessions => {
|
|
76
82
|
switch (payload.type) {
|
|
@@ -89,6 +95,16 @@ export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch):
|
|
|
89
95
|
});
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
case 'toggleSessionPinned': {
|
|
99
|
+
return produce(state, (draft) => {
|
|
100
|
+
const { pinned, id } = payload;
|
|
101
|
+
const session = draft[id];
|
|
102
|
+
if (!session) return;
|
|
103
|
+
|
|
104
|
+
session.pinned = pinned;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
92
108
|
case 'updateSessionMeta': {
|
|
93
109
|
return produce(state, (draft) => {
|
|
94
110
|
const chat = draft[payload.id];
|
|
@@ -21,8 +21,19 @@ export const sessionList = (s: SessionStore) => {
|
|
|
21
21
|
.map((c) => c.content)
|
|
22
22
|
.join(''),
|
|
23
23
|
]);
|
|
24
|
-
|
|
25
|
-
return Object.values(filterChats).sort((a, b) =>
|
|
24
|
+
// 先按照 `pinned` 字段进行排序,置顶的会排在前面。然后,根据 `updateAt` 字段进行倒序排序。
|
|
25
|
+
return Object.values(filterChats).sort((a, b) => {
|
|
26
|
+
if (a.pinned && !b.pinned) {
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
if (!a.pinned && b.pinned) {
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
if (a.updateAt && b.updateAt) {
|
|
33
|
+
return b.updateAt - a.updateAt;
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
});
|
|
26
37
|
};
|
|
27
38
|
|
|
28
39
|
export const getSessionById =
|