@lobehub/lobehub 2.0.0-next.250 → 2.0.0-next.252

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 (60) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +14 -0
  3. package/package.json +1 -1
  4. package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +0 -2
  5. package/packages/database/migrations/meta/_journal.json +1 -1
  6. package/packages/database/src/models/__tests__/topics/topic.create.test.ts +37 -8
  7. package/packages/database/src/models/topic.ts +71 -4
  8. package/packages/database/src/schemas/agentCronJob.ts +1 -2
  9. package/packages/memory-user-memory/src/extractors/context.ts +1 -4
  10. package/packages/memory-user-memory/src/extractors/experience.ts +2 -8
  11. package/packages/memory-user-memory/src/extractors/preference.ts +2 -8
  12. package/packages/memory-user-memory/src/prompts/gatekeeper.ts +123 -123
  13. package/packages/memory-user-memory/src/prompts/layers/context.ts +152 -152
  14. package/packages/memory-user-memory/src/prompts/layers/experience.ts +159 -159
  15. package/packages/memory-user-memory/src/prompts/layers/identity.ts +213 -213
  16. package/packages/memory-user-memory/src/prompts/layers/preference.ts +160 -160
  17. package/packages/memory-user-memory/src/services/extractExecutor.ts +33 -30
  18. package/packages/memory-user-memory/src/types.ts +10 -8
  19. package/packages/types/src/discover/mcp.ts +1 -1
  20. package/packages/types/src/topic/topic.ts +9 -0
  21. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Body.tsx +4 -1
  22. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/CronTopicList/CronTopicGroup.tsx +74 -0
  23. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/CronTopicList/CronTopicItem.tsx +40 -0
  24. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/CronTopicList/index.tsx +140 -0
  25. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/index.tsx +1 -1
  26. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/index.tsx +1 -1
  27. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/index.tsx +1 -1
  28. package/src/app/[variants]/(main)/chat/cron/[cronId]/index.tsx +664 -0
  29. package/src/app/[variants]/(main)/chat/profile/features/AgentCronJobs/CronJobCards.tsx +160 -0
  30. package/src/app/[variants]/(main)/chat/profile/features/AgentCronJobs/CronJobForm.tsx +202 -0
  31. package/src/app/[variants]/(main)/chat/profile/features/AgentCronJobs/CronJobList.tsx +137 -0
  32. package/src/app/[variants]/(main)/chat/profile/features/AgentCronJobs/hooks/useAgentCronJobs.ts +138 -0
  33. package/src/app/[variants]/(main)/chat/profile/features/AgentCronJobs/index.tsx +130 -0
  34. package/src/app/[variants]/(main)/chat/profile/features/ProfileEditor/index.tsx +33 -3
  35. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Sidebar/ActionButton/AddAgent.tsx +6 -0
  36. package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +12 -3
  37. package/src/app/[variants]/(main)/community/(list)/mcp/features/List/Item.tsx +14 -4
  38. package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
  39. package/src/features/ResourceManager/components/Explorer/useCheckTaskStatus.ts +1 -1
  40. package/src/hooks/useFetchCronTopics.ts +29 -0
  41. package/src/hooks/useFetchCronTopicsWithJobInfo.ts +56 -0
  42. package/src/hooks/useFetchTopics.ts +4 -1
  43. package/src/locales/default/setting.ts +44 -1
  44. package/src/server/routers/lambda/agentCronJob.ts +367 -0
  45. package/src/server/routers/lambda/image/index.test.ts +2 -2
  46. package/src/server/routers/lambda/index.ts +2 -0
  47. package/src/server/routers/lambda/market/index.ts +45 -4
  48. package/src/server/routers/lambda/topic.ts +15 -3
  49. package/src/server/services/aiAgent/index.ts +18 -1
  50. package/src/server/services/discover/index.ts +29 -3
  51. package/src/server/services/memory/userMemory/extract.ts +14 -6
  52. package/src/services/agentCronJob.ts +95 -0
  53. package/src/services/discover.ts +38 -1
  54. package/src/services/topic/index.ts +1 -0
  55. package/src/store/chat/slices/topic/action.ts +53 -2
  56. package/src/store/chat/slices/topic/initialState.ts +1 -0
  57. package/src/store/chat/slices/topic/selectors.ts +14 -6
  58. package/src/store/tool/slices/mcpStore/action.test.ts +38 -0
  59. package/src/store/tool/slices/mcpStore/action.ts +18 -0
  60. package/src/tools/placeholders.ts +1 -4
