@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.
Files changed (47) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +5 -0
  3. package/package.json +1 -1
  4. package/packages/const/src/userMemory.ts +1 -0
  5. package/packages/database/src/models/userMemory/model.ts +178 -3
  6. package/packages/database/src/models/userMemory/sources/benchmarkLoCoMo.ts +1 -1
  7. package/packages/memory-user-memory/package.json +2 -1
  8. package/packages/memory-user-memory/promptfoo/evals/activity/basic/buildMessages.ts +40 -0
  9. package/packages/memory-user-memory/promptfoo/evals/activity/basic/eval.yaml +13 -0
  10. package/packages/memory-user-memory/promptfoo/evals/activity/basic/prompt.ts +5 -0
  11. package/packages/memory-user-memory/promptfoo/evals/activity/basic/tests/cases.ts +106 -0
  12. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/buildMessages.ts +104 -0
  13. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/eval.yaml +13 -0
  14. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/prompt.ts +5 -0
  15. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/benchmark-locomo-payload-conv-26.json +149 -0
  16. package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/cases.ts +72 -0
  17. package/packages/memory-user-memory/promptfoo/response-formats/activity.json +370 -0
  18. package/packages/memory-user-memory/promptfoo/response-formats/experience.json +14 -0
  19. package/packages/memory-user-memory/promptfoo/response-formats/identity.json +281 -255
  20. package/packages/memory-user-memory/promptfooconfig.yaml +1 -0
  21. package/packages/memory-user-memory/scripts/generate-response-formats.ts +26 -2
  22. package/packages/memory-user-memory/src/extractors/activity.ts +44 -0
  23. package/packages/memory-user-memory/src/extractors/gatekeeper.test.ts +2 -1
  24. package/packages/memory-user-memory/src/extractors/gatekeeper.ts +2 -1
  25. package/packages/memory-user-memory/src/extractors/index.ts +1 -0
  26. package/packages/memory-user-memory/src/prompts/gatekeeper.ts +3 -3
  27. package/packages/memory-user-memory/src/prompts/index.ts +7 -1
  28. package/packages/memory-user-memory/src/prompts/layers/activity.ts +90 -0
  29. package/packages/memory-user-memory/src/prompts/layers/index.ts +1 -0
  30. package/packages/memory-user-memory/src/providers/existingUserMemory.test.ts +25 -1
  31. package/packages/memory-user-memory/src/providers/existingUserMemory.ts +113 -0
  32. package/packages/memory-user-memory/src/schemas/activity.ts +315 -0
  33. package/packages/memory-user-memory/src/schemas/experience.ts +5 -5
  34. package/packages/memory-user-memory/src/schemas/gatekeeper.ts +1 -0
  35. package/packages/memory-user-memory/src/schemas/index.ts +1 -0
  36. package/packages/memory-user-memory/src/services/extractExecutor.ts +29 -0
  37. package/packages/memory-user-memory/src/types.ts +7 -0
  38. package/packages/types/src/serverConfig.ts +1 -1
  39. package/packages/types/src/userMemory/layers.ts +52 -0
  40. package/packages/types/src/userMemory/list.ts +20 -2
  41. package/packages/types/src/userMemory/shared.ts +22 -1
  42. package/packages/types/src/userMemory/trace.ts +1 -0
  43. package/packages/types/src/util.ts +9 -1
  44. package/src/libs/next/proxy/define-config.ts +1 -0
  45. package/src/server/globalConfig/parseMemoryExtractionConfig.ts +7 -1
  46. package/src/server/services/memory/userMemory/__tests__/extract.runtime.test.ts +2 -0
  47. package/src/server/services/memory/userMemory/extract.ts +108 -7
