@lobehub/lobehub 2.0.0-next.341 → 2.0.0-next.343
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 +74 -0
- package/changelog/v1.json +17 -0
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/userMemories.test.ts +62 -5
- package/packages/database/src/models/agentCronJob.ts +9 -9
- package/packages/database/src/models/userMemory/__tests__/identity.test.ts +5 -5
- package/packages/database/src/models/userMemory/experience.ts +91 -1
- package/packages/database/src/models/userMemory/identity.ts +93 -2
- package/packages/database/src/models/userMemory/model.ts +27 -8
- package/packages/types/src/userMemory/experience.ts +25 -0
- package/packages/types/src/userMemory/identity.ts +27 -0
- package/packages/types/src/userMemory/index.ts +1 -0
- package/packages/types/src/userMemory/shared.ts +30 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/index.tsx +3 -4
- package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +7 -8
- package/src/app/[variants]/(main)/memory/(home)/features/Persona/PersonaDetail.tsx +58 -0
- package/src/app/[variants]/(main)/memory/(home)/features/Persona/PersonaHeader.tsx +22 -0
- package/src/app/[variants]/(main)/memory/(home)/features/Persona/PersonaSummary.tsx +43 -0
- package/src/app/[variants]/(main)/memory/(home)/features/Persona/index.tsx +53 -0
- package/src/app/[variants]/(main)/memory/(home)/features/RoleTagCloud/index.tsx +2 -2
- package/src/app/[variants]/(main)/memory/(home)/index.tsx +15 -3
- package/src/app/[variants]/(main)/memory/experiences/features/List/GridView/ExperienceCard.tsx +3 -3
- package/src/app/[variants]/(main)/memory/experiences/features/List/GridView/index.tsx +3 -3
- package/src/app/[variants]/(main)/memory/experiences/features/List/TimelineView/ExperienceCard.tsx +3 -3
- package/src/app/[variants]/(main)/memory/experiences/features/List/TimelineView/index.tsx +3 -3
- package/src/app/[variants]/(main)/memory/features/SourceLink.tsx +2 -11
- package/src/app/[variants]/(main)/memory/features/TimeLineView/TimeLineCard.tsx +2 -9
- package/src/app/[variants]/(main)/memory/identities/features/IdentityRightPanel.tsx +1 -1
- package/src/app/[variants]/(main)/memory/identities/features/List/GridView/IdentityCard.tsx +5 -4
- package/src/app/[variants]/(main)/memory/identities/features/List/GridView/index.tsx +3 -3
- package/src/app/[variants]/(main)/memory/identities/features/List/TimelineView/IdentityCard.tsx +6 -6
- package/src/app/[variants]/(main)/memory/identities/features/List/TimelineView/index.tsx +6 -4
- package/src/app/[variants]/(main)/settings/profile/index.tsx +8 -8
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +0 -1
- package/src/app/[variants]/(main)/settings/skill/features/Actions.tsx +0 -1
- package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +9 -10
- package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +9 -10
- package/src/app/[variants]/(main)/settings/skill/features/McpSkillItem.tsx +4 -5
- package/src/app/[variants]/(main)/settings/skill/features/SkillList.tsx +4 -5
- package/src/app/[variants]/share/t/[id]/SharedMessageList.tsx +1 -4
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +47 -121
- package/src/app/[variants]/share/t/[id]/_layout/style.ts +59 -0
- package/src/app/[variants]/share/t/[id]/features/Portal/index.tsx +4 -5
- package/src/app/[variants]/share/t/[id]/index.tsx +30 -37
- package/src/components/404/index.tsx +15 -9
- package/src/components/DragUpload/index.tsx +15 -16
- package/src/features/EditorCanvas/DocumentIdMode.tsx +1 -2
- package/src/features/IntegrationDetailModal/index.tsx +11 -12
- package/src/features/PageEditor/Copilot/Toolbar.tsx +1 -1
- package/src/features/ResourceManager/index.tsx +13 -6
- package/src/features/ShareModal/ShareImage/Preview.tsx +19 -28
- package/src/features/ShareModal/ShareImage/style.ts +4 -2
- package/src/features/ShareModal/index.tsx +5 -1
- package/src/features/ShareModal/style.ts +1 -0
- package/src/features/ShareModal/useContainerStyles.ts +1 -1
- package/src/features/SharePopover/index.tsx +16 -9
- package/src/features/SharePopover/style.ts +2 -2
- package/src/features/SkillStore/CommunityList/Item.tsx +2 -2
- package/src/features/SkillStore/LobeHubList/Item.tsx +2 -2
- package/src/features/SkillStore/LobeHubList/index.tsx +2 -3
- package/src/features/SkillStore/style.ts +4 -4
- package/src/layout/GlobalProvider/ServerVersionOutdatedAlert.tsx +28 -20
- package/src/server/routers/lambda/userMemories.ts +61 -5
- package/src/server/routers/lambda/userMemory.ts +5 -1
- package/src/services/chat/index.ts +2 -2
- package/src/services/userMemory/index.ts +25 -1
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +0 -1
- package/src/store/userMemory/initialState.ts +22 -52
- package/src/store/userMemory/slices/context/action.ts +1 -1
- package/src/store/userMemory/slices/context/index.ts +1 -0
- package/src/store/userMemory/slices/context/initialState.ts +22 -0
- package/src/store/userMemory/slices/experience/action.ts +10 -22
- package/src/store/userMemory/slices/experience/index.ts +1 -0
- package/src/store/userMemory/slices/experience/initialState.ts +22 -0
- package/src/store/userMemory/slices/home/action.ts +17 -0
- package/src/store/userMemory/slices/identity/action.ts +36 -24
- package/src/store/userMemory/slices/identity/initialState.ts +7 -4
- package/src/store/userMemory/slices/preference/action.ts +1 -1
- package/src/store/userMemory/slices/preference/index.ts +1 -0
- package/src/store/userMemory/slices/preference/initialState.ts +22 -0
- package/src/styles/antdOverride.ts +9 -0
- package/src/server/routers/lambda/userMemories/index.ts +0 -13
- package/src/server/routers/lambda/userMemories/reembed.ts +0 -440
- package/src/server/routers/lambda/userMemories/search.ts +0 -117
- package/src/server/routers/lambda/userMemories/shared.ts +0 -63
- package/src/server/routers/lambda/userMemories/tools.ts +0 -410
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
type IdentityListResult,
|
|
3
3
|
type NewUserMemoryIdentity,
|
|
4
|
-
type TypesEnum,
|
|
5
4
|
type UpdateUserMemoryIdentity,
|
|
6
5
|
} from '@lobechat/types';
|
|
7
6
|
import { uniqBy } from 'es-toolkit/compat';
|
|
@@ -21,7 +20,9 @@ export interface IdentityQueryParams {
|
|
|
21
20
|
page?: number;
|
|
22
21
|
pageSize?: number;
|
|
23
22
|
q?: string;
|
|
24
|
-
|
|
23
|
+
relationships?: string[];
|
|
24
|
+
sort?: 'capturedAt' | 'type';
|
|
25
|
+
types?: string[];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export interface IdentityAction {
|
|
@@ -30,7 +31,7 @@ export interface IdentityAction {
|
|
|
30
31
|
loadMoreIdentities: () => void;
|
|
31
32
|
resetIdentitiesList: (params?: Omit<IdentityQueryParams, 'page' | 'pageSize'>) => void;
|
|
32
33
|
updateIdentity: (id: string, data: UpdateUserMemoryIdentity) => Promise<boolean>;
|
|
33
|
-
useFetchIdentities: (params: IdentityQueryParams) => SWRResponse<
|
|
34
|
+
useFetchIdentities: (params: IdentityQueryParams) => SWRResponse<IdentityListResult>;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export const createIdentitySlice: StateCreator<
|
|
@@ -42,14 +43,24 @@ export const createIdentitySlice: StateCreator<
|
|
|
42
43
|
createIdentity: async (data) => {
|
|
43
44
|
const result = await memoryCRUDService.createIdentity(data);
|
|
44
45
|
// Reset list to refresh
|
|
45
|
-
get().resetIdentitiesList({
|
|
46
|
+
get().resetIdentitiesList({
|
|
47
|
+
q: get().identitiesQuery,
|
|
48
|
+
relationships: get().identitiesRelationships,
|
|
49
|
+
sort: get().identitiesSort,
|
|
50
|
+
types: get().identitiesTypes,
|
|
51
|
+
});
|
|
46
52
|
return result;
|
|
47
53
|
},
|
|
48
54
|
|
|
49
55
|
deleteIdentity: async (id) => {
|
|
50
56
|
await memoryCRUDService.deleteIdentity(id);
|
|
51
57
|
// Reset list to refresh
|
|
52
|
-
get().resetIdentitiesList({
|
|
58
|
+
get().resetIdentitiesList({
|
|
59
|
+
q: get().identitiesQuery,
|
|
60
|
+
relationships: get().identitiesRelationships,
|
|
61
|
+
sort: get().identitiesSort,
|
|
62
|
+
types: get().identitiesTypes,
|
|
63
|
+
});
|
|
53
64
|
},
|
|
54
65
|
|
|
55
66
|
loadMoreIdentities: () => {
|
|
@@ -71,7 +82,9 @@ export const createIdentitySlice: StateCreator<
|
|
|
71
82
|
draft.identities = [];
|
|
72
83
|
draft.identitiesPage = 1;
|
|
73
84
|
draft.identitiesQuery = params?.q;
|
|
85
|
+
draft.identitiesRelationships = params?.relationships;
|
|
74
86
|
draft.identitiesSearchLoading = true;
|
|
87
|
+
draft.identitiesSort = params?.sort;
|
|
75
88
|
draft.identitiesTypes = params?.types;
|
|
76
89
|
}),
|
|
77
90
|
false,
|
|
@@ -82,7 +95,12 @@ export const createIdentitySlice: StateCreator<
|
|
|
82
95
|
updateIdentity: async (id, data) => {
|
|
83
96
|
const result = await memoryCRUDService.updateIdentity(id, data);
|
|
84
97
|
// Reset list to refresh
|
|
85
|
-
get().resetIdentitiesList({
|
|
98
|
+
get().resetIdentitiesList({
|
|
99
|
+
q: get().identitiesQuery,
|
|
100
|
+
relationships: get().identitiesRelationships,
|
|
101
|
+
sort: get().identitiesSort,
|
|
102
|
+
types: get().identitiesTypes,
|
|
103
|
+
});
|
|
86
104
|
return result;
|
|
87
105
|
},
|
|
88
106
|
|
|
@@ -92,6 +110,8 @@ export const createIdentitySlice: StateCreator<
|
|
|
92
110
|
params.page,
|
|
93
111
|
params.pageSize,
|
|
94
112
|
params.q,
|
|
113
|
+
params.relationships?.join(','),
|
|
114
|
+
params.sort,
|
|
95
115
|
params.types?.join(','),
|
|
96
116
|
];
|
|
97
117
|
const swrKey = swrKeyParts
|
|
@@ -102,42 +122,34 @@ export const createIdentitySlice: StateCreator<
|
|
|
102
122
|
return useSWR(
|
|
103
123
|
swrKey,
|
|
104
124
|
async () => {
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
// Use the new dedicated queryIdentities API
|
|
126
|
+
return userMemoryService.queryIdentities({
|
|
107
127
|
page: params.page,
|
|
108
128
|
pageSize: params.pageSize,
|
|
109
129
|
q: params.q,
|
|
130
|
+
relationships: params.relationships,
|
|
131
|
+
sort: params.sort,
|
|
110
132
|
types: params.types,
|
|
111
133
|
});
|
|
112
134
|
},
|
|
113
135
|
{
|
|
114
|
-
onSuccess(data:
|
|
136
|
+
onSuccess(data: IdentityListResult) {
|
|
115
137
|
set(
|
|
116
138
|
produce((draft) => {
|
|
117
139
|
draft.identitiesSearchLoading = false;
|
|
140
|
+
draft.identitiesTotal = data.total;
|
|
118
141
|
|
|
119
|
-
// 设置基础信息
|
|
120
142
|
if (!draft.identitiesInit) {
|
|
121
143
|
draft.identitiesInit = true;
|
|
122
|
-
draft.identitiesTotal = data.total;
|
|
123
144
|
}
|
|
124
145
|
|
|
125
|
-
//
|
|
126
|
-
const transformedItems = data.items.map((item: any) => ({
|
|
127
|
-
...item.memory,
|
|
128
|
-
...item.identity,
|
|
129
|
-
}));
|
|
130
|
-
|
|
131
|
-
// 累积数据逻辑
|
|
146
|
+
// Backend now returns flat structure directly, no transformation needed
|
|
132
147
|
if (page === 1) {
|
|
133
|
-
|
|
134
|
-
draft.identities = uniqBy(transformedItems, 'id');
|
|
148
|
+
draft.identities = uniqBy(data.items, 'id');
|
|
135
149
|
} else {
|
|
136
|
-
|
|
137
|
-
draft.identities = uniqBy([...draft.identities, ...transformedItems], 'id');
|
|
150
|
+
draft.identities = uniqBy([...draft.identities, ...data.items], 'id');
|
|
138
151
|
}
|
|
139
152
|
|
|
140
|
-
// 更新 hasMore
|
|
141
153
|
draft.identitiesHasMore = data.items.length >= (params.pageSize || 20);
|
|
142
154
|
}),
|
|
143
155
|
false,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { TypesEnum } from '@/types/userMemory';
|
|
1
|
+
import type { IdentityListItem, IdentityListSort } from '@lobechat/types';
|
|
3
2
|
|
|
4
3
|
import type { IdentityForInjection } from '../../types';
|
|
5
4
|
|
|
@@ -10,14 +9,16 @@ export interface IdentitySliceState {
|
|
|
10
9
|
globalIdentitiesFetchedAt?: number;
|
|
11
10
|
/** Whether global identities have been initialized */
|
|
12
11
|
globalIdentitiesInit: boolean;
|
|
13
|
-
identities:
|
|
12
|
+
identities: IdentityListItem[];
|
|
14
13
|
identitiesHasMore: boolean;
|
|
15
14
|
identitiesInit: boolean;
|
|
16
15
|
identitiesPage: number;
|
|
17
16
|
identitiesQuery?: string;
|
|
17
|
+
identitiesRelationships?: string[];
|
|
18
18
|
identitiesSearchLoading?: boolean;
|
|
19
|
+
identitiesSort?: IdentityListSort;
|
|
19
20
|
identitiesTotal: number;
|
|
20
|
-
identitiesTypes?:
|
|
21
|
+
identitiesTypes?: string[];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export const identityInitialState: IdentitySliceState = {
|
|
@@ -29,6 +30,8 @@ export const identityInitialState: IdentitySliceState = {
|
|
|
29
30
|
identitiesInit: false,
|
|
30
31
|
identitiesPage: 1,
|
|
31
32
|
identitiesQuery: undefined,
|
|
33
|
+
identitiesRelationships: undefined,
|
|
34
|
+
identitiesSort: undefined,
|
|
32
35
|
identitiesTotal: 0,
|
|
33
36
|
identitiesTypes: undefined,
|
|
34
37
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type DisplayPreferenceMemory } from '@/database/repositories/userMemory';
|
|
2
|
+
|
|
3
|
+
export interface PreferenceSliceState {
|
|
4
|
+
preferences: DisplayPreferenceMemory[];
|
|
5
|
+
preferencesHasMore: boolean;
|
|
6
|
+
preferencesInit: boolean;
|
|
7
|
+
preferencesPage: number;
|
|
8
|
+
preferencesQuery?: string;
|
|
9
|
+
preferencesSearchLoading?: boolean;
|
|
10
|
+
preferencesSort?: 'capturedAt' | 'scorePriority';
|
|
11
|
+
preferencesTotal: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const preferenceInitialState: PreferenceSliceState = {
|
|
15
|
+
preferences: [],
|
|
16
|
+
preferencesHasMore: true,
|
|
17
|
+
preferencesInit: false,
|
|
18
|
+
preferencesPage: 1,
|
|
19
|
+
preferencesQuery: undefined,
|
|
20
|
+
preferencesSort: undefined,
|
|
21
|
+
preferencesTotal: 0,
|
|
22
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDesktop } from '@lobechat/const';
|
|
1
2
|
import { type Theme, css } from 'antd-style';
|
|
2
3
|
import { rgba } from 'polished';
|
|
3
4
|
|
|
@@ -16,4 +17,12 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
|
|
|
16
17
|
background: ${rgba(token.colorBgLayout, 0.5)} !important;
|
|
17
18
|
backdrop-filter: blur(2px);
|
|
18
19
|
}
|
|
20
|
+
|
|
21
|
+
${isDesktop &&
|
|
22
|
+
css`
|
|
23
|
+
.${token.prefixCls}-modal-mask.${token.prefixCls}-modal-mask-blur {
|
|
24
|
+
background: ${rgba(token.colorBgLayout, 0.8)} !important;
|
|
25
|
+
backdrop-filter: none !important;
|
|
26
|
+
}
|
|
27
|
+
`}
|
|
19
28
|
`;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { router } from './shared';
|
|
2
|
-
import { reembedRouter } from './reembed';
|
|
3
|
-
import { searchRouter } from './search';
|
|
4
|
-
import { toolsRouter } from './tools';
|
|
5
|
-
|
|
6
|
-
// Re-export searchUserMemories for potential external use
|
|
7
|
-
export { searchUserMemories } from './search';
|
|
8
|
-
|
|
9
|
-
export const userMemoriesRouter = router({
|
|
10
|
-
...reembedRouter._def.procedures,
|
|
11
|
-
...searchRouter._def.procedures,
|
|
12
|
-
tools: toolsRouter,
|
|
13
|
-
});
|
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
import { asc, eq, gte, lte } from 'drizzle-orm';
|
|
2
|
-
import pMap from 'p-map';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
userMemories,
|
|
7
|
-
userMemoriesContexts,
|
|
8
|
-
userMemoriesExperiences,
|
|
9
|
-
userMemoriesIdentities,
|
|
10
|
-
userMemoriesPreferences,
|
|
11
|
-
} from '@/database/schemas';
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
EMBEDDING_VECTOR_DIMENSION,
|
|
15
|
-
combineConditions,
|
|
16
|
-
getEmbeddingRuntime,
|
|
17
|
-
memoryProcedure,
|
|
18
|
-
normalizeEmbeddable,
|
|
19
|
-
router,
|
|
20
|
-
} from './shared';
|
|
21
|
-
|
|
22
|
-
const REEMBED_TABLE_KEYS = [
|
|
23
|
-
'userMemories',
|
|
24
|
-
'contexts',
|
|
25
|
-
'preferences',
|
|
26
|
-
'identities',
|
|
27
|
-
'experiences',
|
|
28
|
-
] as const;
|
|
29
|
-
type ReEmbedTableKey = (typeof REEMBED_TABLE_KEYS)[number];
|
|
30
|
-
|
|
31
|
-
const reEmbedInputSchema = z.object({
|
|
32
|
-
concurrency: z.coerce.number().int().min(1).max(50).optional(),
|
|
33
|
-
endDate: z.coerce.date().optional(),
|
|
34
|
-
limit: z.coerce.number().int().min(1).optional(),
|
|
35
|
-
only: z.array(z.enum(REEMBED_TABLE_KEYS)).optional(),
|
|
36
|
-
startDate: z.coerce.date().optional(),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
interface ReEmbedStats {
|
|
40
|
-
failed: number;
|
|
41
|
-
skipped: number;
|
|
42
|
-
succeeded: number;
|
|
43
|
-
total: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const reembedRouter = router({
|
|
47
|
-
reEmbedMemories: memoryProcedure
|
|
48
|
-
.input(reEmbedInputSchema.optional())
|
|
49
|
-
.mutation(async ({ ctx, input }) => {
|
|
50
|
-
try {
|
|
51
|
-
const options = input ?? {};
|
|
52
|
-
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
|
53
|
-
ctx.serverDB,
|
|
54
|
-
ctx.userId,
|
|
55
|
-
);
|
|
56
|
-
const concurrency = options.concurrency ?? 10;
|
|
57
|
-
const shouldProcess = (key: ReEmbedTableKey) =>
|
|
58
|
-
!options.only || options.only.length === 0 || options.only.includes(key);
|
|
59
|
-
|
|
60
|
-
const embedTexts = async (texts: string[]): Promise<number[][]> => {
|
|
61
|
-
if (texts.length === 0) return [];
|
|
62
|
-
|
|
63
|
-
const response = await agentRuntime.embeddings({
|
|
64
|
-
dimensions: EMBEDDING_VECTOR_DIMENSION,
|
|
65
|
-
input: texts,
|
|
66
|
-
model: embeddingModel,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (!response || response.length !== texts.length) {
|
|
70
|
-
throw new Error('Embedding response length mismatch');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return response;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const results: Partial<Record<ReEmbedTableKey, ReEmbedStats>> = {};
|
|
77
|
-
|
|
78
|
-
const run = async (key: ReEmbedTableKey, handler: () => Promise<ReEmbedStats>) => {
|
|
79
|
-
if (!shouldProcess(key)) return;
|
|
80
|
-
results[key] = await handler();
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Re-embed userMemories
|
|
84
|
-
await run('userMemories', async () => {
|
|
85
|
-
const where = combineConditions([
|
|
86
|
-
eq(userMemories.userId, ctx.userId),
|
|
87
|
-
options.startDate ? gte(userMemories.createdAt, options.startDate) : undefined,
|
|
88
|
-
options.endDate ? lte(userMemories.createdAt, options.endDate) : undefined,
|
|
89
|
-
]);
|
|
90
|
-
|
|
91
|
-
const rows = await ctx.serverDB.query.userMemories.findMany({
|
|
92
|
-
columns: { details: true, id: true, summary: true },
|
|
93
|
-
limit: options.limit,
|
|
94
|
-
orderBy: [asc(userMemories.createdAt)],
|
|
95
|
-
where,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
let succeeded = 0;
|
|
99
|
-
let failed = 0;
|
|
100
|
-
let skipped = 0;
|
|
101
|
-
|
|
102
|
-
await pMap(
|
|
103
|
-
rows,
|
|
104
|
-
async (row) => {
|
|
105
|
-
const summaryText = normalizeEmbeddable(row.summary);
|
|
106
|
-
const detailsText = normalizeEmbeddable(row.details);
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
if (!summaryText && !detailsText) {
|
|
110
|
-
await ctx.memoryModel.updateUserMemoryVectors(row.id, {
|
|
111
|
-
detailsVector1024: null,
|
|
112
|
-
summaryVector1024: null,
|
|
113
|
-
});
|
|
114
|
-
skipped += 1;
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const inputs: string[] = [];
|
|
119
|
-
if (summaryText) inputs.push(summaryText);
|
|
120
|
-
if (detailsText) inputs.push(detailsText);
|
|
121
|
-
|
|
122
|
-
const embeddings = await embedTexts(inputs);
|
|
123
|
-
let embedIndex = 0;
|
|
124
|
-
|
|
125
|
-
const summaryVector = summaryText ? (embeddings[embedIndex++] ?? null) : null;
|
|
126
|
-
const detailsVector = detailsText ? (embeddings[embedIndex++] ?? null) : null;
|
|
127
|
-
|
|
128
|
-
await ctx.memoryModel.updateUserMemoryVectors(row.id, {
|
|
129
|
-
detailsVector1024: detailsVector,
|
|
130
|
-
summaryVector1024: summaryVector,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
succeeded += 1;
|
|
134
|
-
} catch (err) {
|
|
135
|
-
failed += 1;
|
|
136
|
-
console.error(
|
|
137
|
-
`[memoryRouter.reEmbed] Failed to re-embed user memory ${row.id}`,
|
|
138
|
-
err,
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
{ concurrency },
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
failed,
|
|
147
|
-
skipped,
|
|
148
|
-
succeeded,
|
|
149
|
-
total: rows.length,
|
|
150
|
-
} satisfies ReEmbedStats;
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Re-embed contexts
|
|
154
|
-
await run('contexts', async () => {
|
|
155
|
-
const where = combineConditions([
|
|
156
|
-
eq(userMemoriesContexts.userId, ctx.userId),
|
|
157
|
-
options.startDate ? gte(userMemoriesContexts.createdAt, options.startDate) : undefined,
|
|
158
|
-
options.endDate ? lte(userMemoriesContexts.createdAt, options.endDate) : undefined,
|
|
159
|
-
]);
|
|
160
|
-
|
|
161
|
-
const rows = await ctx.serverDB.query.userMemoriesContexts.findMany({
|
|
162
|
-
columns: { description: true, id: true },
|
|
163
|
-
limit: options.limit,
|
|
164
|
-
orderBy: [asc(userMemoriesContexts.createdAt)],
|
|
165
|
-
where,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
let succeeded = 0;
|
|
169
|
-
let failed = 0;
|
|
170
|
-
let skipped = 0;
|
|
171
|
-
|
|
172
|
-
await pMap(
|
|
173
|
-
rows,
|
|
174
|
-
async (row) => {
|
|
175
|
-
const description = normalizeEmbeddable(row.description);
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
if (!description) {
|
|
179
|
-
await ctx.memoryModel.updateContextVectors(row.id, {
|
|
180
|
-
descriptionVector: null,
|
|
181
|
-
});
|
|
182
|
-
skipped += 1;
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const [embedding] = await embedTexts([description]);
|
|
187
|
-
|
|
188
|
-
await ctx.memoryModel.updateContextVectors(row.id, {
|
|
189
|
-
descriptionVector: embedding ?? null,
|
|
190
|
-
});
|
|
191
|
-
succeeded += 1;
|
|
192
|
-
} catch (err) {
|
|
193
|
-
failed += 1;
|
|
194
|
-
console.error(`[memoryRouter.reEmbed] Failed to re-embed context ${row.id}`, err);
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
{ concurrency },
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
return {
|
|
201
|
-
failed,
|
|
202
|
-
skipped,
|
|
203
|
-
succeeded,
|
|
204
|
-
total: rows.length,
|
|
205
|
-
} satisfies ReEmbedStats;
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Re-embed preferences
|
|
209
|
-
await run('preferences', async () => {
|
|
210
|
-
const where = combineConditions([
|
|
211
|
-
eq(userMemoriesPreferences.userId, ctx.userId),
|
|
212
|
-
options.startDate
|
|
213
|
-
? gte(userMemoriesPreferences.createdAt, options.startDate)
|
|
214
|
-
: undefined,
|
|
215
|
-
options.endDate ? lte(userMemoriesPreferences.createdAt, options.endDate) : undefined,
|
|
216
|
-
]);
|
|
217
|
-
|
|
218
|
-
const rows = await ctx.serverDB.query.userMemoriesPreferences.findMany({
|
|
219
|
-
columns: { conclusionDirectives: true, id: true },
|
|
220
|
-
limit: options.limit,
|
|
221
|
-
orderBy: [asc(userMemoriesPreferences.createdAt)],
|
|
222
|
-
where,
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
let succeeded = 0;
|
|
226
|
-
let failed = 0;
|
|
227
|
-
let skipped = 0;
|
|
228
|
-
|
|
229
|
-
await pMap(
|
|
230
|
-
rows,
|
|
231
|
-
async (row) => {
|
|
232
|
-
const directives = normalizeEmbeddable(row.conclusionDirectives);
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
if (!directives) {
|
|
236
|
-
await ctx.memoryModel.updatePreferenceVectors(row.id, {
|
|
237
|
-
conclusionDirectivesVector: null,
|
|
238
|
-
});
|
|
239
|
-
skipped += 1;
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const [embedding] = await embedTexts([directives]);
|
|
244
|
-
await ctx.memoryModel.updatePreferenceVectors(row.id, {
|
|
245
|
-
conclusionDirectivesVector: embedding ?? null,
|
|
246
|
-
});
|
|
247
|
-
succeeded += 1;
|
|
248
|
-
} catch (err) {
|
|
249
|
-
failed += 1;
|
|
250
|
-
console.error(
|
|
251
|
-
`[memoryRouter.reEmbed] Failed to re-embed preference ${row.id}`,
|
|
252
|
-
err,
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
},
|
|
256
|
-
{ concurrency },
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
failed,
|
|
261
|
-
skipped,
|
|
262
|
-
succeeded,
|
|
263
|
-
total: rows.length,
|
|
264
|
-
} satisfies ReEmbedStats;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// Re-embed identities
|
|
268
|
-
await run('identities', async () => {
|
|
269
|
-
const where = combineConditions([
|
|
270
|
-
eq(userMemoriesIdentities.userId, ctx.userId),
|
|
271
|
-
options.startDate
|
|
272
|
-
? gte(userMemoriesIdentities.createdAt, options.startDate)
|
|
273
|
-
: undefined,
|
|
274
|
-
options.endDate ? lte(userMemoriesIdentities.createdAt, options.endDate) : undefined,
|
|
275
|
-
]);
|
|
276
|
-
|
|
277
|
-
const rows = await ctx.serverDB.query.userMemoriesIdentities.findMany({
|
|
278
|
-
columns: { description: true, id: true },
|
|
279
|
-
limit: options.limit,
|
|
280
|
-
orderBy: [asc(userMemoriesIdentities.createdAt)],
|
|
281
|
-
where,
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
let succeeded = 0;
|
|
285
|
-
let failed = 0;
|
|
286
|
-
let skipped = 0;
|
|
287
|
-
|
|
288
|
-
await pMap(
|
|
289
|
-
rows,
|
|
290
|
-
async (row) => {
|
|
291
|
-
const description = normalizeEmbeddable(row.description);
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
if (!description) {
|
|
295
|
-
await ctx.memoryModel.updateIdentityVectors(row.id, {
|
|
296
|
-
descriptionVector: null,
|
|
297
|
-
});
|
|
298
|
-
skipped += 1;
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const [embedding] = await embedTexts([description]);
|
|
303
|
-
await ctx.memoryModel.updateIdentityVectors(row.id, {
|
|
304
|
-
descriptionVector: embedding ?? null,
|
|
305
|
-
});
|
|
306
|
-
succeeded += 1;
|
|
307
|
-
} catch (err) {
|
|
308
|
-
failed += 1;
|
|
309
|
-
console.error(`[memoryRouter.reEmbed] Failed to re-embed identity ${row.id}`, err);
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
{ concurrency },
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
failed,
|
|
317
|
-
skipped,
|
|
318
|
-
succeeded,
|
|
319
|
-
total: rows.length,
|
|
320
|
-
} satisfies ReEmbedStats;
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// Re-embed experiences
|
|
324
|
-
await run('experiences', async () => {
|
|
325
|
-
const where = combineConditions([
|
|
326
|
-
eq(userMemoriesExperiences.userId, ctx.userId),
|
|
327
|
-
options.startDate
|
|
328
|
-
? gte(userMemoriesExperiences.createdAt, options.startDate)
|
|
329
|
-
: undefined,
|
|
330
|
-
options.endDate ? lte(userMemoriesExperiences.createdAt, options.endDate) : undefined,
|
|
331
|
-
]);
|
|
332
|
-
|
|
333
|
-
const rows = await ctx.serverDB.query.userMemoriesExperiences.findMany({
|
|
334
|
-
columns: { action: true, id: true, keyLearning: true, situation: true },
|
|
335
|
-
limit: options.limit,
|
|
336
|
-
orderBy: [asc(userMemoriesExperiences.createdAt)],
|
|
337
|
-
where,
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
let succeeded = 0;
|
|
341
|
-
let failed = 0;
|
|
342
|
-
let skipped = 0;
|
|
343
|
-
|
|
344
|
-
await pMap(
|
|
345
|
-
rows,
|
|
346
|
-
async (row) => {
|
|
347
|
-
const situation = normalizeEmbeddable(row.situation);
|
|
348
|
-
const action = normalizeEmbeddable(row.action);
|
|
349
|
-
const keyLearning = normalizeEmbeddable(row.keyLearning);
|
|
350
|
-
|
|
351
|
-
try {
|
|
352
|
-
if (!situation && !action && !keyLearning) {
|
|
353
|
-
await ctx.memoryModel.updateExperienceVectors(row.id, {
|
|
354
|
-
actionVector: null,
|
|
355
|
-
keyLearningVector: null,
|
|
356
|
-
situationVector: null,
|
|
357
|
-
});
|
|
358
|
-
skipped += 1;
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const inputs: string[] = [];
|
|
363
|
-
if (situation) inputs.push(situation);
|
|
364
|
-
if (action) inputs.push(action);
|
|
365
|
-
if (keyLearning) inputs.push(keyLearning);
|
|
366
|
-
|
|
367
|
-
const embeddings = await embedTexts(inputs);
|
|
368
|
-
let embedIndex = 0;
|
|
369
|
-
|
|
370
|
-
const situationVector = situation ? (embeddings[embedIndex++] ?? null) : null;
|
|
371
|
-
const actionVector = action ? (embeddings[embedIndex++] ?? null) : null;
|
|
372
|
-
const keyLearningVector = keyLearning ? (embeddings[embedIndex++] ?? null) : null;
|
|
373
|
-
|
|
374
|
-
await ctx.memoryModel.updateExperienceVectors(row.id, {
|
|
375
|
-
actionVector,
|
|
376
|
-
keyLearningVector,
|
|
377
|
-
situationVector,
|
|
378
|
-
});
|
|
379
|
-
succeeded += 1;
|
|
380
|
-
} catch (err) {
|
|
381
|
-
failed += 1;
|
|
382
|
-
console.error(
|
|
383
|
-
`[memoryRouter.reEmbed] Failed to re-embed experience ${row.id}`,
|
|
384
|
-
err,
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
},
|
|
388
|
-
{ concurrency },
|
|
389
|
-
);
|
|
390
|
-
|
|
391
|
-
return {
|
|
392
|
-
failed,
|
|
393
|
-
skipped,
|
|
394
|
-
succeeded,
|
|
395
|
-
total: rows.length,
|
|
396
|
-
} satisfies ReEmbedStats;
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
const processedEntries = Object.entries(results) as Array<[ReEmbedTableKey, ReEmbedStats]>;
|
|
400
|
-
|
|
401
|
-
if (processedEntries.length === 0) {
|
|
402
|
-
return {
|
|
403
|
-
message: 'No memory records matched re-embed criteria',
|
|
404
|
-
results,
|
|
405
|
-
success: true,
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const aggregate = processedEntries.reduce(
|
|
410
|
-
(acc, [, stats]) => {
|
|
411
|
-
acc.failed += stats.failed;
|
|
412
|
-
acc.skipped += stats.skipped;
|
|
413
|
-
acc.succeeded += stats.succeeded;
|
|
414
|
-
acc.total += stats.total;
|
|
415
|
-
|
|
416
|
-
return acc;
|
|
417
|
-
},
|
|
418
|
-
{ failed: 0, skipped: 0, succeeded: 0, total: 0 },
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
const message =
|
|
422
|
-
aggregate.total === 0
|
|
423
|
-
? 'No memory records required re-embedding'
|
|
424
|
-
: `Re-embedded ${aggregate.succeeded} of ${aggregate.total} records`;
|
|
425
|
-
|
|
426
|
-
return {
|
|
427
|
-
aggregate,
|
|
428
|
-
message,
|
|
429
|
-
results,
|
|
430
|
-
success: true,
|
|
431
|
-
};
|
|
432
|
-
} catch (error) {
|
|
433
|
-
console.error('Failed to re-embed memories:', error);
|
|
434
|
-
return {
|
|
435
|
-
message: `Failed to re-embed memories: ${(error as Error).message}`,
|
|
436
|
-
success: false,
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
}),
|
|
440
|
-
});
|