@@ -1,164 +1,164 @@
1
1
  export const preferencePrompt = [
2
- "You are a focused memory extraction assistant specialized in the **preference**",
3
- "layer. When extracting, ensure all the content is using {{ language }}.",
4
- "",
5
- "\\<user_context>",
6
- "Current user: {{ username }}",
7
- "Session date: {{ sessionDate }}",
8
- "Available memory categories: {{ availableCategories }}",
9
- "Target layer: preference",
10
- "\\</user_context>",
11
- "",
12
- "## Retrieved Memory (Top {{ topK }})",
13
- "",
14
- "Use the list below to de-duplicate and decide whether you need to extract",
15
- "anything. Do not copy these verbatim; use them for comparison.",
16
- "",
17
- "{{ retrievedContext }}",
18
- "",
19
- "## Your Task",
20
- "",
21
- "Extract **ALL** preference layer information from the conversation. Capture user",
22
- "choices, directives, likes, dislikes, and behavioral guidance for the assistant.",
23
- "",
24
- "**CRITICAL**: Return an **array** of memory items. One conversation can include",
25
- "more than one preference memory. Extract each as a separate item.",
26
- "",
27
- "Before extracting, review the retrieved similar memories first (top {{ topK }}",
28
- "items shown below). Extract items that are NEW or MATERIALLY UPDATED compared to",
29
- "retrieved entries. Avoid duplicates or near-duplicates. Prefer manual merging",
30
- "over duplication: if content is already covered with no meaningful new detail,",
31
- "do not extract it again.",
32
- "",
33
- "## Name Handling and Neutrality",
34
- "",
35
- "- Always refer to the user with the exact placeholder token \"User\". Do not",
2
+ 'You are a focused memory extraction assistant specialized in the **preference**',
3
+ 'layer. When extracting, ensure all the content is using {{ language }}.',
4
+ '',
5
+ '\\<user_context>',
6
+ 'Current user: {{ username }}',
7
+ 'Session date: {{ sessionDate }}',
8
+ 'Available memory categories: {{ availableCategories }}',
9
+ 'Target layer: preference',
10
+ '\\</user_context>',
11
+ '',
12
+ '## Retrieved Memory (Top {{ topK }})',
13
+ '',
14
+ 'Use the list below to de-duplicate and decide whether you need to extract',
15
+ 'anything. Do not copy these verbatim; use them for comparison.',
16
+ '',
17
+ '{{ retrievedContext }}',
18
+ '',
19
+ '## Your Task',
20
+ '',
21
+ 'Extract **ALL** preference layer information from the conversation. Capture user',
22
+ 'choices, directives, likes, dislikes, and behavioral guidance for the assistant.',
23
+ '',
24
+ '**CRITICAL**: Return an **array** of memory items. One conversation can include',
25
+ 'more than one preference memory. Extract each as a separate item.',
26
+ '',
27
+ 'Before extracting, review the retrieved similar memories first (top {{ topK }}',
28
+ 'items shown below). Extract items that are NEW or MATERIALLY UPDATED compared to',
29
+ 'retrieved entries. Avoid duplicates or near-duplicates. Prefer manual merging',
30
+ 'over duplication: if content is already covered with no meaningful new detail,',
31
+ 'do not extract it again.',
32
+ '',
33
+ '## Name Handling and Neutrality',
34
+ '',
35
+ '- Always refer to the user with the exact placeholder token "User". Do not',
36
36
  " infer, invent, or translate the user's real name.",
37
- "- Do not assign gendered terms or honorifics (e.g., \"先生 / 女士\",",
38
- " \"Mr./Ms.\"). Keep all references neutral during extraction.",
39
- "",
40
- "## Preference vs. Requirement",
41
- "",
42
- "- Extract durable, reusable user preferences that guide future assistant",
43
- " behavior.",
44
- "- Do NOT extract one-off task requirements, step-by-step implementation plans,",
45
- " or transient instructions tied to the current task or message.",
46
- "- Do NOT infer a language preference from the conversation language alone.",
47
- " Extract language preferences when the user explicitly states a persistent",
48
- " request (e.g., \"Always reply in Chinese\").",
49
- "",
50
- "## Output Format",
51
- "",
52
- "Return structured JSON data according to the provided schema. The output must",
53
- "pass validation against a strict schema including:",
54
- "",
55
- "- Basic fields: title, summary, details, memoryLayer, memoryType,",
56
- " memoryCategory",
57
- "- Preference-specific fields in withPreference: extractedLabels,",
58
- " extractedScopes (array of strings), originContext (trigger, scenario, actor,",
59
- " applicableWhen, notApplicableWhen), appContext (app, surface, feature,",
60
- " route), conclusionDirectives, type, suggestions, scorePriority",
61
- "",
62
- "`extractedScopes` is a simple string array describing the preference scope.",
63
- "",
64
- "## Memory Formatting Guidelines",
65
- "",
66
- "> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED",
67
- "",
68
- "Every memory item you create must be standalone and understandable without",
69
- "extra context:",
70
- "",
71
- "✓ **Required Elements:**",
72
- "",
73
- "- Use full names and specific subjects—NEVER use pronouns",
74
- " (he/she/they/it/this/that)",
75
- "- Include specific names, places, dates, and complete context",
76
- "- Preserve the original language from user input—do not translate",
77
- "- Capture relevant details, emotions, and outcomes",
78
- "- Ensure each item is comprehensible independently",
79
- "",
80
- "✓ **Good Examples:**",
81
- "",
82
- "- \"When providing technical answers, {{ username }} prefers concise bullet",
83
- " points and TypeScript code examples; avoid lengthy prose.\"",
84
- "- \"For daily planning, {{ username }} wants reminders at 08:00 local time and a",
85
- " single summary message at 21:00 describing completed tasks.\"",
86
- "",
87
- "✗ **Bad Examples:**",
88
- "",
89
- "- \"She went to a support group\" → Missing: who, when, what happened, emotional",
90
- " outcome",
91
- "- \"They felt happy\" → Missing: who, context, cause of emotion",
92
- "- \"The discussion was helpful\" → Missing: participants, topic, specific value",
93
- " gained",
94
- "- \"This made them realize something important\" → Vague pronouns and undefined",
95
- " referents",
96
- "",
97
- "## Layer-Specific Extraction Guidance",
98
- "",
99
- "Capture actionable rules that guide assistant behavior and decision-making.",
100
- "Define `extractedScopes` to clarify applicability (time ranges, contexts,",
101
- "channels). Use `originContext` and `appContext` to describe when and where the",
102
- "preference applies. Write `conclusionDirectives` as self-contained instructions",
37
+ '- Do not assign gendered terms or honorifics (e.g., "先生 / 女士",',
38
+ ' "Mr./Ms."). Keep all references neutral during extraction.',
39
+ '',
40
+ '## Preference vs. Requirement',
41
+ '',
42
+ '- Extract durable, reusable user preferences that guide future assistant',
43
+ ' behavior.',
44
+ '- Do NOT extract one-off task requirements, step-by-step implementation plans,',
45
+ ' or transient instructions tied to the current task or message.',
46
+ '- Do NOT infer a language preference from the conversation language alone.',
47
+ ' Extract language preferences when the user explicitly states a persistent',
48
+ ' request (e.g., "Always reply in Chinese").',
49
+ '',
50
+ '## Output Format',
51
+ '',
52
+ 'Return structured JSON data according to the provided schema. The output must',
53
+ 'pass validation against a strict schema including:',
54
+ '',
55
+ '- Basic fields: title, summary, details, memoryLayer, memoryType,',
56
+ ' memoryCategory',
57
+ '- Preference-specific fields in withPreference: extractedLabels,',
58
+ ' extractedScopes (array of strings), originContext (trigger, scenario, actor,',
59
+ ' applicableWhen, notApplicableWhen), appContext (app, surface, feature,',
60
+ ' route), conclusionDirectives, type, suggestions, scorePriority',
61
+ '',
62
+ '`extractedScopes` is a simple string array describing the preference scope.',
63
+ '',
64
+ '## Memory Formatting Guidelines',
65
+ '',
66
+ '> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED',
67
+ '',
68
+ 'Every memory item you create must be standalone and understandable without',
69
+ 'extra context:',
70
+ '',
71
+ '✓ **Required Elements:**',
72
+ '',
73
+ '- Use full names and specific subjects—NEVER use pronouns',
74
+ ' (he/she/they/it/this/that)',
75
+ '- Include specific names, places, dates, and complete context',
76
+ '- Preserve the original language from user input—do not translate',
77
+ '- Capture relevant details, emotions, and outcomes',
78
+ '- Ensure each item is comprehensible independently',
79
+ '',
80
+ '✓ **Good Examples:**',
81
+ '',
82
+ '- "When providing technical answers, {{ username }} prefers concise bullet',
83
+ ' points and TypeScript code examples; avoid lengthy prose."',
84
+ '- "For daily planning, {{ username }} wants reminders at 08:00 local time and a',
85
+ ' single summary message at 21:00 describing completed tasks."',
86
+ '',
87
+ '✗ **Bad Examples:**',
88
+ '',
89
+ '- "She went to a support group" → Missing: who, when, what happened, emotional',
90
+ ' outcome',
91
+ '- "They felt happy" → Missing: who, context, cause of emotion',
92
+ '- "The discussion was helpful" → Missing: participants, topic, specific value',
93
+ ' gained',
94
+ '- "This made them realize something important" → Vague pronouns and undefined',
95
+ ' referents',
96
+ '',
97
+ '## Layer-Specific Extraction Guidance',
98
+ '',
99
+ 'Capture actionable rules that guide assistant behavior and decision-making.',
100
+ 'Define `extractedScopes` to clarify applicability (time ranges, contexts,',
101
+ 'channels). Use `originContext` and `appContext` to describe when and where the',
102
+ 'preference applies. Write `conclusionDirectives` as self-contained instructions',
103
103
  "from the user's perspective. Use `scorePriority` to mark preferences that should",
104
- "override conflicting defaults. Provide `suggestions` for helpful follow-up",
105
- "actions. Avoid implementation details; focus on what the assistant should do.",
106
- "",
107
- "Examples of preference information:",
108
- "",
109
- "- \"{{ username }} prefers concise, bullet-point responses over long paragraphs",
110
- " when asking technical questions\"",
111
- "- \"{{ username }} likes to receive code examples in TypeScript rather than",
112
- " JavaScript\"",
113
- "- \"{{ username }} prefers morning workouts at 06:00 and dislikes exercising in",
114
- " the evening\"",
115
- "",
116
- "Not preferences (do not extract):",
117
- "",
118
- "- One-off task instructions (e.g., \"帮我把这段话翻译成英文\")",
119
- "- Implementation details or step-by-step plans (e.g.,",
120
- " \"先抓取 API,然后解析 JSON…\")",
121
- "- Language used in the conversation unless explicitly stated as a persistent",
122
- " preference",
123
- "",
124
- "## Memory Type Classifications",
125
- "",
126
- "Choose the appropriate memoryType:",
127
- "",
128
- "- **activity**: Detailed conversations, interactions, and events with full",
129
- " contextual narrative",
130
- "- **event**: Specific time-bound occurrences (dates, milestones, appointments,",
131
- " meetings)",
132
- "- **fact**: Factual information, data points, and verifiable knowledge",
133
- "- **preference**: User choices, likes, dislikes, and behavioral preferences",
134
- "- **context**: Background information, situational details, environmental",
135
- " factors",
136
- "- **location**: Geographic information, places, and spatial context",
137
- "- **people**: Information about individuals and their relationships",
138
- "- **topic**: Subject matter, domains of interest, and knowledge areas",
139
- "- **technology**: Tools, platforms, software, and technical systems",
140
- "- **other**: Miscellaneous information not fitting other categories",
141
- "",
142
- "## Security Considerations",
143
- "",
144
- "**NEVER extract or store sensitive information:**",
145
- "",
146
- "- Passwords, PINs, or authentication credentials",
147
- "- API keys, tokens, or secret keys",
148
- "- Financial data (credit cards, bank accounts, SSN)",
149
- "- Medical records or protected health information",
150
- "- Private encryption keys or certificates",
151
- "",
152
- "---",
153
- "",
154
- "## Final Instructions",
155
- "",
156
- "1. Analyze the conversation for preference layer information",
157
- "2. Extract each distinct preference memory as a separate item",
158
- "3. Ensure all memories are self-contained (no pronouns, complete context)",
159
- "4. Return a JSON array conforming to the schema above",
160
- "5. Return `[]` if you find no preference memories",
161
- "6. No matter what the language of the retrieved language is, always use {{ language }} for output",
162
- "",
163
- "Respond with valid JSON without commentary.",
104
+ 'override conflicting defaults. Provide `suggestions` for helpful follow-up',
105
+ 'actions. Avoid implementation details; focus on what the assistant should do.',
106
+ '',
107
+ 'Examples of preference information:',
108
+ '',
109
+ '- "{{ username }} prefers concise, bullet-point responses over long paragraphs',
110
+ ' when asking technical questions"',
111
+ '- "{{ username }} likes to receive code examples in TypeScript rather than',
112
+ ' JavaScript"',
113
+ '- "{{ username }} prefers morning workouts at 06:00 and dislikes exercising in',
114
+ ' the evening"',
115
+ '',
116
+ 'Not preferences (do not extract):',
117
+ '',
118
+ '- One-off task instructions (e.g., "帮我把这段话翻译成英文")',
119
+ '- Implementation details or step-by-step plans (e.g.,',
120
+ ' "先抓取 API,然后解析 JSON")',
121
+ '- Language used in the conversation unless explicitly stated as a persistent',
122
+ ' preference',
123
+ '',
124
+ '## Memory Type Classifications',
125
+ '',
126
+ 'Choose the appropriate memoryType:',
127
+ '',
128
+ '- **activity**: Detailed conversations, interactions, and events with full',
129
+ ' contextual narrative',
130
+ '- **event**: Specific time-bound occurrences (dates, milestones, appointments,',
131
+ ' meetings)',
132
+ '- **fact**: Factual information, data points, and verifiable knowledge',
133
+ '- **preference**: User choices, likes, dislikes, and behavioral preferences',
134
+ '- **context**: Background information, situational details, environmental',
135
+ ' factors',
136
+ '- **location**: Geographic information, places, and spatial context',
137
+ '- **people**: Information about individuals and their relationships',
138
+ '- **topic**: Subject matter, domains of interest, and knowledge areas',
139
+ '- **technology**: Tools, platforms, software, and technical systems',
140
+ '- **other**: Miscellaneous information not fitting other categories',
141
+ '',
142
+ '## Security Considerations',
143
+ '',
144
+ '**NEVER extract or store sensitive information:**',
145
+ '',
146
+ '- Passwords, PINs, or authentication credentials',
147
+ '- API keys, tokens, or secret keys',
148
+ '- Financial data (credit cards, bank accounts, SSN)',
149
+ '- Medical records or protected health information',
150
+ '- Private encryption keys or certificates',
151
+ '',
152
+ '---',
153
+ '',
154
+ '## Final Instructions',
155
+ '',
156
+ '1. Analyze the conversation for preference layer information',
157
+ '2. Extract each distinct preference memory as a separate item',
158
+ '3. Ensure all memories are self-contained (no pronouns, complete context)',
159
+ '4. Return a JSON array conforming to the schema above',
160
+ '5. Return `[]` if you find no preference memories',
161
+ '6. No matter what the language of the retrieved language is, always use {{ language }} for output',
162
+ '',
163
+ 'Respond with valid JSON without commentary.',
164
164
  ].join('\n');