@@ -0,0 +1,315 @@
1
+ import type { GenerateObjectSchema } from '@lobechat/model-runtime';
2
+ import { ActivityTypeEnum, LayersEnum, TypesEnum } from '@lobechat/types';
3
+ import { type JSONSchema7 } from 'json-schema';
4
+
5
+ export interface WithActivity {
6
+ associatedLocations?: {
7
+ address?: string;
8
+ extra?: string | null;
9
+ name?: string;
10
+ tags?: string[];
11
+ type?: string;
12
+ }[];
13
+ associatedObjects?: {
14
+ extra?: string | null;
15
+ name?: string;
16
+ type?: string;
17
+ }[];
18
+ associatedSubjects?: {
19
+ extra?: string | null;
20
+ name?: string;
21
+ type?: string;
22
+ }[];
23
+ endsAt?: string;
24
+ feedback?: string;
25
+ metadata?: Record<string, unknown>;
26
+ narrative: string;
27
+ notes?: string;
28
+ startsAt?: string;
29
+ status?: string;
30
+ tags?: string[];
31
+ timezone?: string;
32
+ type: ActivityTypeEnum | string;
33
+ }
34
+
35
+ export interface ActivityMemoryItem {
36
+ details: string;
37
+ memoryCategory: string;
38
+ memoryLayer: LayersEnum.Activity;
39
+ memoryType: TypesEnum.Activity;
40
+ summary: string;
41
+ tags: string[];
42
+ title: string;
43
+ withActivity: WithActivity;
44
+ }
45
+
46
+ export interface ActivityMemory {
47
+ memories: ActivityMemoryItem[];
48
+ }
49
+
50
+ export const ActivityMemorySchema: GenerateObjectSchema = {
51
+ description:
52
+ 'Extract episodic activities with clear timelines, participants, objects, subjects, locations, and feelings. Temporal and associated fields are optional—omit when missing rather than guessing.',
53
+ name: 'activity_extraction',
54
+ schema: {
55
+ additionalProperties: false,
56
+ properties: {
57
+ memories: {
58
+ description:
59
+ 'Array of extracted activity memories. Use an empty array when no activity should be captured.',
60
+ items: {
61
+ additionalProperties: false,
62
+ description:
63
+ 'Self-contained activity memory describing what happened, when, where, with whom, and how it felt.',
64
+ examples: [
65
+ {
66
+ details:
67
+ 'Talked through renewal scope, confirmed timeline flexibility, and captured follow-ups.',
68
+ memoryCategory: 'work',
69
+ memoryType: 'activity',
70
+ summary: 'Client Q2 renewal meeting with Alice (ACME)',
71
+ tags: ['meeting', 'client', 'renewal'],
72
+ title: 'ACME Q2 renewal meeting',
73
+ withActivity: {
74
+ associatedLocations: [
75
+ {
76
+ address: '123 Main St, New York, NY',
77
+ name: 'ACME HQ',
78
+ },
79
+ ],
80
+ associatedSubjects: [
81
+ { name: 'Alice Smith', type: 'person' },
82
+ ],
83
+ endsAt: '2024-05-03T15:00:00-04:00',
84
+ feedback: 'Positive momentum; Alice felt heard and open to renewal.',
85
+ narrative:
86
+ 'Alice and User reviewed Q2 renewal scope, aligned on reduced deliverables, and agreed to share revised pricing next week.',
87
+ notes: 'Agenda: renewal scope, pricing, next steps.',
88
+ startsAt: '2024-05-03T14:00:00-04:00',
89
+ status: 'completed',
90
+ timezone: 'America/New_York',
91
+ type: 'meeting',
92
+ },
93
+ },
94
+ {
95
+ details: 'Routine check-up; discussed migraines and sleep habits.',
96
+ memoryCategory: 'health',
97
+ memoryType: 'activity',
98
+ summary: 'Doctor appointment with Dr. Kim about migraines',
99
+ tags: ['appointment', 'health'],
100
+ title: 'Neurology follow-up',
101
+ withActivity: {
102
+ associatedLocations: [
103
+ {
104
+ name: 'City Neurology Clinic',
105
+ },
106
+ ],
107
+ associatedSubjects: [
108
+ { name: 'Dr. Kim', type: 'person' },
109
+ ],
110
+ feedback: 'Felt reassured; plan seems manageable.',
111
+ narrative:
112
+ 'User saw Dr. Kim to review migraine frequency; decided to track sleep, hydration, and start a low-dose preventive.',
113
+ notes: 'Discussed triggers, hydration, and medication side effects.',
114
+ status: 'completed',
115
+ type: 'appointment',
116
+ },
117
+ },
118
+ ],
119
+ properties: {
120
+ details: {
121
+ description:
122
+ 'Optional detailed information or longer notes supporting the summary and narrative.',
123
+ type: 'string',
124
+ },
125
+ memoryCategory: {
126
+ description:
127
+ 'Memory category best matching the activity (e.g., work, health, travel, relationships).',
128
+ type: 'string',
129
+ },
130
+ memoryType: {
131
+ const: TypesEnum.Activity,
132
+ description: 'Memory type; always activity.',
133
+ type: 'string',
134
+ },
135
+ summary: {
136
+ description: 'Concise overview of this activity.',
137
+ type: 'string',
138
+ },
139
+ tags: {
140
+ description: 'Model-generated tags summarizing key facets of the activity.',
141
+ items: { type: 'string' },
142
+ type: 'array',
143
+ },
144
+ title: {
145
+ description:
146
+ 'Brief descriptive title for the activity, e.g., "Dinner with friends at Marina".',
147
+ type: 'string',
148
+ },
149
+ withActivity: {
150
+ additionalProperties: false,
151
+ description:
152
+ 'Structured activity fields. Temporal and association values are optional—include only when the user mentioned them.',
153
+ properties: {
154
+ associatedLocations: {
155
+ description:
156
+ 'Places linked to this activity. Capture any mentioned venue, address, or setting.',
157
+ items: {
158
+ additionalProperties: false,
159
+ properties: {
160
+ address: {
161
+ description: 'Free-form address or directions if provided.',
162
+ type: ['string', 'null'],
163
+ },
164
+ extra: {
165
+ description: 'Optional key-value metadata related to the location.',
166
+ type: ['string', 'null'],
167
+ },
168
+ name: {
169
+ description: 'Place name or venue label.',
170
+ type: 'string',
171
+ },
172
+ tags: {
173
+ description: 'Place-related tags (e.g., indoor, outdoor, virtual).',
174
+ items: { type: 'string' },
175
+ type: ['array', 'null'],
176
+ },
177
+ type: {
178
+ description: 'Place type or category (office, clinic, restaurant, virtual).',
179
+ type: 'string',
180
+ },
181
+ },
182
+ required: ['type', 'name', 'address', 'tags', 'extra'],
183
+ type: 'object',
184
+ },
185
+ type: 'array',
186
+ },
187
+ associatedObjects: {
188
+ description:
189
+ 'Non-living entities or items tied to the activity (e.g., transportation for trips, devices, tools).',
190
+ items: {
191
+ additionalProperties: false,
192
+ properties: {
193
+ extra: {
194
+ description: 'Optional key-value metadata related to the object.',
195
+ type: ['string', 'null'],
196
+ },
197
+ name: {
198
+ description: 'Name or label of the object (e.g., “MacBook”, “flight UA123”).',
199
+ type: 'string',
200
+ },
201
+ type: {
202
+ description: 'Object category (e.g., transportation, device, document).',
203
+ enum: ['application', 'item', 'knowledge', 'other', 'person', 'place'],
204
+ type: 'string',
205
+ },
206
+ },
207
+ required: ['type', 'name', 'extra'],
208
+ type: 'object',
209
+ },
210
+ type: 'array',
211
+ },
212
+ associatedSubjects: {
213
+ description:
214
+ 'Living beings involved (people, pets, groups). Use when the subject lacks a known identity ID.',
215
+ items: {
216
+ additionalProperties: false,
217
+ properties: {
218
+ extra: {
219
+ description: 'Optional key-value metadata related to the subject.',
220
+ type: ['string', 'null'],
221
+ },
222
+ name: {
223
+ description: 'Name or short label of the subject.',
224
+ type: 'string',
225
+ },
226
+ type: {
227
+ description: 'Subject category (e.g., person, pet, group).',
228
+ enum: ['person', 'pet', 'group', 'other'],
229
+ type: 'string',
230
+ },
231
+ },
232
+ required: ['type', 'name', 'extra'],
233
+ type: 'object',
234
+ },
235
+ type: 'array',
236
+ },
237
+ endsAt: {
238
+ description:
239
+ 'ISO 8601 end time for the activity when specified. Omit if not explicitly provided.',
240
+ format: 'date-time',
241
+ type: ['string', 'null'],
242
+ },
243
+ feedback: {
244
+ description:
245
+ 'Subjective feelings or evaluation of how the activity went (mood, satisfaction, effort).',
246
+ type: ['string', 'null'],
247
+ },
248
+ metadata: {
249
+ additionalProperties: false,
250
+ description:
251
+ 'Additional structured metadata to keep raw hints (JSON object). Use sparingly.',
252
+ type: ['object', 'null'],
253
+ },
254
+ narrative: {
255
+ description:
256
+ 'Factual story of what happened (chronology, participants, outcomes). Required for recall.',
257
+ type: 'string',
258
+ },
259
+ notes: {
260
+ description:
261
+ 'Short annotations such as agenda, preparation, or quick bullets distinct from narrative.',
262
+ type: ['string', 'null'],
263
+ },
264
+ startsAt: {
265
+ description:
266
+ 'ISO 8601 start time for the activity when specified. Omit if not explicitly provided.',
267
+ format: 'date-time',
268
+ type: ['string', 'null'],
269
+ },
270
+ status: {
271
+ description:
272
+ 'Lifecycle status when mentioned. Use planned/completed/cancelled/ongoing/on_hold/pending. Omit if unclear.',
273
+ enum: ['planned', 'completed', 'cancelled', 'ongoing', 'on_hold', 'pending'],
274
+ type: ['string', 'null'],
275
+ },
276
+ tags: {
277
+ description: 'Optional activity-specific tags or facets.',
278
+ items: { type: 'string' },
279
+ type: ['array', 'null'],
280
+ },
281
+ timezone: {
282
+ description:
283
+ 'IANA timezone string for the start/end times when provided (e.g., "America/New_York").',
284
+ type: ['string', 'null'],
285
+ },
286
+ type: {
287
+ description:
288
+ 'Activity type enum. Choose the closest match; fall back to "other" when unclear.',
289
+ enum: Object.values(ActivityTypeEnum),
290
+ type: 'string',
291
+ },
292
+ },
293
+ required: ['type', 'narrative', 'feedback', 'notes', 'associatedLocations', 'associatedSubjects', 'associatedObjects', 'startsAt', 'endsAt', 'status', 'tags', 'timezone', 'metadata'],
294
+ type: 'object',
295
+ },
296
+ },
297
+ required: [
298
+ 'title',
299
+ 'summary',
300
+ 'details',
301
+ 'memoryType',
302
+ 'memoryCategory',
303
+ 'tags',
304
+ 'withActivity',
305
+ ],
306
+ type: 'object',
307
+ },
308
+ type: 'array',
309
+ },
310
+ } satisfies JSONSchema7['properties'],
311
+ required: ['memories'],
312
+ type: 'object',
313
+ },
314
+ strict: true,
315
+ };
@@ -8,6 +8,11 @@ import { MemoryTypeSchema } from './common';
8
8
  export const WithExperienceSchema = z.object({
9
9
  action: z.string().describe('Narrative describing actions taken or behaviors exhibited'),
10
10
  keyLearning: z.string().describe('Narrative describing key insights or lessons learned'),
11
+ knowledgeValueScore: z
12
+ .number()
13
+ .min(0)
14
+ .max(1)
15
+ .describe('Numeric score (0-1) describing how reusable and shareable this experience is'),
11
16
  labels: z.array(z.string()).describe('Model generated tags that summarize the experience facets'),
12
17
  possibleOutcome: z.string().describe('Narrative describing potential outcomes or learnings'),
13
18
  problemSolvingScore: z
@@ -15,11 +20,6 @@ export const WithExperienceSchema = z.object({
15
20
  .min(0)
16
21
  .max(1)
17
22
  .describe('Numeric score (0-1) describing how effectively the problem was solved'),
18
- knowledgeValueScore: z
19
- .number()
20
- .min(0)
21
- .max(1)
22
- .describe('Numeric score (0-1) describing how reusable and shareable this experience is'),
23
23
  reasoning: z.string().describe('Narrative describing the thought process or motivations'),
24
24
  scoreConfidence: z
25
25
  .number()
@@ -14,6 +14,7 @@ export type LayerDecision = z.infer<typeof LayerDecisionSchema>;
14
14
  * Gatekeeper result schema for memory layers
15
15
  */
16
16
  export const GatekeeperResultSchema = z.object({
17
+ activity: LayerDecisionSchema,
17
18
  context: LayerDecisionSchema,
18
19
  experience: LayerDecisionSchema,
19
20
  identity: LayerDecisionSchema,
@@ -1,4 +1,5 @@
1
1
  export * from './common';
2
+ export * from './activity';
2
3
  export * from './context';
3
4
  export * from './experience';
4
5
  export * from './gatekeeper';
@@ -12,6 +12,7 @@ import { attributesCommon } from '@lobechat/observability-otel/node';
12
12
  import { LayersEnum } from '@lobechat/types';
13
13
 
14
14
  import {
15
+ ActivityExtractor,
15
16
  ContextExtractor,
16
17
  ExperienceExtractor,
17
18
  IdentityExtractor,
@@ -32,6 +33,7 @@ import {
32
33
  } from '../types';
33
34
 
34
35
  const LAYER_ORDER: LayersEnum[] = [
36
+ 'activity' as LayersEnum,
35
37
  'identity' as LayersEnum,
36
38
  'context' as LayersEnum,
37
39
  'preference' as LayersEnum,
@@ -39,6 +41,7 @@ const LAYER_ORDER: LayersEnum[] = [
39
41
  ];
40
42
 
41
43
  const LAYER_LABEL_MAP: Record<LayersEnum, string> = {
44
+ activity: 'activities',
42
45
  context: 'contexts',
43
46
  experience: 'experiences',
44
47
  identity: 'identities',
@@ -61,6 +64,7 @@ export interface MemoryExtractionServiceOptions {
61
64
 
62
65
  export interface MemoryExtractionLayerOutputTypes {
63
66
  [LayersEnum.Context]: Awaited<ReturnType<ContextExtractor['structuredCall']>>;
67
+ [LayersEnum.Activity]: Awaited<ReturnType<ActivityExtractor['structuredCall']>>;
64
68
  [LayersEnum.Experience]: Awaited<ReturnType<ExperienceExtractor['structuredCall']>>;
65
69
  [LayersEnum.Preference]: Awaited<ReturnType<PreferenceExtractor['structuredCall']>>;
66
70
  [LayersEnum.Identity]: Awaited<ReturnType<IdentityExtractor['structuredCall']>>;
@@ -79,6 +83,7 @@ export class MemoryExtractionService<RO> {
79
83
  private readonly contextExtractor: ContextExtractor;
80
84
  private readonly experienceExtractor: ExperienceExtractor;
81
85
  private readonly preferenceExtractor: PreferenceExtractor;
86
+ private readonly activityExtractor: ActivityExtractor;
82
87
 
83
88
  private readonly gatekeeperRuntime: ModelRuntime;
84
89
  private readonly layerRuntime: ModelRuntime;
@@ -115,6 +120,9 @@ export class MemoryExtractionService<RO> {
115
120
  this.identityExtractor = new IdentityExtractor(
116
121
  buildExtractorConfig(LayersEnum.Identity, 'layer-identity'),
117
122
  );
123
+ this.activityExtractor = new ActivityExtractor(
124
+ buildExtractorConfig(LayersEnum.Activity, 'layer-activity'),
125
+ );
118
126
  this.contextExtractor = new ContextExtractor(
119
127
  buildExtractorConfig(LayersEnum.Context, 'layer-context'),
120
128
  );
@@ -214,6 +222,7 @@ export class MemoryExtractionService<RO> {
214
222
  const outputs = await this.runLayers(job, layersToExtract, { ...options });
215
223
 
216
224
  const processedLayersCount = {
225
+ activity: outputs.activity?.data ? outputs.activity?.data?.memories?.length : 0,
217
226
  context: outputs.context?.data ? outputs.context?.data?.memories?.length : 0,
218
227
  experience: outputs.experience?.data ? outputs.experience?.data?.memories?.length : 0,
219
228
  identity: outputs.identity?.data
@@ -224,6 +233,7 @@ export class MemoryExtractionService<RO> {
224
233
  preference: outputs.preference?.data ? outputs.preference?.data?.memories?.length : 0,
225
234
  };
226
235
  const processedErrorsCount = {
236
+ activity: outputs.activity?.error ? 1 : 0,
227
237
  context: outputs.context?.error ? 1 : 0,
228
238
  experience: outputs.experience?.error ? 1 : 0,
229
239
  identity: outputs.identity?.error ? 1 : 0,
@@ -281,6 +291,15 @@ export class MemoryExtractionService<RO> {
281
291
  );
282
292
  }
283
293
 
294
+ private async runActivityLayer(job: MemoryExtractionJob, options: ExtractorOptions) {
295
+ return this.runLayerExtractor(job, LayersEnum.Activity, () =>
296
+ this.activityExtractor.structuredCall({
297
+ ...options,
298
+ language: options.language ?? 'English',
299
+ }),
300
+ );
301
+ }
302
+
284
303
  private async runExperienceLayer(job: MemoryExtractionJob, options: ExtractorOptions) {
285
304
  return this.runLayerExtractor(job, LayersEnum.Experience, () =>
286
305
  this.experienceExtractor.structuredCall({
@@ -347,6 +366,12 @@ export class MemoryExtractionService<RO> {
347
366
  | { error: unknown };
348
367
  break;
349
368
  }
369
+ case LayersEnum.Activity: {
370
+ outputs.activity = result as
371
+ | { data: MemoryExtractionLayerOutputTypes[typeof layer] }
372
+ | { error: unknown };
373
+ break;
374
+ }
350
375
  case LayersEnum.Experience: {
351
376
  outputs.experience = result as
352
377
  | { data: MemoryExtractionLayerOutputTypes[typeof layer] }
@@ -374,6 +399,7 @@ export class MemoryExtractionService<RO> {
374
399
  await Promise.all(
375
400
  (
376
401
  [
402
+ LayersEnum.Activity,
377
403
  LayersEnum.Context,
378
404
  LayersEnum.Experience,
379
405
  LayersEnum.Preference,
@@ -407,6 +433,9 @@ export class MemoryExtractionService<RO> {
407
433
  case LayersEnum.Context: {
408
434
  return await this.runContextLayer(job, options);
409
435
  }
436
+ case LayersEnum.Activity: {
437
+ return await this.runActivityLayer(job, options);
438
+ }
410
439
  case LayersEnum.Experience: {
411
440
  return await this.runExperienceLayer(job, options);
412
441
  }
@@ -6,6 +6,7 @@ import type {
6
6
  import type { LayersEnum, MemorySourceType } from '@lobechat/types';
7
7
 
8
8
  import type {
9
+ ActivityExtractor,
9
10
  ContextExtractor,
10
11
  ExperienceExtractor,
11
12
  IdentityExtractor,
@@ -14,6 +15,7 @@ import type {
14
15
 
15
16
  export type MemoryExtractionAgent =
16
17
  | 'gatekeeper'
18
+ | 'layer-activity'
17
19
  | 'layer-context'
18
20
  | 'layer-experience'
19
21
  | 'layer-identity'
@@ -124,6 +126,10 @@ export interface PersistedMemoryResult {
124
126
  }
125
127
 
126
128
  export type MemoryExtractionLayerOutputs = Partial<{
129
+ activity: {
130
+ data?: Awaited<ReturnType<ActivityExtractor['structuredCall']>>;
131
+ error?: unknown;
132
+ };
127
133
  context: {
128
134
  data?: Awaited<ReturnType<ContextExtractor['structuredCall']>>;
129
135
  error?: unknown;
@@ -143,6 +149,7 @@ export type MemoryExtractionLayerOutputs = Partial<{
143
149
  }>;
144
150
 
145
151
  export interface GatekeeperDecision {
152
+ activity: MemoryLayerDecision;
146
153
  context: MemoryLayerDecision;
147
154
  experience: MemoryLayerDecision;
148
155
  identity: MemoryLayerDecision;
@@ -10,7 +10,7 @@ import {
10
10
  UserSystemAgentConfig,
11
11
  } from './user/settings';
12
12
 
13
- export type GlobalMemoryLayer = 'context' | 'experience' | 'identity' | 'preference';
13
+ export type GlobalMemoryLayer = 'activity' | 'context' | 'experience' | 'identity' | 'preference';
14
14
 
15
15
  export interface MemoryAgentPublicConfig {
16
16
  baseURL?: string;
@@ -22,6 +22,26 @@ export enum UserMemoryContextSubjectType {
22
22
  }
23
23
  export const CONTEXT_SUBJECT_TYPES = Object.values(UserMemoryContextSubjectType);
24
24
 
25
+ export interface UserMemoryAssociatedLocation {
26
+ address?: string | null;
27
+ extra?: Record<string, unknown> | null;
28
+ name?: string | null;
29
+ tags?: string[] | null;
30
+ type?: string | null;
31
+ }
32
+
33
+ export interface UserMemoryAssociatedObject {
34
+ extra?: Record<string, unknown> | null;
35
+ name?: string;
36
+ type?: string | null;
37
+ }
38
+
39
+ export interface UserMemoryAssociatedSubject {
40
+ extra?: Record<string, unknown> | null;
41
+ name?: string;
42
+ type?: string | null;
43
+ }
44
+
25
45
  export interface UserMemoryContext extends UserMemoryTimestamps {
26
46
  associatedObjects:
27
47
  | {
@@ -112,3 +132,35 @@ export type UserMemoryPreferenceWithoutVectors = Omit<
112
132
  >;
113
133
 
114
134
  export type UserMemoryPreferencesListItem = Omit<UserMemoryPreferenceWithoutVectors, 'suggestions'>;
135
+
136
+ export interface UserMemoryActivity extends UserMemoryTimestamps {
137
+ associatedLocations: UserMemoryAssociatedLocation[] | null;
138
+ associatedObjects: UserMemoryAssociatedObject[] | null;
139
+ associatedSubjects: UserMemoryAssociatedSubject[] | null;
140
+ endsAt: Date | null;
141
+ feedback: string | null;
142
+ feedbackVector: number[] | null;
143
+ id: string;
144
+ metadata: Record<string, unknown> | null;
145
+ narrative: string | null;
146
+ narrativeVector: number[] | null;
147
+ notes: string | null;
148
+ startsAt: Date | null;
149
+ status: string | null;
150
+ tags: string[] | null;
151
+ timezone: string | null;
152
+ type: string | null;
153
+ userId: string | null;
154
+ userMemoryId: string | null;
155
+ }
156
+
157
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
158
+ export type UserMemoryActivityWithoutVectors = Omit<
159
+ UserMemoryActivity,
160
+ 'narrativeVector' | 'feedbackVector'
161
+ >;
162
+
163
+ export type UserMemoryActivitiesListItem = Omit<
164
+ UserMemoryActivityWithoutVectors,
165
+ 'feedback' | 'narrative' | 'notes'
166
+ >;
@@ -5,6 +5,8 @@ import {
5
5
  UserMemoryContextsListItem,
6
6
  UserMemoryExperiencesListItem,
7
7
  UserMemoryPreferencesListItem,
8
+ UserMemoryActivitiesListItem,
9
+ UserMemoryActivityWithoutVectors,
8
10
  } from './layers'
9
11
  import {
10
12
  UserMemoryIdentityWithoutVectors,
@@ -87,14 +89,30 @@ export interface IdentityMemoryDetail {
87
89
  sourceType?: MemorySourceType;
88
90
  }
89
91
 
92
+ export interface ActivityMemorySimple {
93
+ activity: UserMemoryActivitiesListItem;
94
+ layer: LayersEnum.Activity;
95
+ memory: UserMemoryListItem;
96
+ }
97
+
98
+ export interface ActivityMemoryDetail {
99
+ activity: UserMemoryActivityWithoutVectors;
100
+ layer: LayersEnum.Activity;
101
+ memory: UserMemoryWithoutVectors;
102
+ source?: MemorySource;
103
+ sourceType?: MemorySourceType;
104
+ }
105
+
90
106
  export type UserMemoryItemSimple =
91
107
  | ContextMemorySimple
92
108
  | ExperienceMemorySimple
93
109
  | IdentityMemorySimple
94
- | PreferenceMemorySimple;
110
+ | PreferenceMemorySimple
111
+ | ActivityMemorySimple;
95
112
 
96
113
  export type UserMemoryDetail =
97
114
  | ContextMemoryDetail
98
115
  | ExperienceMemoryDetail
99
116
  | IdentityMemoryDetail
100
- | PreferenceMemoryDetail;
117
+ | PreferenceMemoryDetail
118
+ | ActivityMemoryDetail;
@@ -46,6 +46,7 @@ export enum IdentityTypeEnum {
46
46
  export const IDENTITY_TYPES = Object.values(IdentityTypeEnum);
47
47
 
48
48
  export enum LayersEnum {
49
+ Activity = 'activity',
49
50
  Context = 'context',
50
51
  Experience = 'experience',
51
52
  Identity = 'identity',
@@ -80,7 +81,6 @@ export const CONTEXT_STATUS = Object.values(ContextStatusEnum);
80
81
  /**
81
82
  * Shared types for memory list queries
82
83
  */
83
-
84
84
  export interface BaseListParams {
85
85
  order?: 'asc' | 'desc';
86
86
  page?: number;
@@ -106,3 +106,24 @@ export interface BaseListItem {
106
106
  type: string | null;
107
107
  updatedAt: Date;
108
108
  }
109
+
110
+ export enum ActivityTypeEnum {
111
+ Appointment = 'appointment',
112
+ Call = 'call',
113
+ Celebration = 'celebration',
114
+ Class = 'class',
115
+ Conference = 'conference',
116
+ Errand = 'errand',
117
+ Event = 'event',
118
+ Exercise = 'exercise',
119
+ Meal = 'meal',
120
+ Meeting = 'meeting',
121
+ Other = 'other',
122
+ ProjectSession = 'project-session',
123
+ Social = 'social',
124
+ Task = 'task',
125
+ Trip = 'trip',
126
+ Workshop = 'workshop',
127
+ }
128
+
129
+ export const ACTIVITY_TYPES = Object.values(ActivityTypeEnum);
@@ -3,6 +3,7 @@ import type { MemorySourceType } from './list';
3
3
 
4
4
  export type MemoryExtractionAgent =
5
5
  | 'gatekeeper'
6
+ | 'layer-activity'
6
7
  | 'layer-context'
7
8
  | 'layer-experience'
8
9
  | 'layer-identity'
@@ -1,2 +1,10 @@
1
1
  export type Primitive = number | string | boolean | undefined | null | any[];
2
- export type Optional<T, K extends keyof T> = { [P in K]?: T[P] } & { [P in Exclude<keyof T, K>]: T[P] extends Primitive ? T[P] : Optional<T[P], keyof T[P] & K> };
2
+ type OptionalKeys<T> = { [P in keyof T]-?: undefined extends T[P] ? P : never }[keyof T];
3
+ type OptionalField<T, P extends keyof T, K extends keyof T> = T[P] extends Primitive
4
+ ? T[P]
5
+ : Optional<T[P], keyof T[P] & K>;
6
+
7
+ export type Optional<T, K extends keyof T> = T extends null | undefined
8
+ ? T
9
+ : Partial<Pick<T, K | OptionalKeys<T>>> &
10
+ { [P in Exclude<keyof T, K | OptionalKeys<T>>]: OptionalField<T, P, K> };
@@ -162,6 +162,7 @@ export function defineConfig() {
162
162
  '/api/webhooks(.*)',
163
163
  '/api/workflows(.*)',
164
164
  '/api/agent(.*)',
165
+ '/api/dev(.*)',
165
166
  '/webapi(.*)',
166
167
  '/trpc(.*)',
167
168
  // better auth