@lobehub/lobehub 2.0.0-next.360 → 2.0.0-next.361
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 +25 -0
- package/changelog/v1.json +5 -0
- package/package.json +1 -1
- package/packages/const/src/userMemory.ts +1 -0
- package/packages/database/src/models/userMemory/model.ts +178 -3
- package/packages/database/src/models/userMemory/sources/benchmarkLoCoMo.ts +1 -1
- package/packages/memory-user-memory/package.json +2 -1
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/buildMessages.ts +40 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/eval.yaml +13 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/prompt.ts +5 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/tests/cases.ts +106 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/buildMessages.ts +104 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/eval.yaml +13 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/prompt.ts +5 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/benchmark-locomo-payload-conv-26.json +149 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/cases.ts +72 -0
- package/packages/memory-user-memory/promptfoo/response-formats/activity.json +370 -0
- package/packages/memory-user-memory/promptfoo/response-formats/experience.json +14 -0
- package/packages/memory-user-memory/promptfoo/response-formats/identity.json +281 -255
- package/packages/memory-user-memory/promptfooconfig.yaml +1 -0
- package/packages/memory-user-memory/scripts/generate-response-formats.ts +26 -2
- package/packages/memory-user-memory/src/extractors/activity.ts +44 -0
- package/packages/memory-user-memory/src/extractors/gatekeeper.test.ts +2 -1
- package/packages/memory-user-memory/src/extractors/gatekeeper.ts +2 -1
- package/packages/memory-user-memory/src/extractors/index.ts +1 -0
- package/packages/memory-user-memory/src/prompts/gatekeeper.ts +3 -3
- package/packages/memory-user-memory/src/prompts/index.ts +7 -1
- package/packages/memory-user-memory/src/prompts/layers/activity.ts +90 -0
- package/packages/memory-user-memory/src/prompts/layers/index.ts +1 -0
- package/packages/memory-user-memory/src/providers/existingUserMemory.test.ts +25 -1
- package/packages/memory-user-memory/src/providers/existingUserMemory.ts +113 -0
- package/packages/memory-user-memory/src/schemas/activity.ts +315 -0
- package/packages/memory-user-memory/src/schemas/experience.ts +5 -5
- package/packages/memory-user-memory/src/schemas/gatekeeper.ts +1 -0
- package/packages/memory-user-memory/src/schemas/index.ts +1 -0
- package/packages/memory-user-memory/src/services/extractExecutor.ts +29 -0
- package/packages/memory-user-memory/src/types.ts +7 -0
- package/packages/types/src/serverConfig.ts +1 -1
- package/packages/types/src/userMemory/layers.ts +52 -0
- package/packages/types/src/userMemory/list.ts +20 -2
- package/packages/types/src/userMemory/shared.ts +22 -1
- package/packages/types/src/userMemory/trace.ts +1 -0
- package/packages/types/src/util.ts +9 -1
- package/src/libs/next/proxy/define-config.ts +1 -0
- package/src/server/globalConfig/parseMemoryExtractionConfig.ts +7 -1
- package/src/server/services/memory/userMemory/__tests__/extract.runtime.test.ts +2 -0
- package/src/server/services/memory/userMemory/extract.ts +108 -7
|
@@ -8,7 +8,13 @@ import {
|
|
|
8
8
|
type MemoryLayerExtractorPublicConfig,
|
|
9
9
|
} from '@/types/serverConfig';
|
|
10
10
|
|
|
11
|
-
const MEMORY_LAYERS: GlobalMemoryLayer[] = [
|
|
11
|
+
const MEMORY_LAYERS: GlobalMemoryLayer[] = [
|
|
12
|
+
'activity',
|
|
13
|
+
'context',
|
|
14
|
+
'experience',
|
|
15
|
+
'identity',
|
|
16
|
+
'preference',
|
|
17
|
+
];
|
|
12
18
|
|
|
13
19
|
const parseTokenLimitEnv = (value?: string) => {
|
|
14
20
|
if (value === undefined) return undefined;
|
|
@@ -26,6 +26,7 @@ const createExecutor = (privateOverrides?: Partial<MemoryExtractionPrivateConfig
|
|
|
26
26
|
agentLayerExtractor: {
|
|
27
27
|
contextLimit: 2048,
|
|
28
28
|
layers: {
|
|
29
|
+
activity: 'layer-act',
|
|
29
30
|
context: 'layer-ctx',
|
|
30
31
|
experience: 'layer-exp',
|
|
31
32
|
identity: 'layer-id',
|
|
@@ -38,6 +39,7 @@ const createExecutor = (privateOverrides?: Partial<MemoryExtractionPrivateConfig
|
|
|
38
39
|
embedding: { model: 'embed-1', provider: 'provider-e' },
|
|
39
40
|
featureFlags: { enableBenchmarkLoCoMo: false },
|
|
40
41
|
observabilityS3: { enabled: false },
|
|
42
|
+
webhookHeaders: {},
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
const serverConfig = {
|
|
@@ -90,6 +90,7 @@ const LAYER_ALIAS = new Set<LayersEnum>([
|
|
|
90
90
|
]);
|
|
91
91
|
|
|
92
92
|
const LAYER_LABEL_MAP: Record<LayersEnum, string> = {
|
|
93
|
+
[LayersEnum.Activity]: 'activities',
|
|
93
94
|
[LayersEnum.Context]: 'contexts',
|
|
94
95
|
[LayersEnum.Experience]: 'experiences',
|
|
95
96
|
[LayersEnum.Identity]: 'identities',
|
|
@@ -267,6 +268,7 @@ const resolveLayerModels = (
|
|
|
267
268
|
layers: Partial<Record<GlobalMemoryLayer, string>> | undefined,
|
|
268
269
|
fallback: Record<GlobalMemoryLayer, string>,
|
|
269
270
|
): Record<LayersEnum, string> => ({
|
|
271
|
+
activity: layers?.activity ?? fallback.activity,
|
|
270
272
|
context: layers?.context ?? fallback.context,
|
|
271
273
|
experience: layers?.experience ?? fallback.experience,
|
|
272
274
|
identity: layers?.identity ?? fallback.identity,
|
|
@@ -569,6 +571,79 @@ export class MemoryExtractionExecutor {
|
|
|
569
571
|
});
|
|
570
572
|
}
|
|
571
573
|
|
|
574
|
+
async persistActivityMemories(
|
|
575
|
+
job: MemoryExtractionJob,
|
|
576
|
+
messageIds: string[],
|
|
577
|
+
result: NonNullable<MemoryExtractionResult['outputs']['activity']>['data'],
|
|
578
|
+
runtime: ModelRuntime,
|
|
579
|
+
model: string,
|
|
580
|
+
tokenLimit: number | undefined,
|
|
581
|
+
db: Awaited<ReturnType<typeof getServerDB>>,
|
|
582
|
+
) {
|
|
583
|
+
const insertedIds: string[] = [];
|
|
584
|
+
const userMemoryModel = new UserMemoryModel(db, job.userId);
|
|
585
|
+
|
|
586
|
+
for (const item of result?.memories ?? []) {
|
|
587
|
+
const activityTags = item.withActivity?.tags ?? item.tags;
|
|
588
|
+
const associatedObjects = UserMemoryModel.parseAssociatedObjects(
|
|
589
|
+
item.withActivity?.associatedObjects,
|
|
590
|
+
);
|
|
591
|
+
const associatedSubjects = UserMemoryModel.parseAssociatedSubjects(
|
|
592
|
+
item.withActivity?.associatedSubjects,
|
|
593
|
+
);
|
|
594
|
+
const associatedLocations = UserMemoryModel.parseAssociatedLocations(
|
|
595
|
+
item.withActivity?.associatedLocations,
|
|
596
|
+
);
|
|
597
|
+
const [summaryVector, detailsVector, narrativeVector, feedbackVector] =
|
|
598
|
+
await this.generateEmbeddings(
|
|
599
|
+
runtime,
|
|
600
|
+
model,
|
|
601
|
+
[item.summary, item.details, item.withActivity?.narrative, item.withActivity?.feedback],
|
|
602
|
+
tokenLimit,
|
|
603
|
+
);
|
|
604
|
+
const baseMetadata = this.buildBaseMetadata(
|
|
605
|
+
job,
|
|
606
|
+
messageIds,
|
|
607
|
+
LayersEnum.Activity,
|
|
608
|
+
activityTags,
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
const { memory } = await userMemoryModel.createActivityMemory({
|
|
612
|
+
activity: {
|
|
613
|
+
associatedLocations: associatedLocations.length > 0 ? associatedLocations : [],
|
|
614
|
+
associatedObjects: associatedObjects.length > 0 ? associatedObjects : [],
|
|
615
|
+
associatedSubjects: associatedSubjects.length > 0 ? associatedSubjects : [],
|
|
616
|
+
capturedAt: job.sourceUpdatedAt,
|
|
617
|
+
endsAt: UserMemoryModel.parseDateFromString(item.withActivity?.endsAt),
|
|
618
|
+
feedback: item.withActivity?.feedback ?? null,
|
|
619
|
+
feedbackVector: feedbackVector ?? null,
|
|
620
|
+
metadata: baseMetadata,
|
|
621
|
+
narrative: item.withActivity?.narrative ?? null,
|
|
622
|
+
narrativeVector: narrativeVector ?? null,
|
|
623
|
+
notes: item.withActivity?.notes ?? null,
|
|
624
|
+
startsAt: UserMemoryModel.parseDateFromString(item.withActivity?.startsAt),
|
|
625
|
+
status: item.withActivity?.status ?? 'pending',
|
|
626
|
+
tags: activityTags ?? null,
|
|
627
|
+
timezone: item.withActivity?.timezone ?? null,
|
|
628
|
+
type: item.withActivity?.type ?? 'other',
|
|
629
|
+
},
|
|
630
|
+
capturedAt: job.sourceUpdatedAt,
|
|
631
|
+
details: item.details ?? '',
|
|
632
|
+
detailsEmbedding: detailsVector ?? undefined,
|
|
633
|
+
memoryCategory: item.memoryCategory ?? null,
|
|
634
|
+
memoryLayer: (item.memoryLayer as LayersEnum) ?? LayersEnum.Activity,
|
|
635
|
+
memoryType: (item.memoryType as TypesEnum) ?? TypesEnum.Activity,
|
|
636
|
+
summary: item.summary ?? '',
|
|
637
|
+
summaryEmbedding: summaryVector ?? undefined,
|
|
638
|
+
title: item.title ?? '',
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
insertedIds.push(memory.id);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
return insertedIds;
|
|
645
|
+
}
|
|
646
|
+
|
|
572
647
|
async persistContextMemories(
|
|
573
648
|
job: MemoryExtractionJob,
|
|
574
649
|
messageIds: string[],
|
|
@@ -601,7 +676,7 @@ export class MemoryExtractionExecutor {
|
|
|
601
676
|
associatedObjects: UserMemoryModel.parseAssociatedObjects(
|
|
602
677
|
item.withContext?.associatedObjects,
|
|
603
678
|
),
|
|
604
|
-
associatedSubjects: UserMemoryModel.
|
|
679
|
+
associatedSubjects: UserMemoryModel.parseAssociatedSubjects(
|
|
605
680
|
item.withContext?.associatedSubjects,
|
|
606
681
|
),
|
|
607
682
|
capturedAt: job.sourceUpdatedAt,
|
|
@@ -923,13 +998,14 @@ export class MemoryExtractionExecutor {
|
|
|
923
998
|
if (vector) {
|
|
924
999
|
const retrieved = await userMemoryModel.searchWithEmbedding({
|
|
925
1000
|
embedding: vector,
|
|
926
|
-
limits: { contexts: topK, experiences: topK, preferences: topK },
|
|
1001
|
+
limits: { activities: topK, contexts: topK, experiences: topK, preferences: topK },
|
|
927
1002
|
});
|
|
928
1003
|
|
|
929
1004
|
return retrieved;
|
|
930
1005
|
}
|
|
931
1006
|
|
|
932
1007
|
return {
|
|
1008
|
+
activities: [],
|
|
933
1009
|
contexts: [],
|
|
934
1010
|
experiences: [],
|
|
935
1011
|
preferences: [],
|
|
@@ -1563,6 +1639,24 @@ export class MemoryExtractionExecutor {
|
|
|
1563
1639
|
);
|
|
1564
1640
|
};
|
|
1565
1641
|
|
|
1642
|
+
const activityOutput = extraction.outputs.activity;
|
|
1643
|
+
if (activityOutput?.error) {
|
|
1644
|
+
appendError(LayersEnum.Activity, 'extract', activityOutput.error);
|
|
1645
|
+
}
|
|
1646
|
+
if (activityOutput?.data) {
|
|
1647
|
+
await persistWithSpan(LayersEnum.Activity, () =>
|
|
1648
|
+
this.persistActivityMemories(
|
|
1649
|
+
job,
|
|
1650
|
+
messageIds,
|
|
1651
|
+
activityOutput.data,
|
|
1652
|
+
runtimes.embeddings,
|
|
1653
|
+
this.modelConfig.embeddingsModel,
|
|
1654
|
+
this.embeddingContextLimit,
|
|
1655
|
+
db,
|
|
1656
|
+
),
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1566
1660
|
const contextOutput = extraction.outputs.context;
|
|
1567
1661
|
if (contextOutput?.error) {
|
|
1568
1662
|
appendError(LayersEnum.Context, 'extract', contextOutput.error);
|
|
@@ -1636,7 +1730,7 @@ export class MemoryExtractionExecutor {
|
|
|
1636
1730
|
}
|
|
1637
1731
|
|
|
1638
1732
|
if (errors.length) {
|
|
1639
|
-
const detail = errors.map((error) => error.message).join('; ');
|
|
1733
|
+
const detail = errors.map((error) => `${error.message}${error.cause ? `: ${error.cause}` : ''}`).join('; ');
|
|
1640
1734
|
throw new AggregateError(errors, `Memory extraction encountered layer errors: ${detail}`);
|
|
1641
1735
|
}
|
|
1642
1736
|
|
|
@@ -1825,14 +1919,21 @@ export class MemoryExtractionExecutor {
|
|
|
1825
1919
|
userId: params.userId,
|
|
1826
1920
|
});
|
|
1827
1921
|
|
|
1922
|
+
const latestCreatedAt = params.parts.reduce<Date | undefined>((latest, part) => {
|
|
1923
|
+
if (!part.createdAt) return latest;
|
|
1924
|
+
|
|
1925
|
+
const date = new Date(part.createdAt);
|
|
1926
|
+
if (Number.isNaN(date.getTime())) return latest;
|
|
1927
|
+
|
|
1928
|
+
return !latest || date > latest ? date : latest;
|
|
1929
|
+
}, undefined);
|
|
1930
|
+
|
|
1828
1931
|
extractionJob = {
|
|
1829
1932
|
force: params.forceAll ?? true,
|
|
1830
1933
|
layers: params.layers,
|
|
1831
1934
|
source: params.source,
|
|
1832
1935
|
sourceId: params.sourceId,
|
|
1833
|
-
sourceUpdatedAt:
|
|
1834
|
-
? new Date(params.parts.at(-1)!.createdAt as Date)
|
|
1835
|
-
: new Date(),
|
|
1936
|
+
sourceUpdatedAt: latestCreatedAt ?? new Date(),
|
|
1836
1937
|
userId: params.userId,
|
|
1837
1938
|
};
|
|
1838
1939
|
|
|
@@ -1898,7 +1999,7 @@ export class MemoryExtractionExecutor {
|
|
|
1898
1999
|
language,
|
|
1899
2000
|
retrievedContexts: [trimmedContext],
|
|
1900
2001
|
retrievedIdentitiesContext: undefined,
|
|
1901
|
-
sessionDate: new Date().toISOString(),
|
|
2002
|
+
sessionDate: (latestCreatedAt ?? new Date()).toISOString(),
|
|
1902
2003
|
topK: 10,
|
|
1903
2004
|
username:
|
|
1904
2005
|
userState.fullName || `${userState.firstName} ${userState.lastName}`.trim() || 'User',
|