@lobehub/lobehub 2.0.0-next.370 → 2.0.0-next.372
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/changelog/v1.json +10 -0
- package/locales/zh-CN/memory.json +11 -0
- package/package.json +1 -1
- package/packages/builtin-tool-memory/package.json +1 -0
- package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +3 -2
- package/packages/builtin-tool-memory/src/manifest.ts +4 -1
- package/packages/context-engine/src/engine/messages/index.ts +1 -0
- package/packages/context-engine/src/engine/messages/types.ts +11 -0
- package/packages/database/src/models/userMemory/activity.ts +163 -0
- package/packages/database/src/models/userMemory/index.ts +1 -0
- package/packages/database/src/models/userMemory/model.ts +175 -1
- package/packages/database/src/repositories/userMemory/index.ts +5 -0
- package/packages/prompts/src/prompts/userMemory/__snapshots__/formatSearchResults.test.ts.snap +12 -0
- package/packages/prompts/src/prompts/userMemory/formatSearchResults.test.ts +41 -0
- package/packages/prompts/src/prompts/userMemory/formatSearchResults.ts +56 -2
- package/packages/types/src/userMemory/activity.ts +19 -0
- package/packages/types/src/userMemory/index.ts +1 -0
- package/packages/types/src/userMemory/tools.ts +10 -1
- package/src/app/(backend)/api/dev/memory-user-memory/benchmark-locomo/route.ts +19 -0
- package/src/app/[variants]/(main)/memory/_layout/Sidebar/Header/Nav.tsx +8 -0
- package/src/app/[variants]/(main)/memory/activities/features/ActivityDropdown.tsx +68 -0
- package/src/app/[variants]/(main)/memory/activities/features/ActivityRightPanel.tsx +113 -0
- package/src/app/[variants]/(main)/memory/activities/features/List/GridView/ActivityCard.tsx +36 -0
- package/src/app/[variants]/(main)/memory/activities/features/List/GridView/index.tsx +32 -0
- package/src/app/[variants]/(main)/memory/activities/features/List/TimelineView/ActivityCard.tsx +34 -0
- package/src/app/[variants]/(main)/memory/activities/features/List/TimelineView/index.tsx +41 -0
- package/src/app/[variants]/(main)/memory/activities/features/List/index.tsx +43 -0
- package/src/app/[variants]/(main)/memory/activities/index.tsx +125 -0
- package/src/app/[variants]/(main)/memory/features/EditableModal/index.tsx +1 -0
- package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
- package/src/locales/default/memory.ts +12 -0
- package/src/server/routers/lambda/userMemories.test.ts +18 -4
- package/src/server/routers/lambda/userMemories.ts +131 -1
- package/src/server/routers/lambda/userMemory.ts +34 -1
- package/src/server/services/memory/userMemory/extract.ts +1 -0
- package/src/services/chat/mecha/contextEngineering.test.ts +1 -0
- package/src/services/chat/mecha/memoryManager.ts +2 -0
- package/src/services/userMemory/crud.ts +17 -0
- package/src/services/userMemory/index.ts +18 -1
- package/src/store/userMemory/initialState.ts +4 -1
- package/src/store/userMemory/selectors.ts +1 -0
- package/src/store/userMemory/slices/activity/action.ts +123 -0
- package/src/store/userMemory/slices/activity/index.ts +2 -0
- package/src/store/userMemory/slices/activity/initialState.ts +23 -0
- package/src/store/userMemory/slices/agent/action.ts +1 -0
- package/src/store/userMemory/slices/base/action.ts +27 -4
- package/src/store/userMemory/store.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.372](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.371...v2.0.0-next.372)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-25**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **userMemories**: Memory activity list.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **userMemories**: Memory activity list, closes [#11785](https://github.com/lobehub/lobe-chat/issues/11785) ([a9f3a53](https://github.com/lobehub/lobe-chat/commit/a9f3a53))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 2.0.0-next.371](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.370...v2.0.0-next.371)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2026-01-25**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **builtin-tool-memory**: Missing activities for topK parameter.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **builtin-tool-memory**: Missing activities for topK parameter, closes [#11801](https://github.com/lobehub/lobe-chat/issues/11801) ([d6dee2a](https://github.com/lobehub/lobe-chat/commit/d6dee2a))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 2.0.0-next.370](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.369...v2.0.0-next.370)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2026-01-25**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
+
"activity.actions.delete": "删除",
|
|
3
|
+
"activity.actions.edit": "编辑",
|
|
4
|
+
"activity.defaultType": "事件",
|
|
5
|
+
"activity.deleteConfirm": "确认删除这条事件记忆?删除后将无法恢复",
|
|
6
|
+
"activity.deleteTitle": "删除事件记忆",
|
|
7
|
+
"activity.empty": "暂无事件记忆",
|
|
8
|
+
"activity.feedback": "反馈",
|
|
9
|
+
"activity.narrative": "叙述",
|
|
10
|
+
"activity.notes": "备注",
|
|
2
11
|
"context.actions.delete": "删除",
|
|
3
12
|
"context.actions.edit": "编辑",
|
|
4
13
|
"context.defaultType": "上下文",
|
|
@@ -29,6 +38,7 @@
|
|
|
29
38
|
"filter.sort.scoreImpact": "重要度",
|
|
30
39
|
"filter.sort.scorePriority": "偏好权重",
|
|
31
40
|
"filter.sort.scoreUrgency": "紧急度",
|
|
41
|
+
"filter.sort.startsAt": "开始时间",
|
|
32
42
|
"identity.empty": "暂无身份记忆",
|
|
33
43
|
"identity.filter.search": "搜索角色、关系或描述...",
|
|
34
44
|
"identity.filter.type.all": "全部",
|
|
@@ -55,6 +65,7 @@
|
|
|
55
65
|
"preference.empty": "暂无偏好记忆",
|
|
56
66
|
"preference.source": "来源",
|
|
57
67
|
"preference.suggestions": "助理可能会采取的行动",
|
|
68
|
+
"tab.activities": "活动",
|
|
58
69
|
"tab.contexts": "情境",
|
|
59
70
|
"tab.experiences": "经验",
|
|
60
71
|
"tab.home": "首页",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.372",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -26,9 +26,10 @@ export const SearchUserMemoryInspector = memo<
|
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
// pluginState is SearchMemoryResult directly (contexts, experiences, preferences)
|
|
29
|
+
// pluginState is SearchMemoryResult directly (activities, contexts, experiences, preferences)
|
|
30
30
|
const resultCount = pluginState
|
|
31
|
-
? (pluginState.
|
|
31
|
+
? (pluginState.activities?.length ?? 0) +
|
|
32
|
+
(pluginState.contexts?.length ?? 0) +
|
|
32
33
|
(pluginState.experiences?.length ?? 0) +
|
|
33
34
|
(pluginState.preferences?.length ?? 0)
|
|
34
35
|
: 0;
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
MERGE_STRATEGIES,
|
|
9
9
|
RELATIONSHIPS,
|
|
10
10
|
} from '@lobechat/types';
|
|
11
|
+
import { JSONSchema7 } from 'json-schema'
|
|
11
12
|
|
|
12
13
|
import { systemPrompt } from './systemRole';
|
|
13
14
|
import { MemoryApiName } from './types';
|
|
@@ -26,7 +27,9 @@ export const MemoryManifest: BuiltinToolManifest = {
|
|
|
26
27
|
query: { type: 'string' },
|
|
27
28
|
topK: {
|
|
28
29
|
additionalProperties: false,
|
|
30
|
+
description: "Limits on number of memories to return per layer, default to search 3 activities, 0 contexts, 0 experiences, and 0 preferences if not specified.",
|
|
29
31
|
properties: {
|
|
32
|
+
activities: { minimum: 0, type: 'integer' },
|
|
30
33
|
contexts: { minimum: 0, type: 'integer' },
|
|
31
34
|
experiences: { minimum: 0, type: 'integer' },
|
|
32
35
|
preferences: { minimum: 0, type: 'integer' },
|
|
@@ -37,7 +40,7 @@ export const MemoryManifest: BuiltinToolManifest = {
|
|
|
37
40
|
},
|
|
38
41
|
required: ['query', 'topK'],
|
|
39
42
|
type: 'object',
|
|
40
|
-
},
|
|
43
|
+
} satisfies JSONSchema7,
|
|
41
44
|
},
|
|
42
45
|
{
|
|
43
46
|
description:
|
|
@@ -86,6 +86,16 @@ export interface UserMemoryPreferenceItem {
|
|
|
86
86
|
[key: string]: unknown;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
export interface UserMemoryActivityItem {
|
|
90
|
+
endsAt?: string | Date | null;
|
|
91
|
+
id?: string;
|
|
92
|
+
startsAt?: string | Date | null;
|
|
93
|
+
status?: string | null;
|
|
94
|
+
timezone?: string | null;
|
|
95
|
+
type?: string | null;
|
|
96
|
+
[key: string]: unknown;
|
|
97
|
+
}
|
|
98
|
+
|
|
89
99
|
export interface UserMemoryIdentityItem {
|
|
90
100
|
description?: string | null;
|
|
91
101
|
id?: string;
|
|
@@ -100,6 +110,7 @@ export interface UserMemoryIdentityItem {
|
|
|
100
110
|
* Compatible with SearchMemoryResult from @lobechat/types
|
|
101
111
|
*/
|
|
102
112
|
export interface UserMemoryData {
|
|
113
|
+
activities?: UserMemoryActivityItem[];
|
|
103
114
|
contexts: UserMemoryContextItem[];
|
|
104
115
|
experiences: UserMemoryExperienceItem[];
|
|
105
116
|
identities?: UserMemoryIdentityItem[];
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { ActivityListParams, ActivityListResult } from '@lobechat/types';
|
|
2
|
+
import { type SQL, and, asc, desc, eq, ilike, inArray, or, sql } from 'drizzle-orm';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
NewUserMemoryActivity,
|
|
6
|
+
UserMemoryActivity,
|
|
7
|
+
userMemories,
|
|
8
|
+
userMemoriesActivities,
|
|
9
|
+
} from '../../schemas';
|
|
10
|
+
import { LobeChatDatabase } from '../../type';
|
|
11
|
+
|
|
12
|
+
export class UserMemoryActivityModel {
|
|
13
|
+
private userId: string;
|
|
14
|
+
private db: LobeChatDatabase;
|
|
15
|
+
|
|
16
|
+
constructor(db: LobeChatDatabase, userId: string) {
|
|
17
|
+
this.userId = userId;
|
|
18
|
+
this.db = db;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
create = async (params: Omit<NewUserMemoryActivity, 'userId'>) => {
|
|
22
|
+
const [result] = await this.db
|
|
23
|
+
.insert(userMemoriesActivities)
|
|
24
|
+
.values({ ...params, userId: this.userId })
|
|
25
|
+
.returning();
|
|
26
|
+
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
delete = async (id: string) => {
|
|
31
|
+
return this.db.transaction(async (tx) => {
|
|
32
|
+
const activity = await tx.query.userMemoriesActivities.findFirst({
|
|
33
|
+
where: and(eq(userMemoriesActivities.id, id), eq(userMemoriesActivities.userId, this.userId)),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (!activity || !activity.userMemoryId) {
|
|
37
|
+
return { success: false };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
await tx
|
|
41
|
+
.delete(userMemories)
|
|
42
|
+
.where(and(eq(userMemories.id, activity.userMemoryId), eq(userMemories.userId, this.userId)));
|
|
43
|
+
|
|
44
|
+
return { success: true };
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
deleteAll = async () => {
|
|
49
|
+
return this.db
|
|
50
|
+
.delete(userMemoriesActivities)
|
|
51
|
+
.where(eq(userMemoriesActivities.userId, this.userId));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
query = async (limit = 50) => {
|
|
55
|
+
return this.db.query.userMemoriesActivities.findMany({
|
|
56
|
+
limit,
|
|
57
|
+
orderBy: [desc(userMemoriesActivities.createdAt)],
|
|
58
|
+
where: eq(userMemoriesActivities.userId, this.userId),
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
queryList = async (params: ActivityListParams = {}): Promise<ActivityListResult> => {
|
|
63
|
+
const { order = 'desc', page = 1, pageSize = 20, q, sort, status, tags, types } = params;
|
|
64
|
+
|
|
65
|
+
const normalizedPage = Math.max(1, page);
|
|
66
|
+
const normalizedPageSize = Math.min(Math.max(pageSize, 1), 100);
|
|
67
|
+
const offset = (normalizedPage - 1) * normalizedPageSize;
|
|
68
|
+
const normalizedQuery = typeof q === 'string' ? q.trim() : '';
|
|
69
|
+
|
|
70
|
+
const conditions: Array<SQL | undefined> = [
|
|
71
|
+
eq(userMemoriesActivities.userId, this.userId),
|
|
72
|
+
normalizedQuery
|
|
73
|
+
? or(
|
|
74
|
+
ilike(userMemories.title, `%${normalizedQuery}%`),
|
|
75
|
+
ilike(userMemoriesActivities.narrative, `%${normalizedQuery}%`),
|
|
76
|
+
ilike(userMemoriesActivities.notes, `%${normalizedQuery}%`),
|
|
77
|
+
ilike(userMemoriesActivities.feedback, `%${normalizedQuery}%`),
|
|
78
|
+
)
|
|
79
|
+
: undefined,
|
|
80
|
+
types && types.length > 0 ? inArray(userMemoriesActivities.type, types) : undefined,
|
|
81
|
+
status && status.length > 0 ? inArray(userMemoriesActivities.status, status) : undefined,
|
|
82
|
+
tags && tags.length > 0
|
|
83
|
+
? or(
|
|
84
|
+
...tags.map(
|
|
85
|
+
(tag) =>
|
|
86
|
+
sql<boolean>`
|
|
87
|
+
COALESCE(${tag} = ANY(${userMemoriesActivities.tags}), false)
|
|
88
|
+
OR COALESCE(${tag} = ANY(${userMemories.tags}), false)
|
|
89
|
+
`,
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
: undefined,
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const filters = conditions.filter((condition): condition is SQL => condition !== undefined);
|
|
96
|
+
const whereClause = filters.length > 0 ? and(...filters) : undefined;
|
|
97
|
+
|
|
98
|
+
const applyOrder = order === 'asc' ? asc : desc;
|
|
99
|
+
const sortColumn =
|
|
100
|
+
sort === 'startsAt' ? userMemoriesActivities.startsAt : userMemoriesActivities.capturedAt;
|
|
101
|
+
|
|
102
|
+
const orderByClauses = [
|
|
103
|
+
applyOrder(sortColumn),
|
|
104
|
+
applyOrder(userMemoriesActivities.updatedAt),
|
|
105
|
+
applyOrder(userMemoriesActivities.createdAt),
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const joinCondition = and(
|
|
109
|
+
eq(userMemories.id, userMemoriesActivities.userMemoryId),
|
|
110
|
+
eq(userMemories.userId, this.userId),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const [rows, totalResult] = await Promise.all([
|
|
114
|
+
this.db
|
|
115
|
+
.select({
|
|
116
|
+
capturedAt: userMemoriesActivities.capturedAt,
|
|
117
|
+
createdAt: userMemoriesActivities.createdAt,
|
|
118
|
+
endsAt: userMemoriesActivities.endsAt,
|
|
119
|
+
id: userMemoriesActivities.id,
|
|
120
|
+
narrative: userMemoriesActivities.narrative,
|
|
121
|
+
notes: userMemoriesActivities.notes,
|
|
122
|
+
startsAt: userMemoriesActivities.startsAt,
|
|
123
|
+
status: userMemoriesActivities.status,
|
|
124
|
+
tags: userMemoriesActivities.tags,
|
|
125
|
+
timezone: userMemoriesActivities.timezone,
|
|
126
|
+
title: userMemories.title,
|
|
127
|
+
type: userMemoriesActivities.type,
|
|
128
|
+
updatedAt: userMemoriesActivities.updatedAt,
|
|
129
|
+
})
|
|
130
|
+
.from(userMemoriesActivities)
|
|
131
|
+
.innerJoin(userMemories, joinCondition)
|
|
132
|
+
.where(whereClause)
|
|
133
|
+
.orderBy(...orderByClauses)
|
|
134
|
+
.limit(normalizedPageSize)
|
|
135
|
+
.offset(offset),
|
|
136
|
+
this.db
|
|
137
|
+
.select({ count: sql<number>`COUNT(*)::int` })
|
|
138
|
+
.from(userMemoriesActivities)
|
|
139
|
+
.innerJoin(userMemories, joinCondition)
|
|
140
|
+
.where(whereClause),
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
items: rows,
|
|
145
|
+
page: normalizedPage,
|
|
146
|
+
pageSize: normalizedPageSize,
|
|
147
|
+
total: Number(totalResult[0]?.count ?? 0),
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
findById = async (id: string) => {
|
|
152
|
+
return this.db.query.userMemoriesActivities.findFirst({
|
|
153
|
+
where: and(eq(userMemoriesActivities.id, id), eq(userMemoriesActivities.userId, this.userId)),
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
update = async (id: string, value: Partial<UserMemoryActivity>) => {
|
|
158
|
+
return this.db
|
|
159
|
+
.update(userMemoriesActivities)
|
|
160
|
+
.set({ ...value, updatedAt: new Date() })
|
|
161
|
+
.where(and(eq(userMemoriesActivities.id, id), eq(userMemoriesActivities.userId, this.userId)));
|
|
162
|
+
};
|
|
163
|
+
}
|
|
@@ -331,7 +331,8 @@ export type QueryUserMemoriesSort =
|
|
|
331
331
|
| 'scoreConfidence' // user_memories_experiences
|
|
332
332
|
| 'scoreImpact' // user_memories_contexts
|
|
333
333
|
| 'scorePriority' // user_memories_preferences
|
|
334
|
-
| 'scoreUrgency'
|
|
334
|
+
| 'scoreUrgency' // user_memories_contexts
|
|
335
|
+
| 'startsAt'; // user_memories_activities
|
|
335
336
|
|
|
336
337
|
export interface QueryUserMemoriesParams {
|
|
337
338
|
categories?: string[];
|
|
@@ -341,6 +342,7 @@ export interface QueryUserMemoriesParams {
|
|
|
341
342
|
pageSize?: number;
|
|
342
343
|
q?: string;
|
|
343
344
|
sort?: QueryUserMemoriesSort;
|
|
345
|
+
status?: string[];
|
|
344
346
|
tags?: string[];
|
|
345
347
|
types?: string[];
|
|
346
348
|
}
|
|
@@ -850,6 +852,7 @@ export class UserMemoryModel {
|
|
|
850
852
|
pageSize = 20,
|
|
851
853
|
q,
|
|
852
854
|
sort,
|
|
855
|
+
status,
|
|
853
856
|
tags,
|
|
854
857
|
types,
|
|
855
858
|
} = params;
|
|
@@ -1005,6 +1008,98 @@ export class UserMemoryModel {
|
|
|
1005
1008
|
total: Number(totalResult[0]?.count ?? 0),
|
|
1006
1009
|
};
|
|
1007
1010
|
}
|
|
1011
|
+
case LayersEnum.Activity: {
|
|
1012
|
+
const sortColumn =
|
|
1013
|
+
sort === 'startsAt'
|
|
1014
|
+
? userMemoriesActivities.startsAt
|
|
1015
|
+
: userMemoriesActivities.capturedAt;
|
|
1016
|
+
|
|
1017
|
+
const orderByClauses = buildOrderBy(
|
|
1018
|
+
sortColumn,
|
|
1019
|
+
userMemoriesActivities.updatedAt,
|
|
1020
|
+
userMemoriesActivities.createdAt,
|
|
1021
|
+
);
|
|
1022
|
+
const joinCondition = and(
|
|
1023
|
+
eq(userMemories.id, userMemoriesActivities.userMemoryId),
|
|
1024
|
+
eq(userMemoriesActivities.userId, this.userId),
|
|
1025
|
+
);
|
|
1026
|
+
|
|
1027
|
+
const activityFilters: Array<SQL | undefined> = [
|
|
1028
|
+
whereClause,
|
|
1029
|
+
types && types.length > 0 ? inArray(userMemoriesActivities.type, types) : undefined,
|
|
1030
|
+
status && status.length > 0 ? inArray(userMemoriesActivities.status, status) : undefined,
|
|
1031
|
+
tags && tags.length > 0
|
|
1032
|
+
? or(
|
|
1033
|
+
...tags.map(
|
|
1034
|
+
(tag) =>
|
|
1035
|
+
sql<boolean>`
|
|
1036
|
+
COALESCE(${tag} = ANY(${userMemoriesActivities.tags}), false)
|
|
1037
|
+
OR COALESCE(${tag} = ANY(${userMemories.tags}), false)
|
|
1038
|
+
`,
|
|
1039
|
+
),
|
|
1040
|
+
)
|
|
1041
|
+
: undefined,
|
|
1042
|
+
];
|
|
1043
|
+
const activityWhereClause = activityFilters.some(
|
|
1044
|
+
(condition): condition is SQL => condition !== undefined,
|
|
1045
|
+
)
|
|
1046
|
+
? and(
|
|
1047
|
+
...(activityFilters.filter(
|
|
1048
|
+
(condition): condition is SQL => condition !== undefined,
|
|
1049
|
+
) as SQL[]),
|
|
1050
|
+
)
|
|
1051
|
+
: undefined;
|
|
1052
|
+
|
|
1053
|
+
const [rows, totalResult] = await Promise.all([
|
|
1054
|
+
this.db
|
|
1055
|
+
.select({
|
|
1056
|
+
activity: {
|
|
1057
|
+
accessedAt: userMemoriesActivities.accessedAt,
|
|
1058
|
+
associatedLocations: userMemoriesActivities.associatedLocations,
|
|
1059
|
+
associatedObjects: userMemoriesActivities.associatedObjects,
|
|
1060
|
+
associatedSubjects: userMemoriesActivities.associatedSubjects,
|
|
1061
|
+
capturedAt: userMemoriesActivities.capturedAt,
|
|
1062
|
+
createdAt: userMemoriesActivities.createdAt,
|
|
1063
|
+
endsAt: userMemoriesActivities.endsAt,
|
|
1064
|
+
id: userMemoriesActivities.id,
|
|
1065
|
+
metadata: userMemoriesActivities.metadata,
|
|
1066
|
+
startsAt: userMemoriesActivities.startsAt,
|
|
1067
|
+
status: userMemoriesActivities.status,
|
|
1068
|
+
tags: userMemoriesActivities.tags,
|
|
1069
|
+
timezone: userMemoriesActivities.timezone,
|
|
1070
|
+
type: userMemoriesActivities.type,
|
|
1071
|
+
updatedAt: userMemoriesActivities.updatedAt,
|
|
1072
|
+
userId: userMemoriesActivities.userId,
|
|
1073
|
+
userMemoryId: userMemoriesActivities.userMemoryId,
|
|
1074
|
+
},
|
|
1075
|
+
memory: baseSelection,
|
|
1076
|
+
})
|
|
1077
|
+
.from(userMemories)
|
|
1078
|
+
.innerJoin(userMemoriesActivities, joinCondition)
|
|
1079
|
+
.where(activityWhereClause)
|
|
1080
|
+
.orderBy(...orderByClauses)
|
|
1081
|
+
.limit(normalizedPageSize)
|
|
1082
|
+
.offset(offset),
|
|
1083
|
+
this.db
|
|
1084
|
+
.select({ count: sql<number>`COUNT(*)::int` })
|
|
1085
|
+
.from(userMemories)
|
|
1086
|
+
.innerJoin(userMemoriesActivities, joinCondition)
|
|
1087
|
+
.where(activityWhereClause),
|
|
1088
|
+
]);
|
|
1089
|
+
|
|
1090
|
+
return {
|
|
1091
|
+
items: rows.map((row) => {
|
|
1092
|
+
return {
|
|
1093
|
+
activity: row.activity,
|
|
1094
|
+
layer: LayersEnum.Activity,
|
|
1095
|
+
memory: row.memory,
|
|
1096
|
+
};
|
|
1097
|
+
}),
|
|
1098
|
+
page: normalizedPage,
|
|
1099
|
+
pageSize: normalizedPageSize,
|
|
1100
|
+
total: Number(totalResult[0]?.count ?? 0),
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1008
1103
|
case LayersEnum.Experience: {
|
|
1009
1104
|
const scoreColumn =
|
|
1010
1105
|
sort === 'scoreConfidence'
|
|
@@ -1310,6 +1405,58 @@ export class UserMemoryModel {
|
|
|
1310
1405
|
sourceType,
|
|
1311
1406
|
};
|
|
1312
1407
|
}
|
|
1408
|
+
case LayersEnum.Activity: {
|
|
1409
|
+
const [activity] = await this.db
|
|
1410
|
+
.select({
|
|
1411
|
+
accessedAt: userMemoriesActivities.accessedAt,
|
|
1412
|
+
associatedLocations: userMemoriesActivities.associatedLocations,
|
|
1413
|
+
associatedObjects: userMemoriesActivities.associatedObjects,
|
|
1414
|
+
associatedSubjects: userMemoriesActivities.associatedSubjects,
|
|
1415
|
+
capturedAt: userMemoriesActivities.capturedAt,
|
|
1416
|
+
createdAt: userMemoriesActivities.createdAt,
|
|
1417
|
+
endsAt: userMemoriesActivities.endsAt,
|
|
1418
|
+
feedback: userMemoriesActivities.feedback,
|
|
1419
|
+
id: userMemoriesActivities.id,
|
|
1420
|
+
metadata: userMemoriesActivities.metadata,
|
|
1421
|
+
narrative: userMemoriesActivities.narrative,
|
|
1422
|
+
notes: userMemoriesActivities.notes,
|
|
1423
|
+
startsAt: userMemoriesActivities.startsAt,
|
|
1424
|
+
status: userMemoriesActivities.status,
|
|
1425
|
+
tags: userMemoriesActivities.tags,
|
|
1426
|
+
timezone: userMemoriesActivities.timezone,
|
|
1427
|
+
type: userMemoriesActivities.type,
|
|
1428
|
+
updatedAt: userMemoriesActivities.updatedAt,
|
|
1429
|
+
userId: userMemoriesActivities.userId,
|
|
1430
|
+
userMemoryId: userMemoriesActivities.userMemoryId,
|
|
1431
|
+
})
|
|
1432
|
+
.from(userMemoriesActivities)
|
|
1433
|
+
.where(
|
|
1434
|
+
and(eq(userMemoriesActivities.id, id), eq(userMemoriesActivities.userId, this.userId)),
|
|
1435
|
+
)
|
|
1436
|
+
.limit(1);
|
|
1437
|
+
if (!activity?.userMemoryId) {
|
|
1438
|
+
return undefined;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
const memory = await this.findUserMemoryRawById(activity.userMemoryId);
|
|
1442
|
+
if (!memory) {
|
|
1443
|
+
return undefined;
|
|
1444
|
+
}
|
|
1445
|
+
if (memory.memoryLayer !== LayersEnum.Activity) {
|
|
1446
|
+
return undefined;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
const { sourceId, sourceType } = await this.extractSourceMetadata(activity.metadata);
|
|
1450
|
+
const source = sourceId ? await this.topicModel.findById(sourceId) : undefined;
|
|
1451
|
+
|
|
1452
|
+
return {
|
|
1453
|
+
activity,
|
|
1454
|
+
layer,
|
|
1455
|
+
memory,
|
|
1456
|
+
source,
|
|
1457
|
+
sourceType,
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1313
1460
|
case LayersEnum.Experience: {
|
|
1314
1461
|
const [experience] = await this.db
|
|
1315
1462
|
.select({
|
|
@@ -1630,6 +1777,33 @@ export class UserMemoryModel {
|
|
|
1630
1777
|
);
|
|
1631
1778
|
};
|
|
1632
1779
|
|
|
1780
|
+
updateActivityVectors = async (
|
|
1781
|
+
id: string,
|
|
1782
|
+
vectors: { feedbackVector?: number[] | null; narrativeVector?: number[] | null },
|
|
1783
|
+
): Promise<void> => {
|
|
1784
|
+
const vectorUpdates: Partial<typeof userMemoriesActivities.$inferInsert> = {};
|
|
1785
|
+
if (vectors.feedbackVector !== undefined) {
|
|
1786
|
+
vectorUpdates.feedbackVector = vectors.feedbackVector;
|
|
1787
|
+
}
|
|
1788
|
+
if (vectors.narrativeVector !== undefined) {
|
|
1789
|
+
vectorUpdates.narrativeVector = vectors.narrativeVector;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
if (Object.keys(vectorUpdates).length === 0) {
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
await this.db
|
|
1797
|
+
.update(userMemoriesActivities)
|
|
1798
|
+
.set({
|
|
1799
|
+
...vectorUpdates,
|
|
1800
|
+
updatedAt: new Date(),
|
|
1801
|
+
})
|
|
1802
|
+
.where(
|
|
1803
|
+
and(eq(userMemoriesActivities.id, id), eq(userMemoriesActivities.userId, this.userId)),
|
|
1804
|
+
);
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1633
1807
|
addIdentityEntry = async (params: AddIdentityEntryParams): Promise<AddIdentityEntryResult> => {
|
|
1634
1808
|
const now = new Date();
|
|
1635
1809
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
UserMemoryActivitiesWithoutVectors,
|
|
2
3
|
UserMemoryContextsWithoutVectors,
|
|
3
4
|
UserMemoryExperiencesWithoutVectors,
|
|
4
5
|
UserMemoryIdentitiesWithoutVectors,
|
|
@@ -25,3 +26,7 @@ export interface DisplayPreferenceMemory extends UserMemoryPreferencesWithoutVec
|
|
|
25
26
|
export type DisplayContextMemory = UserMemoryContextsWithoutVectors;
|
|
26
27
|
|
|
27
28
|
export type DisplayIdentityMemory = UserMemoryIdentitiesWithoutVectors;
|
|
29
|
+
|
|
30
|
+
export interface DisplayActivityMemory extends UserMemoryActivitiesWithoutVectors {
|
|
31
|
+
title: string | null;
|
|
32
|
+
}
|
package/packages/prompts/src/prompts/userMemory/__snapshots__/formatSearchResults.test.ts.snap
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
+
exports[`formatMemorySearchResults > should format activity memories with scheduling and feedback details 1`] = `
|
|
4
|
+
"<memories query="meeting" total="1">
|
|
5
|
+
<activities count="1">
|
|
6
|
+
<activity id="act-1" type="meeting" status="scheduled" startsAt="2024-01-01T10:00:00.000Z" endsAt="2024-01-01T11:00:00.000Z" timezone="UTC">
|
|
7
|
+
<feedback>Great alignment</feedback>
|
|
8
|
+
<narrative>Covered Q1 roadmap and risks</narrative>
|
|
9
|
+
<notes>Share slides after the call</notes>
|
|
10
|
+
</activity>
|
|
11
|
+
</activities>
|
|
12
|
+
</memories>"
|
|
13
|
+
`;
|
|
14
|
+
|
|
3
15
|
exports[`formatMemorySearchResults > should format context memories with full content 1`] = `
|
|
4
16
|
"<memories query="project" total="1">
|
|
5
17
|
<contexts count="1">
|