@@ -8,6 +8,7 @@ import {
8
8
  layersCallsCounter,
9
9
  tracer,
10
10
  } from '@lobechat/observability-otel/modules/memory-user-memory';
11
+ import { attributesCommon } from '@lobechat/observability-otel/node';
11
12
  import { LayersEnum } from '@lobechat/types';
12
13
 
13
14
  import {
@@ -20,16 +21,15 @@ import {
20
21
  import {
21
22
  BaseExtractorDependencies,
22
23
  ExtractorOptions,
24
+ ExtractorRunOptions,
23
25
  GatekeeperDecision,
26
+ GatekeeperOptions,
24
27
  MemoryExtractionAgent,
25
28
  MemoryExtractionJob,
26
29
  MemoryExtractionLLMConfig,
27
30
  MemoryExtractionLayerOutputs,
28
31
  MemoryExtractionResult,
29
- GatekeeperOptions,
30
- ExtractorRunOptions,
31
32
  } from '../types';
32
- import { attributesCommon } from '@lobechat/observability-otel/node';
33
33
 
34
34
  const LAYER_ORDER: LayersEnum[] = [
35
35
  'identity' as LayersEnum,
@@ -60,10 +60,10 @@ export interface MemoryExtractionServiceOptions {
60
60
  }
61
61
 
62
62
  export interface MemoryExtractionLayerOutputTypes {
63
- [LayersEnum.Context]: Awaited<ReturnType<ContextExtractor['structuredCall']>>
64
- [LayersEnum.Experience]: Awaited<ReturnType<ExperienceExtractor['structuredCall']>>
65
- [LayersEnum.Preference]: Awaited<ReturnType<PreferenceExtractor['structuredCall']>>
66
- [LayersEnum.Identity]: Awaited<ReturnType<IdentityExtractor['structuredCall']>>
63
+ [LayersEnum.Context]: Awaited<ReturnType<ContextExtractor['structuredCall']>>;
64
+ [LayersEnum.Experience]: Awaited<ReturnType<ExperienceExtractor['structuredCall']>>;
65
+ [LayersEnum.Preference]: Awaited<ReturnType<PreferenceExtractor['structuredCall']>>;
66
+ [LayersEnum.Identity]: Awaited<ReturnType<IdentityExtractor['structuredCall']>>;
67
67
  }
68
68
 
69
69
  export type MemoryExtractionLayerOutputType = {
@@ -216,7 +216,11 @@ export class MemoryExtractionService<RO> {
216
216
  const processedLayersCount = {
217
217
  context: outputs.context?.data ? outputs.context?.data?.memories?.length : 0,
218
218
  experience: outputs.experience?.data ? outputs.experience?.data?.memories?.length : 0,
219
- identity: outputs.identity?.data ? (outputs.identity?.data?.add?.length || 0) + (outputs.identity?.data?.update?.length || 0) + (outputs.identity?.data?.remove?.length || 0) : 0,
219
+ identity: outputs.identity?.data
220
+ ? (outputs.identity?.data?.add?.length || 0) +
221
+ (outputs.identity?.data?.update?.length || 0) +
222
+ (outputs.identity?.data?.remove?.length || 0)
223
+ : 0,
220
224
  preference: outputs.preference?.data ? outputs.preference?.data?.memories?.length : 0,
221
225
  };
222
226
  const processedErrorsCount = {
@@ -224,7 +228,7 @@ export class MemoryExtractionService<RO> {
224
228
  experience: outputs.experience?.error ? 1 : 0,
225
229
  identity: outputs.identity?.error ? 1 : 0,
226
230
  preference: outputs.preference?.error ? 1 : 0,
227
- }
231
+ };
228
232
 
229
233
  const processedCount = Object.values(processedLayersCount).reduce((a, b) => a + b, 0);
230
234
 
@@ -334,9 +338,7 @@ export class MemoryExtractionService<RO> {
334
338
 
335
339
  const setLayerOutput = (
336
340
  layer: LayersEnum,
337
- result:
338
- | { data: MemoryExtractionLayerOutputType }
339
- | { error: unknown },
341
+ result: { data: MemoryExtractionLayerOutputType } | { error: unknown },
340
342
  ) => {
341
343
  switch (layer) {
342
344
  case LayersEnum.Context: {
@@ -370,24 +372,25 @@ export class MemoryExtractionService<RO> {
370
372
  };
371
373
 
372
374
  await Promise.all(
373
- ([
374
- LayersEnum.Context,
375
- LayersEnum.Experience,
376
- LayersEnum.Preference,
377
- LayersEnum.Identity,
378
- ] as LayersEnum[])
379
- .map(async (layer) => {
380
- if (!layers.includes(layer)) {
381
- return
382
- }
383
-
384
- try {
385
- const result = await this.runLayer(job, layer, options);
386
- setLayerOutput(layer, { data: result });
387
- } catch (error) {
388
- setLayerOutput(layer, { error });
389
- }
390
- }),
375
+ (
376
+ [
377
+ LayersEnum.Context,
378
+ LayersEnum.Experience,
379
+ LayersEnum.Preference,
380
+ LayersEnum.Identity,
381
+ ] as LayersEnum[]
382
+ ).map(async (layer) => {
383
+ if (!layers.includes(layer)) {
384
+ return;
385
+ }
386
+
387
+ try {
388
+ const result = await this.runLayer(job, layer, options);
389
+ setLayerOutput(layer, { data: result });
390
+ } catch (error) {
391
+ setLayerOutput(layer, { error });
392
+ }
393
+ }),
391
394
  );
392
395
 
393
396
  return outputs as MemoryExtractionLayerOutputs;
@@ -30,12 +30,14 @@ export interface ExtractorOptions extends ExtractorTemplateProps {
30
30
  additionalMessages?: OpenAIChatMessage[];
31
31
  callbacks?: {
32
32
  onExtractError?: (agent: MemoryExtractionAgent, error: unknown) => Promise<void> | void;
33
- onExtractRequest?: (agent: MemoryExtractionAgent, request: GenerateObjectPayload) =>
34
- | Promise<void>
35
- | void;
36
- onExtractResponse?: <TOutput>(agent: MemoryExtractionAgent, response: TOutput) =>
37
- | Promise<void>
38
- | void;
33
+ onExtractRequest?: (
34
+ agent: MemoryExtractionAgent,
35
+ request: GenerateObjectPayload,
36
+ ) => Promise<void> | void;
37
+ onExtractResponse?: <TOutput>(
38
+ agent: MemoryExtractionAgent,
39
+ response: TOutput,
40
+ ) => Promise<void> | void;
39
41
  };
40
42
  messageIds?: string[];
41
43
  sourceId?: string;
@@ -133,11 +135,11 @@ export type MemoryExtractionLayerOutputs = Partial<{
133
135
  identity: {
134
136
  data?: Awaited<ReturnType<IdentityExtractor['structuredCall']>>;
135
137
  error?: unknown;
136
- }
138
+ };
137
139
  preference: {
138
140
  data?: Awaited<ReturnType<PreferenceExtractor['structuredCall']>>;
139
141
  error?: unknown;
140
- }
142
+ };
141
143
  }>;
142
144
 
143
145
  export interface GatekeeperDecision {
@@ -18,7 +18,7 @@ export enum McpCategory {
18
18
  Tools = 'tools',
19
19
  TravelTransport = 'travel-transport',
20
20
  Weather = 'weather',
21
- WebSearch = 'web-search',
21
+ WebSearch = 'web-search'
22
22
  }
23
23
 
24
24
  export enum McpSorts {
@@ -34,6 +34,10 @@ export interface TopicUserMemoryExtractRunState {
34
34
  }
35
35
 
36
36
  export interface ChatTopicMetadata {
37
+ /**
38
+ * Cron job ID that triggered this topic creation (if created by scheduled task)
39
+ */
40
+ cronJobId?: string;
37
41
  model?: string;
38
42
  provider?: string;
39
43
  userMemoryExtractRunState?: TopicUserMemoryExtractRunState;
@@ -57,6 +61,7 @@ export interface ChatTopic extends Omit<BaseDataModel, 'meta'> {
57
61
  metadata?: ChatTopicMetadata;
58
62
  sessionId?: string;
59
63
  title: string;
64
+ trigger?: string | null;
60
65
  }
61
66
 
62
67
  export type ChatTopicMap = Record<string, ChatTopic>;
@@ -106,6 +111,10 @@ export interface CreateTopicParams {
106
111
  export interface QueryTopicParams {
107
112
  agentId?: string | null;
108
113
  current?: number;
114
+ /**
115
+ * Exclude topics by trigger types (e.g. ['cron'])
116
+ */
117
+ excludeTriggers?: string[];
109
118
  /**
110
119
  * Group ID to filter topics by
111
120
  */
@@ -2,15 +2,18 @@ import { Accordion, Flexbox } from '@lobehub/ui';
2
2
  import React, { memo } from 'react';
3
3
 
4
4
  import Topic from './Topic';
5
+ import CronTopicList from './Topic/CronTopicList';
5
6
 
6
7
  export enum ChatSidebarKey {
7
- Topic = 'topic',
8
+ CronTopics = 'cronTopics',
9
+ Topic = 'topic'
8
10
  }
9
11
 
10
12
  const Body = memo(() => {
11
13
  return (
12
14
  <Flexbox paddingInline={4}>
13
15
  <Accordion defaultExpandedKeys={[ChatSidebarKey.Topic]} gap={8}>
16
+ <CronTopicList itemKey={ChatSidebarKey.CronTopics} />
14
17
  <Topic itemKey={ChatSidebarKey.Topic} />
15
18
  </Accordion>
16
19
  </Flexbox>
@@ -0,0 +1,74 @@
1
+ 'use client';
2
+
3
+ import { Flexbox, Icon, Text } from '@lobehub/ui';
4
+ import { cssVar } from 'antd-style';
5
+ import { Clock } from 'lucide-react';
6
+ import { type MouseEvent, memo, useCallback } from 'react';
7
+ import { useParams } from 'react-router-dom';
8
+
9
+ import { useRouter } from '@/app/[variants]/(main)/hooks/useRouter';
10
+ import type { AgentCronJob } from '@/database/schemas/agentCronJob';
11
+
12
+ import CronTopicItem from './CronTopicItem';
13
+
14
+ interface CronTopicGroupProps {
15
+ cronJob: AgentCronJob | null;
16
+ cronJobId: string;
17
+ topics: Array<{
18
+ createdAt: Date | string;
19
+ favorite?: boolean | null;
20
+ historySummary?: string | null;
21
+ id: string;
22
+ metadata?: any;
23
+ title?: string | null;
24
+ trigger?: string | null;
25
+ updatedAt: Date | string;
26
+ }>;
27
+ }
28
+
29
+ const CronTopicGroup = memo<CronTopicGroupProps>(({ cronJob, cronJobId, topics }) => {
30
+ const { aid } = useParams<{ aid?: string }>();
31
+ const router = useRouter();
32
+ const handleOpenCronJob = useCallback(
33
+ (event: MouseEvent) => {
34
+ event.stopPropagation();
35
+ if (!aid) return;
36
+ router.push(`/agent/${aid}/cron/${cronJobId}`);
37
+ },
38
+ [aid, cronJobId, router],
39
+ );
40
+
41
+ const cronJobName = cronJob?.name || `Cron Job ${cronJobId.slice(-8)}`;
42
+ const isEnabled = cronJob?.enabled ?? false;
43
+
44
+ return (
45
+ <Flexbox gap={1}>
46
+ <Flexbox
47
+ align="center"
48
+ gap={6}
49
+ height={24}
50
+ horizontal
51
+ onClick={handleOpenCronJob}
52
+ paddingInline={8}
53
+ style={{ cursor: 'pointer', opacity: isEnabled ? 1 : 0.6, overflow: 'hidden' }}
54
+ >
55
+ <Icon icon={Clock} style={{ color: cssVar.colorTextDescription, opacity: 0.7 }} />
56
+ <Text ellipsis fontSize={12} style={{ flex: 1 }} type={'secondary'} weight={500}>
57
+ {cronJobName}
58
+ </Text>
59
+ {topics.length > 0 && (
60
+ <Text style={{ color: cssVar.colorTextDescription, fontSize: 11 }}>{topics.length}</Text>
61
+ )}
62
+ </Flexbox>
63
+ {topics.length > 0 && (
64
+ <Flexbox gap={1} paddingBlock={1}>
65
+ {topics.map((topic) => (
66
+ <CronTopicItem key={topic.id} topic={topic} />
67
+ ))}
68
+ </Flexbox>
69
+ )}
70
+ </Flexbox>
71
+ );
72
+ });
73
+
74
+ export default CronTopicGroup;