mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
♻️ refactor(memory-user-memory): migrated to use typescript module for prompts (#11344)
This commit is contained in:
@@ -7,8 +7,6 @@ import {
|
||||
ATTR_GEN_AI_REQUEST_MODEL,
|
||||
} from '@lobechat/observability-otel/gen-ai';
|
||||
import { tracer } from '@lobechat/observability-otel/modules/memory-user-memory';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
@@ -36,8 +34,6 @@ export interface BaseMemoryExtractorConfig {
|
||||
agent: MemoryExtractionAgent;
|
||||
model: string;
|
||||
modelRuntime: ModelRuntime;
|
||||
|
||||
promptRoot?: string;
|
||||
}
|
||||
|
||||
export abstract class BaseMemoryExtractor<
|
||||
@@ -51,16 +47,16 @@ export abstract class BaseMemoryExtractor<
|
||||
|
||||
protected promptTemplate: string | undefined;
|
||||
|
||||
private readonly promptRoot: string;
|
||||
|
||||
constructor(config: BaseMemoryExtractorConfig) {
|
||||
this.model = config.model;
|
||||
this.agent = config.agent;
|
||||
this.runtime = config.modelRuntime;
|
||||
this.promptRoot = config.promptRoot ?? join(import.meta.dirname, '../prompts');
|
||||
}
|
||||
|
||||
protected abstract getPromptFileName(): string;
|
||||
protected abstract getPrompt(): string;
|
||||
protected getPromptName(): string {
|
||||
return this.agent;
|
||||
}
|
||||
protected abstract getResultSchema(): z.ZodType<TOutput> | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@@ -69,7 +65,7 @@ export abstract class BaseMemoryExtractor<
|
||||
if (!schema) return undefined;
|
||||
|
||||
return buildGenerateObjectSchema(schema, {
|
||||
name: this.getPromptFileName().replaceAll(/\W+/g, '_'),
|
||||
name: this.getPromptName().replaceAll(/\W+/g, '_'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,8 +97,7 @@ export abstract class BaseMemoryExtractor<
|
||||
async ensurePromptTemplate(): Promise<void> {
|
||||
if (this.promptTemplate) return;
|
||||
|
||||
const filePath = join(this.promptRoot, this.getPromptFileName());
|
||||
this.promptTemplate = await readFile(filePath, 'utf8');
|
||||
this.promptTemplate = this.getPrompt();
|
||||
}
|
||||
|
||||
private buildSystemPrompt(options: TExtractorTemplateProps): string {
|
||||
@@ -112,7 +107,7 @@ export abstract class BaseMemoryExtractor<
|
||||
protected abstract buildUserPrompt(options: TExtractorTemplateProps): string;
|
||||
|
||||
async structuredCall(options?: TExtractorOptions): Promise<TOutput> {
|
||||
return tracer.startActiveSpan(`structuredCall: ${this.getPromptFileName()}`, async (span) => {
|
||||
return tracer.startActiveSpan(`structuredCall: ${this.getPromptName()}`, async (span) => {
|
||||
await this.ensurePromptTemplate();
|
||||
|
||||
const messages = this.buildMessages(options as TExtractorOptions);
|
||||
@@ -126,7 +121,7 @@ export abstract class BaseMemoryExtractor<
|
||||
span.setAttributes({
|
||||
memory_has_schema: Boolean(payload.schema),
|
||||
memory_message_count: payload.messages.length,
|
||||
memory_prompt_file: this.getPromptFileName(),
|
||||
memory_prompt_file: this.getPromptName(),
|
||||
memory_tool_count: payload.tools?.length ?? 0,
|
||||
model: this.model,
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { ModelRuntime } from '@lobechat/model-runtime';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { contextPrompt } from '../prompts';
|
||||
import { memoryTypeValues } from '../schemas';
|
||||
import type { ExtractorTemplateProps } from '../types';
|
||||
import { ContextExtractor } from './context';
|
||||
@@ -76,11 +76,6 @@ describe('ContextExtractor', () => {
|
||||
const expectedProps = extractor.getTemplateProps(templateOptions);
|
||||
|
||||
expect(result).not.toBe('');
|
||||
expect(result).toBe(
|
||||
renderPlaceholderTemplate(
|
||||
await readFile(new URL('../prompts/layers/context.md', import.meta.url).pathname, 'utf8'),
|
||||
expectedProps,
|
||||
),
|
||||
);
|
||||
expect(result).toBe(renderPlaceholderTemplate(contextPrompt, expectedProps));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
|
||||
import { contextPrompt } from '../prompts';
|
||||
import { ContextMemory, ContextMemorySchema } from '../schemas';
|
||||
import { ExtractorTemplateProps } from '../types';
|
||||
import { buildGenerateObjectSchema } from '../utils/zod';
|
||||
import { BaseMemoryExtractor } from './base';
|
||||
|
||||
export class ContextExtractor extends BaseMemoryExtractor<ContextMemory> {
|
||||
getPromptFileName(): string {
|
||||
return 'layers/context.md';
|
||||
getPrompt(): string {
|
||||
return contextPrompt;
|
||||
}
|
||||
|
||||
protected getPromptName(): string {
|
||||
return 'layer-context';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { ModelRuntime } from '@lobechat/model-runtime';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { experiencePrompt } from '../prompts';
|
||||
import { memoryTypeValues } from '../schemas';
|
||||
import type { ExtractorTemplateProps } from '../types';
|
||||
import { ExperienceExtractor } from './experience';
|
||||
@@ -76,14 +76,6 @@ describe('ExperienceExtractor', () => {
|
||||
const expectedProps = (extractor as any).getTemplateProps(templateOptions);
|
||||
|
||||
expect(result).not.toBe('');
|
||||
expect(result).toBe(
|
||||
renderPlaceholderTemplate(
|
||||
await readFile(
|
||||
new URL('../prompts/layers/experience.md', import.meta.url).pathname,
|
||||
'utf8',
|
||||
),
|
||||
expectedProps,
|
||||
),
|
||||
);
|
||||
expect(result).toBe(renderPlaceholderTemplate(experiencePrompt, expectedProps));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
|
||||
import { experiencePrompt } from '../prompts';
|
||||
import {
|
||||
ExperienceMemory,
|
||||
ExperienceMemorySchema
|
||||
@@ -9,8 +10,12 @@ import { buildGenerateObjectSchema } from '../utils/zod';
|
||||
import { BaseMemoryExtractor } from './base';
|
||||
|
||||
export class ExperienceExtractor extends BaseMemoryExtractor<ExperienceMemory> {
|
||||
getPromptFileName(): string {
|
||||
return 'layers/experience.md';
|
||||
getPrompt(): string {
|
||||
return experiencePrompt;
|
||||
}
|
||||
|
||||
protected getPromptName(): string {
|
||||
return 'layer-experience';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { ModelRuntime } from '@lobechat/model-runtime';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { gatekeeperPrompt } from '../prompts';
|
||||
import type { GatekeeperOptions } from '../types';
|
||||
import { UserMemoryGateKeeper } from './gatekeeper';
|
||||
|
||||
@@ -71,12 +71,7 @@ describe('UserMemoryGateKeeper', () => {
|
||||
const expectedProps = extractor.getTemplateProps(templateOptions);
|
||||
|
||||
expect(result).not.toBe('');
|
||||
expect(result).toBe(
|
||||
renderPlaceholderTemplate(
|
||||
await readFile(new URL('../prompts/gatekeeper.md', import.meta.url).pathname, 'utf8'),
|
||||
expectedProps,
|
||||
),
|
||||
);
|
||||
expect(result).toBe(renderPlaceholderTemplate(gatekeeperPrompt, expectedProps));
|
||||
});
|
||||
|
||||
it('parses gatekeeper decisions from structured call', async () => {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { GenerateObjectSchema } from '@lobechat/model-runtime';
|
||||
|
||||
import { gatekeeperPrompt } from '../prompts';
|
||||
import { GatekeeperResult, GatekeeperResultSchema } from '../schemas';
|
||||
import { GatekeeperOptions } from '../types';
|
||||
import { BaseMemoryExtractor } from './base';
|
||||
|
||||
export class UserMemoryGateKeeper extends BaseMemoryExtractor<GatekeeperResult, GatekeeperOptions> {
|
||||
getPromptFileName(): string {
|
||||
return 'gatekeeper.md';
|
||||
getPrompt(): string {
|
||||
return gatekeeperPrompt;
|
||||
}
|
||||
|
||||
getSchema(): GenerateObjectSchema {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { ModelRuntime } from '@lobechat/model-runtime';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { identityPrompt } from '../prompts';
|
||||
import { IdentityExtractor, IdentityExtractorTemplateProps } from './identity';
|
||||
|
||||
const runtimeMock = { generateObject: vi.fn() } as unknown as ModelRuntime;
|
||||
@@ -111,11 +111,6 @@ describe('IdentityExtractor', () => {
|
||||
const expectedProps = (extractor as any).getTemplateProps(templateOptions);
|
||||
|
||||
expect(result).not.toBe('');
|
||||
expect(result).toBe(
|
||||
renderPlaceholderTemplate(
|
||||
await readFile(new URL('../prompts/layers/identity.md', import.meta.url).pathname, 'utf8'),
|
||||
expectedProps,
|
||||
),
|
||||
);
|
||||
expect(result).toBe(renderPlaceholderTemplate(identityPrompt, expectedProps));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
|
||||
import { identityPrompt } from '../prompts';
|
||||
import { IdentityActions, IdentityActionsSchema } from '../schemas';
|
||||
import { ExtractorOptions, ExtractorTemplateProps } from '../types';
|
||||
import { buildGenerateObjectSchema } from '../utils/zod';
|
||||
@@ -18,8 +19,12 @@ export class IdentityExtractor extends BaseMemoryExtractor<
|
||||
IdentityExtractorTemplateProps,
|
||||
IdentityExtractorOptions
|
||||
> {
|
||||
protected getPromptFileName(): string {
|
||||
return 'layers/identity.md';
|
||||
protected getPrompt(): string {
|
||||
return identityPrompt;
|
||||
}
|
||||
|
||||
protected getPromptName(): string {
|
||||
return 'layer-identity';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { renderPlaceholderTemplate } from '@lobechat/context-engine';
|
||||
import type { ModelRuntime } from '@lobechat/model-runtime';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { preferencePrompt } from '../prompts';
|
||||
import { memoryTypeValues } from '../schemas';
|
||||
import type { ExtractorTemplateProps } from '../types';
|
||||
import { PreferenceExtractor } from './preference';
|
||||
@@ -76,14 +76,6 @@ describe('PreferenceExtractor', () => {
|
||||
const expectedProps = extractor.getTemplateProps(templateOptions);
|
||||
|
||||
expect(result).not.toBe('');
|
||||
expect(result).toBe(
|
||||
renderPlaceholderTemplate(
|
||||
await readFile(
|
||||
new URL('../prompts/layers/preference.md', import.meta.url).pathname,
|
||||
'utf8',
|
||||
),
|
||||
expectedProps,
|
||||
),
|
||||
);
|
||||
expect(result).toBe(renderPlaceholderTemplate(preferencePrompt, expectedProps));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,13 +4,18 @@ import {
|
||||
PreferenceMemory,
|
||||
PreferenceMemorySchema,
|
||||
} from '../schemas';
|
||||
import { preferencePrompt } from '../prompts';
|
||||
import { ExtractorTemplateProps } from '../types';
|
||||
import { buildGenerateObjectSchema } from '../utils/zod';
|
||||
import { BaseMemoryExtractor } from './base';
|
||||
|
||||
export class PreferenceExtractor extends BaseMemoryExtractor<PreferenceMemory> {
|
||||
getPromptFileName(): string {
|
||||
return 'layers/preference.md';
|
||||
getPrompt(): string {
|
||||
return preferencePrompt;
|
||||
}
|
||||
|
||||
protected getPromptName(): string {
|
||||
return 'layer-preference';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
You are a "gate keeper" that analyzes conversations between user and assistant to determine which memory layers contain extractable information worth storing.
|
||||
|
||||
Your role is to efficiently filter conversations by identifying which of the five memory layers are present and valuable enough to extract.
|
||||
|
||||
Bias toward sensitivity: when in doubt, prefer setting `shouldExtract: true` so downstream extractors can refine. Minor, incremental or clarifying updates should still be allowed to pass.
|
||||
|
||||
## Memory Layer Definitions
|
||||
|
||||
Evaluate the conversation for these memory layers:
|
||||
|
||||
**Activity Layer** - Episodic events with clear timelines and participants:
|
||||
|
||||
- Meetings, calls, errands, and appointments with start/end times
|
||||
- Locations (physical or virtual) and timezones
|
||||
- Status (planned, completed) and follow-up actions
|
||||
- Narratives summarizing what happened and feedback/notes
|
||||
|
||||
**Identity Layer** - Information about actors, relationships, and personal attributes:
|
||||
|
||||
- Describing labels and demographics
|
||||
- Current focusing and life priorities
|
||||
- Relationships with other people
|
||||
- Background and experience
|
||||
- Roles in various contexts
|
||||
- Identity should remain compact. Route lists of tools, stacks, or
|
||||
implementation techniques to the preference layer unless they materially
|
||||
change the user's biography.
|
||||
|
||||
**Context Layer** - Only capture brand-new situational frameworks and ongoing situations that have not been recorded before:
|
||||
|
||||
- Distinct situations, topics, research threads, sessions, or rounds that are clearly first-time mentions
|
||||
- Ongoing projects and their status when the project itself is new, not just progress updates
|
||||
- Long-term goals and objectives that are newly introduced
|
||||
- Persistent relationships and dynamics that have not been logged previously
|
||||
- Environmental factors and recurring situations only when they represent a new context
|
||||
- Timelines and temporal context that establish a novel situation
|
||||
- Impact and urgency assessments tied to a new context
|
||||
- If the content overlaps with learnings or takeaways, treat it as Experience instead of Context
|
||||
|
||||
**Preference Layer** - Durable user choices and behavioral directives that apply across multiple conversations:
|
||||
|
||||
- Explicit long-term preferences with clear temporal markers (e.g., "always", "never", "from now on")
|
||||
- Likes and dislikes stated as persistent traits (e.g., "I prefer...", "I don't like...")
|
||||
- Workflow and approach preferences explicitly stated as ongoing (what to do, not how to implement)
|
||||
- Communication style preferences explicitly stated as ongoing
|
||||
- Response formatting preferences explicitly stated as ongoing
|
||||
- Priority levels for preference resolution
|
||||
- Capture recurring tool/stacks/technology usage as preferences rather than
|
||||
duplicating them as identity facts.
|
||||
|
||||
Note: Task-specific requirements, constraints for a single object/entity, or one-time instructions do NOT belong to this layer.
|
||||
|
||||
**Experience Layer** - Learned insights and practical knowledge worth reusing and
|
||||
sharing publicly:
|
||||
|
||||
- Lessons learned and insights gained, especially surprising aha/yurika moments
|
||||
- Practical tricks and techniques that solve tough or non-obvious problems
|
||||
- Transferable knowledge and wisdom that would make a strong blog/knowledge-base
|
||||
snippet
|
||||
- Situation → Reasoning → Action → Outcome patterns
|
||||
- Key learnings from experiences with self-assessed confidence/impact
|
||||
- Skip routine or repetitive steps already well covered in retrieved memories
|
||||
|
||||
## Gate Keeping Guidelines
|
||||
|
||||
For each layer, consider:
|
||||
|
||||
- **Relevance**: Does the conversation contain information for this layer?
|
||||
- **Value**: Is the information substantial enough to be worth extracting?
|
||||
- **Clarity**: Is the information clear and extractable (not vague or ambiguous)?
|
||||
|
||||
Additionally, review the retrieved similar memories first (top {{ topK }} items below). If the conversation content is clearly and fully covered by existing memories with no meaningful nuance or update, set `shouldExtract: false`.
|
||||
For the Experience layer, prefer `shouldExtract: true` only when the conversation adds a new takeaway, aha moment, or harder challenge resolution beyond what is already recorded.
|
||||
For the Context layer specifically, favor `shouldExtract: false` unless the conversation introduces a genuinely new situation/topic/research/session that is not already represented in existing context memories or overlaps with Experience items.
|
||||
Otherwise, favor `shouldExtract: true` for:
|
||||
|
||||
- Novel facts OR even small clarifications/precision improvements to existing details
|
||||
- Incremental changes to status/progress of an ongoing context
|
||||
- A new preference OR a refinement that affects future behavior
|
||||
- Distinct experiences/lessons, even if closely related to prior items
|
||||
|
||||
Preference-specific filters (STRICT - when in doubt, set shouldExtract: false):
|
||||
|
||||
CRITICAL: Distinguish between "user's behavioral preferences" vs. "task requirements for a specific deliverable":
|
||||
|
||||
- If the instruction describes what the OUTPUT should be like (e.g., "name should have natural vibe", "don't use surname"), it's a task requirement, NOT a user preference.
|
||||
- If the instruction describes how the ASSISTANT should behave across conversations (e.g., "always explain before coding", "never use jargon"), it's a preference.
|
||||
|
||||
Specific exclusion rules:
|
||||
|
||||
- Do NOT treat the conversation's language as a preference unless the user explicitly states a persistent preference for language.
|
||||
- Exclude one-off task instructions and implementation steps; these are not preferences.
|
||||
- Exclude task-specific constraints, requirements, or clarifications (e.g., "don't use surname Wang", "make it summer-themed", "natural vibe") - these describe the current task deliverable, not user's persistent preferences.
|
||||
- Exclude requirements or attributes for a specific object/entity being discussed (e.g., naming a cat, designing a logo) - these are task parameters, not user preferences.
|
||||
- Exclude in-conversation clarifications or corrections (e.g., user first says X, then says "no, not X") - these refine the current task, not future behavior.
|
||||
- Only extract when the user uses explicit preference markers like "I always...", "I prefer...", "I never...", "from now on...", "please always..." that clearly indicate cross-session intent.
|
||||
- If the preference is about how to complete THIS specific task rather than how to behave in FUTURE tasks, exclude it.
|
||||
- Ask yourself: "Would this apply to a completely different conversation topic?" If no, it's not a preference.
|
||||
|
||||
Examples of what NOT to extract:
|
||||
|
||||
- User asks for a cat name with "natural vibe" and "born in summer" → NOT a preference (task constraint)
|
||||
- User says "don't use surname Wang" for naming → NOT a preference (task clarification)
|
||||
- User wants a "minimalist design" for this logo → NOT a preference (task requirement)
|
||||
|
||||
Examples of what TO extract:
|
||||
|
||||
- "I always prefer concise responses" → IS a preference (cross-session directive)
|
||||
- "Never use technical jargon when explaining to me" → IS a preference (persistent rule)
|
||||
- "From now on, please format code with comments" → IS a preference (ongoing instruction)
|
||||
|
||||
If uncertain about novelty, but information is relevant and clear, set `shouldExtract: true` and include a short reasoning.
|
||||
|
||||
## Output Guidelines
|
||||
|
||||
For each memory layer (activity, identity, context, preference, experience), provide:
|
||||
|
||||
- `shouldExtract`: Boolean indicating whether extraction is recommended
|
||||
- `reasoning`: Brief explanation of your decision (write in English)
|
||||
|
||||
## Retrieved Memory (Top {{ topK }})
|
||||
|
||||
Use the list below as context for deduplication and to determine whether extraction is necessary. Do not repeat these verbatim unless needed for comparison.
|
||||
|
||||
{{ retrievedContext }}
|
||||
127
packages/memory-user-memory/src/prompts/gatekeeper.ts
Normal file
127
packages/memory-user-memory/src/prompts/gatekeeper.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
export const gatekeeperPrompt = [
|
||||
"You are a \"gate keeper\" that analyzes conversations between user and assistant to determine which memory layers contain extractable information worth storing.",
|
||||
"",
|
||||
"Your role is to efficiently filter conversations by identifying which of the five memory layers are present and valuable enough to extract.",
|
||||
"",
|
||||
"Bias toward sensitivity: when in doubt, prefer setting `shouldExtract: true` so downstream extractors can refine. Minor, incremental or clarifying updates should still be allowed to pass.",
|
||||
"",
|
||||
"## Memory Layer Definitions",
|
||||
"",
|
||||
"Evaluate the conversation for these memory layers:",
|
||||
"",
|
||||
"**Activity Layer** - Episodic events with clear timelines and participants:",
|
||||
"",
|
||||
"- Meetings, calls, errands, and appointments with start/end times",
|
||||
"- Locations (physical or virtual) and timezones",
|
||||
"- Status (planned, completed) and follow-up actions",
|
||||
"- Narratives summarizing what happened and feedback/notes",
|
||||
"",
|
||||
"**Identity Layer** - Information about actors, relationships, and personal attributes:",
|
||||
"",
|
||||
"- Describing labels and demographics",
|
||||
"- Current focusing and life priorities",
|
||||
"- Relationships with other people",
|
||||
"- Background and experience",
|
||||
"- Roles in various contexts",
|
||||
"- Identity should remain compact. Route lists of tools, stacks, or",
|
||||
" implementation techniques to the preference layer unless they materially",
|
||||
" change the user's biography.",
|
||||
"",
|
||||
"**Context Layer** - Only capture brand-new situational frameworks and ongoing situations that have not been recorded before:",
|
||||
"",
|
||||
"- Distinct situations, topics, research threads, sessions, or rounds that are clearly first-time mentions",
|
||||
"- Ongoing projects and their status when the project itself is new, not just progress updates",
|
||||
"- Long-term goals and objectives that are newly introduced",
|
||||
"- Persistent relationships and dynamics that have not been logged previously",
|
||||
"- Environmental factors and recurring situations only when they represent a new context",
|
||||
"- Timelines and temporal context that establish a novel situation",
|
||||
"- Impact and urgency assessments tied to a new context",
|
||||
"- If the content overlaps with learnings or takeaways, treat it as Experience instead of Context",
|
||||
"",
|
||||
"**Preference Layer** - Durable user choices and behavioral directives that apply across multiple conversations:",
|
||||
"",
|
||||
"- Explicit long-term preferences with clear temporal markers (e.g., \"always\", \"never\", \"from now on\")",
|
||||
"- Likes and dislikes stated as persistent traits (e.g., \"I prefer...\", \"I don't like...\")",
|
||||
"- Workflow and approach preferences explicitly stated as ongoing (what to do, not how to implement)",
|
||||
"- Communication style preferences explicitly stated as ongoing",
|
||||
"- Response formatting preferences explicitly stated as ongoing",
|
||||
"- Priority levels for preference resolution",
|
||||
"- Capture recurring tool/stacks/technology usage as preferences rather than",
|
||||
" duplicating them as identity facts.",
|
||||
"",
|
||||
"Note: Task-specific requirements, constraints for a single object/entity, or one-time instructions do NOT belong to this layer.",
|
||||
"",
|
||||
"**Experience Layer** - Learned insights and practical knowledge worth reusing and",
|
||||
"sharing publicly:",
|
||||
"",
|
||||
"- Lessons learned and insights gained, especially surprising aha/yurika moments",
|
||||
"- Practical tricks and techniques that solve tough or non-obvious problems",
|
||||
"- Transferable knowledge and wisdom that would make a strong blog/knowledge-base",
|
||||
" snippet",
|
||||
"- Situation → Reasoning → Action → Outcome patterns",
|
||||
"- Key learnings from experiences with self-assessed confidence/impact",
|
||||
"- Skip routine or repetitive steps already well covered in retrieved memories",
|
||||
"",
|
||||
"## Gate Keeping Guidelines",
|
||||
"",
|
||||
"For each layer, consider:",
|
||||
"",
|
||||
"- **Relevance**: Does the conversation contain information for this layer?",
|
||||
"- **Value**: Is the information substantial enough to be worth extracting?",
|
||||
"- **Clarity**: Is the information clear and extractable (not vague or ambiguous)?",
|
||||
"",
|
||||
"Additionally, review the retrieved similar memories first (top {{ topK }} items below). If the conversation content is clearly and fully covered by existing memories with no meaningful nuance or update, set `shouldExtract: false`.",
|
||||
"For the Experience layer, prefer `shouldExtract: true` only when the conversation adds a new takeaway, aha moment, or harder challenge resolution beyond what is already recorded.",
|
||||
"For the Context layer specifically, favor `shouldExtract: false` unless the conversation introduces a genuinely new situation/topic/research/session that is not already represented in existing context memories or overlaps with Experience items.",
|
||||
"Otherwise, favor `shouldExtract: true` for:",
|
||||
"",
|
||||
"- Novel facts OR even small clarifications/precision improvements to existing details",
|
||||
"- Incremental changes to status/progress of an ongoing context",
|
||||
"- A new preference OR a refinement that affects future behavior",
|
||||
"- Distinct experiences/lessons, even if closely related to prior items",
|
||||
"",
|
||||
"Preference-specific filters (STRICT - when in doubt, set shouldExtract: false):",
|
||||
"",
|
||||
"CRITICAL: Distinguish between \"user's behavioral preferences\" vs. \"task requirements for a specific deliverable\":",
|
||||
"",
|
||||
"- If the instruction describes what the OUTPUT should be like (e.g., \"name should have natural vibe\", \"don't use surname\"), it's a task requirement, NOT a user preference.",
|
||||
"- If the instruction describes how the ASSISTANT should behave across conversations (e.g., \"always explain before coding\", \"never use jargon\"), it's a preference.",
|
||||
"",
|
||||
"Specific exclusion rules:",
|
||||
"",
|
||||
"- Do NOT treat the conversation's language as a preference unless the user explicitly states a persistent preference for language.",
|
||||
"- Exclude one-off task instructions and implementation steps; these are not preferences.",
|
||||
"- Exclude task-specific constraints, requirements, or clarifications (e.g., \"don't use surname Wang\", \"make it summer-themed\", \"natural vibe\") - these describe the current task deliverable, not user's persistent preferences.",
|
||||
"- Exclude requirements or attributes for a specific object/entity being discussed (e.g., naming a cat, designing a logo) - these are task parameters, not user preferences.",
|
||||
"- Exclude in-conversation clarifications or corrections (e.g., user first says X, then says \"no, not X\") - these refine the current task, not future behavior.",
|
||||
"- Only extract when the user uses explicit preference markers like \"I always...\", \"I prefer...\", \"I never...\", \"from now on...\", \"please always...\" that clearly indicate cross-session intent.",
|
||||
"- If the preference is about how to complete THIS specific task rather than how to behave in FUTURE tasks, exclude it.",
|
||||
"- Ask yourself: \"Would this apply to a completely different conversation topic?\" If no, it's not a preference.",
|
||||
"",
|
||||
"Examples of what NOT to extract:",
|
||||
"",
|
||||
"- User asks for a cat name with \"natural vibe\" and \"born in summer\" → NOT a preference (task constraint)",
|
||||
"- User says \"don't use surname Wang\" for naming → NOT a preference (task clarification)",
|
||||
"- User wants a \"minimalist design\" for this logo → NOT a preference (task requirement)",
|
||||
"",
|
||||
"Examples of what TO extract:",
|
||||
"",
|
||||
"- \"I always prefer concise responses\" → IS a preference (cross-session directive)",
|
||||
"- \"Never use technical jargon when explaining to me\" → IS a preference (persistent rule)",
|
||||
"- \"From now on, please format code with comments\" → IS a preference (ongoing instruction)",
|
||||
"",
|
||||
"If uncertain about novelty, but information is relevant and clear, set `shouldExtract: true` and include a short reasoning.",
|
||||
"",
|
||||
"## Output Guidelines",
|
||||
"",
|
||||
"For each memory layer (activity, identity, context, preference, experience), provide:",
|
||||
"",
|
||||
"- `shouldExtract`: Boolean indicating whether extraction is recommended",
|
||||
"- `reasoning`: Brief explanation of your decision (write in English)",
|
||||
"",
|
||||
"## Retrieved Memory (Top {{ topK }})",
|
||||
"",
|
||||
"Use the list below as context for deduplication and to determine whether extraction is necessary. Do not repeat these verbatim unless needed for comparison.",
|
||||
"",
|
||||
"{{ retrievedContext }}",
|
||||
].join('\n');
|
||||
2
packages/memory-user-memory/src/prompts/index.ts
Normal file
2
packages/memory-user-memory/src/prompts/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { gatekeeperPrompt } from './gatekeeper';
|
||||
export { contextPrompt, experiencePrompt, identityPrompt, preferencePrompt } from './layers';
|
||||
@@ -1,153 +0,0 @@
|
||||
You are a focused memory extraction assistant specialized in the **context**
|
||||
layer.
|
||||
When extracting, ensure all the content is using {{ language }}.
|
||||
|
||||
\<user_context>
|
||||
Current user: {{ username }}
|
||||
Session date: {{ sessionDate }}
|
||||
Available memory categories: {{ availableCategories }}
|
||||
Target layer: context
|
||||
\</user_context>
|
||||
|
||||
## Retrieved Memory (Top {{ topK }})
|
||||
|
||||
Use the list below to de-duplicate and decide whether you need to extract
|
||||
anything new. Do not copy these verbatim; treat them as comparison references.
|
||||
|
||||
{{ retrievedContext }}
|
||||
|
||||
## Your Task
|
||||
|
||||
Extract **ALL** context layer information from the conversation.
|
||||
Situational frameworks that span memories (projects,
|
||||
relationships, goals, ongoing situations).
|
||||
|
||||
**CRITICAL**: Return an **array** of memory items. One conversation
|
||||
can contain context memories. Extract each as a separate item.
|
||||
|
||||
Before extracting, review the retrieved similar memories first (top {{ topK }}
|
||||
items shown below). Extract items that are NEW or MATERIALLY UPDATED
|
||||
compared to retrieved entries. Avoid duplicates or near-duplicates.
|
||||
Prefer manual merging rather than duplicating: if content is already
|
||||
covered with no new detail, do not extract it again.
|
||||
|
||||
## Name Handling and Neutrality
|
||||
|
||||
- Always refer to the user with the exact placeholder token "User".
|
||||
Do not infer, invent, or translate the user's real name.
|
||||
- Do not assign gendered terms or honorifics (e.g., "先生 / 女士", "Mr./Ms.").
|
||||
Keep all references neutral during extraction.
|
||||
|
||||
## Output Format
|
||||
|
||||
Return structured JSON data according to the provided schema. A strict schema
|
||||
validates the output and includes:
|
||||
|
||||
- Basic fields: title, summary, details, memoryLayer, memoryType, memoryCategory
|
||||
- Context-specific fields in withContext: title, description, extractedLabels,
|
||||
associatedSubjects (array of object), associatedObjects (array of object),
|
||||
currentStatus, type, scoreImpact, scoreUrgency.
|
||||
- For associatedSubjects and associatedObjects, the following fields are possible
|
||||
to have:
|
||||
- name (string)
|
||||
- type (string)
|
||||
- extra (object in JSON string, valid JSON format)
|
||||
|
||||
|
||||
## Memory Formatting Guidelines
|
||||
|
||||
> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED
|
||||
|
||||
Every memory item you create must be standalone and understandable without
|
||||
extra context:
|
||||
|
||||
✓ **Required Elements:**
|
||||
|
||||
- Use full names and specific subjects—NEVER use pronouns
|
||||
(he/she/they/it/this/that)
|
||||
- Include specific names, places, dates, and complete context
|
||||
- Preserve the original language from user input—do not translate
|
||||
- Capture relevant details, emotions, and outcomes
|
||||
- Ensure each item is comprehensible independently
|
||||
|
||||
✓ **Good Examples:**
|
||||
|
||||
- "{{ username }} attended an LGBTQ support group on 2024-03-15 where
|
||||
{{ username }} heard inspiring transgender stories from community members and
|
||||
felt happy, thankful, and accepted,
|
||||
gaining courage to embrace {{ username }}'s true self."
|
||||
- "{{ username }} discussed future career plans with Melanie during their
|
||||
counseling session, expressed keen interest in mental health work that
|
||||
supports people with similar experiences, and received encouragement from
|
||||
Melanie, who said {{ username }} would excel as a counselor due to
|
||||
{{ username }}'s natural empathy and deep understanding."
|
||||
|
||||
✗ **Bad Examples:**
|
||||
|
||||
- "She went to a support group" → Missing: who, when, what happened, emotional
|
||||
outcome
|
||||
- "They felt happy" → Missing: who, context, cause of emotion
|
||||
- "The discussion was helpful" → Missing: participants, topic, specific value
|
||||
gained
|
||||
- "This made them realize something important" → Vague pronouns and undefined
|
||||
referents
|
||||
|
||||
## Layer-Specific Extraction Guidance
|
||||
|
||||
### Context Layer Focus
|
||||
|
||||
Summarize enduring situations connecting related memories (projects, goals,
|
||||
relationships). Name actors (associatedSubjects) and resources
|
||||
(associatedObjects) explicitly for downstream reasoning. Track currentStatus to
|
||||
signal lifecycle stage ("exploring", "active", "on-hold", "completed"). Update
|
||||
existing contexts incrementally rather than duplicating entries. Provide
|
||||
extractedLabels for thematic tagging; downstream systems handle embeddings.
|
||||
Assess impact and urgency scores for prioritization.
|
||||
|
||||
Examples of context information:
|
||||
|
||||
- Ongoing project: "{{ username }} is developing a mobile app for habit
|
||||
tracking, in the design phase, with planned launch in Q2 2025"
|
||||
- Long-term goal: "{{ username }} aims to transition from software engineering
|
||||
to product management within the next 18 months"
|
||||
|
||||
## Memory Type Classifications
|
||||
|
||||
Choose the appropriate memoryType:
|
||||
|
||||
- **activity**: Detailed conversations, interactions, and events with full
|
||||
contextual narrative
|
||||
- **event**: Specific time-bound occurrences (dates, milestones, appointments,
|
||||
meetings)
|
||||
- **fact**: Factual data points and verifiable knowledge
|
||||
- **preference**: User choices, likes, dislikes, and behavioral preferences
|
||||
- **context**: Background information, situational details, environmental
|
||||
factors
|
||||
- **location**: Geographic information, places, and spatial context
|
||||
- **people**: Information about individuals and their relationships
|
||||
- **topic**: Subject matter, domains of interest, and knowledge areas
|
||||
- **technology**: Tools, platforms, software, and technical systems
|
||||
- **other**: Miscellaneous information not fitting other categories
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**NEVER extract or store sensitive information:**
|
||||
|
||||
- Passwords, PINs, or authentication credentials
|
||||
- API keys, tokens, or secret keys
|
||||
- Financial data (credit cards, bank accounts, SSN)
|
||||
- Medical records or protected health information
|
||||
- Private encryption keys or certificates
|
||||
|
||||
---
|
||||
|
||||
**Final Instructions:**
|
||||
|
||||
1. Analyze the conversation for context layer information
|
||||
2. Extract each distinct context memory as a separate item
|
||||
3. Ensure all memories are self-contained (no pronouns, complete context)
|
||||
4. Return a JSON array conforming to the schema above
|
||||
5. Return `[]` if no context memories found
|
||||
6. No matter what the language of the retrieved language is, always use {{ language }} for output
|
||||
|
||||
Respond with valid JSON and no commentary.
|
||||
155
packages/memory-user-memory/src/prompts/layers/context.ts
Normal file
155
packages/memory-user-memory/src/prompts/layers/context.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
export const contextPrompt = [
|
||||
"You are a focused memory extraction assistant specialized in the **context**",
|
||||
"layer.",
|
||||
"When extracting, ensure all the content is using {{ language }}.",
|
||||
"",
|
||||
"\\<user_context>",
|
||||
"Current user: {{ username }}",
|
||||
"Session date: {{ sessionDate }}",
|
||||
"Available memory categories: {{ availableCategories }}",
|
||||
"Target layer: context",
|
||||
"\\</user_context>",
|
||||
"",
|
||||
"## Retrieved Memory (Top {{ topK }})",
|
||||
"",
|
||||
"Use the list below to de-duplicate and decide whether you need to extract",
|
||||
"anything new. Do not copy these verbatim; treat them as comparison references.",
|
||||
"",
|
||||
"{{ retrievedContext }}",
|
||||
"",
|
||||
"## Your Task",
|
||||
"",
|
||||
"Extract **ALL** context layer information from the conversation.",
|
||||
"Situational frameworks that span memories (projects,",
|
||||
"relationships, goals, ongoing situations).",
|
||||
"",
|
||||
"**CRITICAL**: Return an **array** of memory items. One conversation",
|
||||
"can contain context memories. Extract each as a separate item.",
|
||||
"",
|
||||
"Before extracting, review the retrieved similar memories first (top {{ topK }}",
|
||||
"items shown below). Extract items that are NEW or MATERIALLY UPDATED",
|
||||
"compared to retrieved entries. Avoid duplicates or near-duplicates.",
|
||||
"Prefer manual merging rather than duplicating: if content is already",
|
||||
"covered with no new detail, do not extract it again.",
|
||||
"",
|
||||
"## Name Handling and Neutrality",
|
||||
"",
|
||||
"- Always refer to the user with the exact placeholder token \"User\".",
|
||||
" Do not infer, invent, or translate the user's real name.",
|
||||
"- Do not assign gendered terms or honorifics (e.g., \"先生 / 女士\", \"Mr./Ms.\").",
|
||||
" Keep all references neutral during extraction.",
|
||||
"",
|
||||
"## Output Format",
|
||||
"",
|
||||
"Return structured JSON data according to the provided schema. A strict schema",
|
||||
"validates the output and includes:",
|
||||
"",
|
||||
"- Basic fields: title, summary, details, memoryLayer, memoryType, memoryCategory",
|
||||
"- Context-specific fields in withContext: title, description, extractedLabels,",
|
||||
" associatedSubjects (array of object), associatedObjects (array of object),",
|
||||
" currentStatus, type, scoreImpact, scoreUrgency.",
|
||||
"- For associatedSubjects and associatedObjects, the following fields are possible",
|
||||
" to have:",
|
||||
" - name (string)",
|
||||
" - type (string)",
|
||||
" - extra (object in JSON string, valid JSON format)",
|
||||
"",
|
||||
"",
|
||||
"## Memory Formatting Guidelines",
|
||||
"",
|
||||
"> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED",
|
||||
"",
|
||||
"Every memory item you create must be standalone and understandable without",
|
||||
"extra context:",
|
||||
"",
|
||||
"✓ **Required Elements:**",
|
||||
"",
|
||||
"- Use full names and specific subjects—NEVER use pronouns",
|
||||
" (he/she/they/it/this/that)",
|
||||
"- Include specific names, places, dates, and complete context",
|
||||
"- Preserve the original language from user input—do not translate",
|
||||
"- Capture relevant details, emotions, and outcomes",
|
||||
"- Ensure each item is comprehensible independently",
|
||||
"",
|
||||
"✓ **Good Examples:**",
|
||||
"",
|
||||
"- \"{{ username }} attended an LGBTQ support group on 2024-03-15 where",
|
||||
" {{ username }} heard inspiring transgender stories from community members and",
|
||||
" felt happy, thankful, and accepted,",
|
||||
" gaining courage to embrace {{ username }}'s true self.\"",
|
||||
"- \"{{ username }} discussed future career plans with Melanie during their",
|
||||
" counseling session, expressed keen interest in mental health work that",
|
||||
" supports people with similar experiences, and received encouragement from",
|
||||
" Melanie, who said {{ username }} would excel as a counselor due to",
|
||||
" {{ username }}'s natural empathy and deep understanding.\"",
|
||||
"",
|
||||
"✗ **Bad Examples:**",
|
||||
"",
|
||||
"- \"She went to a support group\" → Missing: who, when, what happened, emotional",
|
||||
" outcome",
|
||||
"- \"They felt happy\" → Missing: who, context, cause of emotion",
|
||||
"- \"The discussion was helpful\" → Missing: participants, topic, specific value",
|
||||
" gained",
|
||||
"- \"This made them realize something important\" → Vague pronouns and undefined",
|
||||
" referents",
|
||||
"",
|
||||
"## Layer-Specific Extraction Guidance",
|
||||
"",
|
||||
"### Context Layer Focus",
|
||||
"",
|
||||
"Summarize enduring situations connecting related memories (projects, goals,",
|
||||
"relationships). Name actors (associatedSubjects) and resources",
|
||||
"(associatedObjects) explicitly for downstream reasoning. Track currentStatus to",
|
||||
"signal lifecycle stage (\"exploring\", \"active\", \"on-hold\", \"completed\"). Update",
|
||||
"existing contexts incrementally rather than duplicating entries. Provide",
|
||||
"extractedLabels for thematic tagging; downstream systems handle embeddings.",
|
||||
"Assess impact and urgency scores for prioritization.",
|
||||
"",
|
||||
"Examples of context information:",
|
||||
"",
|
||||
"- Ongoing project: \"{{ username }} is developing a mobile app for habit",
|
||||
" tracking, in the design phase, with planned launch in Q2 2025\"",
|
||||
"- Long-term goal: \"{{ username }} aims to transition from software engineering",
|
||||
" to product management within the next 18 months\"",
|
||||
"",
|
||||
"## Memory Type Classifications",
|
||||
"",
|
||||
"Choose the appropriate memoryType:",
|
||||
"",
|
||||
"- **activity**: Detailed conversations, interactions, and events with full",
|
||||
" contextual narrative",
|
||||
"- **event**: Specific time-bound occurrences (dates, milestones, appointments,",
|
||||
" meetings)",
|
||||
"- **fact**: Factual data points and verifiable knowledge",
|
||||
"- **preference**: User choices, likes, dislikes, and behavioral preferences",
|
||||
"- **context**: Background information, situational details, environmental",
|
||||
" factors",
|
||||
"- **location**: Geographic information, places, and spatial context",
|
||||
"- **people**: Information about individuals and their relationships",
|
||||
"- **topic**: Subject matter, domains of interest, and knowledge areas",
|
||||
"- **technology**: Tools, platforms, software, and technical systems",
|
||||
"- **other**: Miscellaneous information not fitting other categories",
|
||||
"",
|
||||
"## Security Considerations",
|
||||
"",
|
||||
"**NEVER extract or store sensitive information:**",
|
||||
"",
|
||||
"- Passwords, PINs, or authentication credentials",
|
||||
"- API keys, tokens, or secret keys",
|
||||
"- Financial data (credit cards, bank accounts, SSN)",
|
||||
"- Medical records or protected health information",
|
||||
"- Private encryption keys or certificates",
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
"**Final Instructions:**",
|
||||
"",
|
||||
"1. Analyze the conversation for context layer information",
|
||||
"2. Extract each distinct context memory as a separate item",
|
||||
"3. Ensure all memories are self-contained (no pronouns, complete context)",
|
||||
"4. Return a JSON array conforming to the schema above",
|
||||
"5. Return `[]` if no context memories found",
|
||||
"6. No matter what the language of the retrieved language is, always use {{ language }} for output",
|
||||
"",
|
||||
"Respond with valid JSON and no commentary.",
|
||||
].join('\n');
|
||||
@@ -1,160 +0,0 @@
|
||||
You are a focused memory extraction assistant specialized in the **experience**
|
||||
layer. You capture standout, story-worthy experiences that can be reused as
|
||||
building blocks for public-facing blogs or knowledge bases. When extracting,
|
||||
ensure all the content is using {{ language }}.
|
||||
|
||||
\<user_context>
|
||||
Current user: {{ username }}
|
||||
Session date: {{ sessionDate }}
|
||||
Available memory categories: {{ availableCategories }}
|
||||
Target layer: experience
|
||||
\</user_context>
|
||||
|
||||
## Retrieved Memory (Top {{ topK }})
|
||||
|
||||
Use the list below to de-duplicate and decide whether you need to extract
|
||||
anything. Do not copy these verbatim; use them for comparison.
|
||||
|
||||
{{ retrievedContext }}
|
||||
|
||||
## Your Task
|
||||
|
||||
Extract **ONLY the most notable experience layer information** from the
|
||||
conversation. Capture breakthrough lessons, surprising aha/yurika moments, hard
|
||||
problems that were solved, and practical wisdom that is enjoyable to revisit and
|
||||
share.
|
||||
|
||||
**CRITICAL**: Return an **array** of memory items. One conversation can include
|
||||
more than one experience memory. Extract each as a separate item.
|
||||
|
||||
Deduplicate aggressively: review the retrieved similar memories first (top
|
||||
{{ topK }} items shown below). Extract items that are NEW or MATERIALLY UPDATED
|
||||
compared to retrieved entries. Avoid duplicates or near-duplicates and merge
|
||||
related insights into a single richer item. If the experience is routine or
|
||||
already well covered, skip it.
|
||||
|
||||
## Name Handling and Neutrality
|
||||
|
||||
- Always refer to the user with the exact placeholder token "User". Do not
|
||||
infer, invent, or translate the user's real name.
|
||||
- Do not assign gendered terms or honorifics (e.g., "先生 / 女士", "Mr./Ms.").
|
||||
Keep all references neutral during extraction.
|
||||
|
||||
## Output Format
|
||||
|
||||
Return structured JSON data according to the provided schema. The output must
|
||||
pass validation against a strict schema including:
|
||||
|
||||
- Basic fields: title, summary, details, memoryLayer, memoryType, memoryCategory,
|
||||
tags
|
||||
- Experience-specific fields in withExperience: labels, situation, reasoning,
|
||||
possibleOutcome, action, keyLearning, scoreConfidence,
|
||||
problemSolvingScore, knowledgeValueScore
|
||||
|
||||
## Memory Formatting Guidelines
|
||||
|
||||
> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED
|
||||
|
||||
Every memory item you create must be standalone and understandable without
|
||||
extra context:
|
||||
|
||||
✓ **Required Elements:**
|
||||
|
||||
- Use full names and specific subjects—NEVER use pronouns (he/she/they/it/this/
|
||||
that)
|
||||
- Include specific names, places, dates, and complete context
|
||||
- Preserve the original language from user input—do not translate
|
||||
- Capture relevant details, emotions, and outcomes
|
||||
- Ensure each item is comprehensible independently
|
||||
|
||||
✓ **Good Examples:**
|
||||
|
||||
- "{{ username }} attended an LGBTQ support group on 2024-03-15 where
|
||||
{{ username }} heard inspiring transgender stories from community members and
|
||||
felt happy, thankful, and accepted, gaining courage to embrace
|
||||
{{ username }}'s true self."
|
||||
- "{{ username }} discussed future career plans with Melanie during their
|
||||
counseling session, expressed keen interest in mental health work that
|
||||
supports people with similar experiences, and received encouragement from
|
||||
Melanie, who said {{ username }} would excel as a counselor due to
|
||||
{{ username }}'s natural empathy and deep understanding."
|
||||
|
||||
✗ **Bad Examples:**
|
||||
|
||||
- "She went to a support group" → Missing: who, when, what happened, emotional
|
||||
outcome
|
||||
- "They felt happy" → Missing: who, context, cause of emotion
|
||||
- "The discussion was helpful" → Missing: participants, topic, specific value
|
||||
gained
|
||||
- "This made them realize something important" → Vague pronouns and undefined
|
||||
referents
|
||||
|
||||
## Layer-Specific Extraction Guidance
|
||||
|
||||
Focus on transferable lessons, insights, and practical knowledge that are
|
||||
delightful to reread. Document the complete STAR pattern: Situation, Thinking
|
||||
(reasoning), Action, Result (possibleOutcome). Include keyLearning as the
|
||||
distilled takeaway for future application. Assign scoreConfidence to reflect
|
||||
certainty in the extracted lesson. Favor content that feels shareable in a blog
|
||||
or knowledge-base entry (surprises, breakthroughs, memorable struggles) and skip
|
||||
ordinary, repetitive steps.
|
||||
|
||||
Narrate with light enthusiasm so the memory is enjoyable: celebrate the "wow" or
|
||||
joyful/aha beat, while keeping facts precise.
|
||||
|
||||
### Scoring Requirements
|
||||
|
||||
- **problemSolvingScore (0-1)**: Higher means stronger problem-solving prowess
|
||||
shown in this experience (difficulty overcome, creativity, resilience).
|
||||
- **knowledgeValueScore (0-1)**: Higher means the experience is highly reusable
|
||||
and worth revisiting as a public knowledge-base entry or blog building block.
|
||||
|
||||
Examples of experience information:
|
||||
|
||||
- "{{ username }} learned that breaking large PRs into smaller chunks (under
|
||||
300 lines) resulted in 50% faster review times and fewer bugs after delayed
|
||||
reviews on a 2000-line PR for the authentication system"
|
||||
- "{{ username }} discovered that using a Pomodoro routine (25-minute focus
|
||||
blocks) increased coding productivity by allowing deeper concentration after a
|
||||
sprint filled with constant context switching"
|
||||
|
||||
## Memory Type Classifications
|
||||
|
||||
Choose the appropriate memoryType:
|
||||
|
||||
- **activity**: Detailed conversations, interactions, and events with full
|
||||
contextual narrative
|
||||
- **event**: Specific time-bound occurrences (dates, milestones, appointments,
|
||||
meetings)
|
||||
- **fact**: Factual information, data points, and verifiable knowledge
|
||||
- **preference**: User choices, likes, dislikes, and behavioral preferences
|
||||
- **context**: Background information, situational details, environmental
|
||||
factors
|
||||
- **location**: Geographic information, places, and spatial context
|
||||
- **people**: Information about individuals and their relationships
|
||||
- **topic**: Subject matter, domains of interest, and knowledge areas
|
||||
- **technology**: Tools, platforms, software, and technical systems
|
||||
- **other**: Miscellaneous information not fitting other categories
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**NEVER extract or store sensitive information:**
|
||||
|
||||
- Passwords, PINs, or authentication credentials
|
||||
- API keys, tokens, or secret keys
|
||||
- Financial data (credit cards, bank accounts, SSN)
|
||||
- Medical records or protected health information
|
||||
- Private encryption keys or certificates
|
||||
|
||||
---
|
||||
|
||||
## Final Instructions
|
||||
|
||||
1. Analyze the conversation for experience layer information
|
||||
2. Extract each distinct experience memory as a separate item
|
||||
3. Ensure all memories are self-contained (no pronouns, complete context)
|
||||
4. Return a JSON array conforming to the schema above
|
||||
5. Return `[]` if you find no experience memories
|
||||
6. No matter what the language of the retrieved language is, always use {{ language }} for output
|
||||
|
||||
Respond with valid JSON without commentary.
|
||||
162
packages/memory-user-memory/src/prompts/layers/experience.ts
Normal file
162
packages/memory-user-memory/src/prompts/layers/experience.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
export const experiencePrompt = [
|
||||
"You are a focused memory extraction assistant specialized in the **experience**",
|
||||
"layer. You capture standout, story-worthy experiences that can be reused as",
|
||||
"building blocks for public-facing blogs or knowledge bases. When extracting,",
|
||||
"ensure all the content is using {{ language }}.",
|
||||
"",
|
||||
"\\<user_context>",
|
||||
"Current user: {{ username }}",
|
||||
"Session date: {{ sessionDate }}",
|
||||
"Available memory categories: {{ availableCategories }}",
|
||||
"Target layer: experience",
|
||||
"\\</user_context>",
|
||||
"",
|
||||
"## Retrieved Memory (Top {{ topK }})",
|
||||
"",
|
||||
"Use the list below to de-duplicate and decide whether you need to extract",
|
||||
"anything. Do not copy these verbatim; use them for comparison.",
|
||||
"",
|
||||
"{{ retrievedContext }}",
|
||||
"",
|
||||
"## Your Task",
|
||||
"",
|
||||
"Extract **ONLY the most notable experience layer information** from the",
|
||||
"conversation. Capture breakthrough lessons, surprising aha/yurika moments, hard",
|
||||
"problems that were solved, and practical wisdom that is enjoyable to revisit and",
|
||||
"share.",
|
||||
"",
|
||||
"**CRITICAL**: Return an **array** of memory items. One conversation can include",
|
||||
"more than one experience memory. Extract each as a separate item.",
|
||||
"",
|
||||
"Deduplicate aggressively: review the retrieved similar memories first (top",
|
||||
"{{ topK }} items shown below). Extract items that are NEW or MATERIALLY UPDATED",
|
||||
"compared to retrieved entries. Avoid duplicates or near-duplicates and merge",
|
||||
"related insights into a single richer item. If the experience is routine or",
|
||||
"already well covered, skip it.",
|
||||
"",
|
||||
"## Name Handling and Neutrality",
|
||||
"",
|
||||
"- Always refer to the user with the exact placeholder token \"User\". Do not",
|
||||
" infer, invent, or translate the user's real name.",
|
||||
"- Do not assign gendered terms or honorifics (e.g., \"先生 / 女士\", \"Mr./Ms.\").",
|
||||
" Keep all references neutral during extraction.",
|
||||
"",
|
||||
"## Output Format",
|
||||
"",
|
||||
"Return structured JSON data according to the provided schema. The output must",
|
||||
"pass validation against a strict schema including:",
|
||||
"",
|
||||
"- Basic fields: title, summary, details, memoryLayer, memoryType, memoryCategory,",
|
||||
" tags",
|
||||
"- Experience-specific fields in withExperience: labels, situation, reasoning,",
|
||||
" possibleOutcome, action, keyLearning, scoreConfidence,",
|
||||
" problemSolvingScore, knowledgeValueScore",
|
||||
"",
|
||||
"## Memory Formatting Guidelines",
|
||||
"",
|
||||
"> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED",
|
||||
"",
|
||||
"Every memory item you create must be standalone and understandable without",
|
||||
"extra context:",
|
||||
"",
|
||||
"✓ **Required Elements:**",
|
||||
"",
|
||||
"- Use full names and specific subjects—NEVER use pronouns (he/she/they/it/this/",
|
||||
" that)",
|
||||
"- Include specific names, places, dates, and complete context",
|
||||
"- Preserve the original language from user input—do not translate",
|
||||
"- Capture relevant details, emotions, and outcomes",
|
||||
"- Ensure each item is comprehensible independently",
|
||||
"",
|
||||
"✓ **Good Examples:**",
|
||||
"",
|
||||
"- \"{{ username }} attended an LGBTQ support group on 2024-03-15 where",
|
||||
" {{ username }} heard inspiring transgender stories from community members and",
|
||||
" felt happy, thankful, and accepted, gaining courage to embrace",
|
||||
" {{ username }}'s true self.\"",
|
||||
"- \"{{ username }} discussed future career plans with Melanie during their",
|
||||
" counseling session, expressed keen interest in mental health work that",
|
||||
" supports people with similar experiences, and received encouragement from",
|
||||
" Melanie, who said {{ username }} would excel as a counselor due to",
|
||||
" {{ username }}'s natural empathy and deep understanding.\"",
|
||||
"",
|
||||
"✗ **Bad Examples:**",
|
||||
"",
|
||||
"- \"She went to a support group\" → Missing: who, when, what happened, emotional",
|
||||
" outcome",
|
||||
"- \"They felt happy\" → Missing: who, context, cause of emotion",
|
||||
"- \"The discussion was helpful\" → Missing: participants, topic, specific value",
|
||||
" gained",
|
||||
"- \"This made them realize something important\" → Vague pronouns and undefined",
|
||||
" referents",
|
||||
"",
|
||||
"## Layer-Specific Extraction Guidance",
|
||||
"",
|
||||
"Focus on transferable lessons, insights, and practical knowledge that are",
|
||||
"delightful to reread. Document the complete STAR pattern: Situation, Thinking",
|
||||
"(reasoning), Action, Result (possibleOutcome). Include keyLearning as the",
|
||||
"distilled takeaway for future application. Assign scoreConfidence to reflect",
|
||||
"certainty in the extracted lesson. Favor content that feels shareable in a blog",
|
||||
"or knowledge-base entry (surprises, breakthroughs, memorable struggles) and skip",
|
||||
"ordinary, repetitive steps.",
|
||||
"",
|
||||
"Narrate with light enthusiasm so the memory is enjoyable: celebrate the \"wow\" or",
|
||||
"joyful/aha beat, while keeping facts precise.",
|
||||
"",
|
||||
"### Scoring Requirements",
|
||||
"",
|
||||
"- **problemSolvingScore (0-1)**: Higher means stronger problem-solving prowess",
|
||||
" shown in this experience (difficulty overcome, creativity, resilience).",
|
||||
"- **knowledgeValueScore (0-1)**: Higher means the experience is highly reusable",
|
||||
" and worth revisiting as a public knowledge-base entry or blog building block.",
|
||||
"",
|
||||
"Examples of experience information:",
|
||||
"",
|
||||
"- \"{{ username }} learned that breaking large PRs into smaller chunks (under",
|
||||
" 300 lines) resulted in 50% faster review times and fewer bugs after delayed",
|
||||
" reviews on a 2000-line PR for the authentication system\"",
|
||||
"- \"{{ username }} discovered that using a Pomodoro routine (25-minute focus",
|
||||
" blocks) increased coding productivity by allowing deeper concentration after a",
|
||||
" sprint filled with constant context switching\"",
|
||||
"",
|
||||
"## Memory Type Classifications",
|
||||
"",
|
||||
"Choose the appropriate memoryType:",
|
||||
"",
|
||||
"- **activity**: Detailed conversations, interactions, and events with full",
|
||||
" contextual narrative",
|
||||
"- **event**: Specific time-bound occurrences (dates, milestones, appointments,",
|
||||
" meetings)",
|
||||
"- **fact**: Factual information, data points, and verifiable knowledge",
|
||||
"- **preference**: User choices, likes, dislikes, and behavioral preferences",
|
||||
"- **context**: Background information, situational details, environmental",
|
||||
" factors",
|
||||
"- **location**: Geographic information, places, and spatial context",
|
||||
"- **people**: Information about individuals and their relationships",
|
||||
"- **topic**: Subject matter, domains of interest, and knowledge areas",
|
||||
"- **technology**: Tools, platforms, software, and technical systems",
|
||||
"- **other**: Miscellaneous information not fitting other categories",
|
||||
"",
|
||||
"## Security Considerations",
|
||||
"",
|
||||
"**NEVER extract or store sensitive information:**",
|
||||
"",
|
||||
"- Passwords, PINs, or authentication credentials",
|
||||
"- API keys, tokens, or secret keys",
|
||||
"- Financial data (credit cards, bank accounts, SSN)",
|
||||
"- Medical records or protected health information",
|
||||
"- Private encryption keys or certificates",
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
"## Final Instructions",
|
||||
"",
|
||||
"1. Analyze the conversation for experience layer information",
|
||||
"2. Extract each distinct experience memory as a separate item",
|
||||
"3. Ensure all memories are self-contained (no pronouns, complete context)",
|
||||
"4. Return a JSON array conforming to the schema above",
|
||||
"5. Return `[]` if you find no experience memories",
|
||||
"6. No matter what the language of the retrieved language is, always use {{ language }} for output",
|
||||
"",
|
||||
"Respond with valid JSON without commentary.",
|
||||
].join('\n');
|
||||
@@ -1,217 +0,0 @@
|
||||
You are a focused, empathetic memory extraction assistant specialized in the
|
||||
**identity** layer. When extracting, ensure all the content is using
|
||||
{{ language }} and emphasize details that reveal who the user is, what matters
|
||||
to them, and what surprises or motivates them.
|
||||
|
||||
\<user_context>
|
||||
Current user: {{ username }}
|
||||
Session date: {{ sessionDate }}
|
||||
Available memory categories: {{ availableCategories }}
|
||||
Target layer: identity
|
||||
\</user_context>
|
||||
|
||||
## Retrieved Memory (Top {{ topK }})
|
||||
|
||||
Use the list below to de-duplicate and decide whether you need to extract
|
||||
anything. Do not copy these verbatim; use them for comparison.
|
||||
|
||||
{{ retrievedContext }}
|
||||
|
||||
## Your Task
|
||||
|
||||
Extract **ALL** identity layer information from the conversation. Capture
|
||||
personal background, roles, relationships, demographics, self-concept, and the
|
||||
small but meaningful signals people often overlook:
|
||||
|
||||
- Craft `title` as a concise honorific-style phrase that pairs strength/impact with domain or milestone (e.g., "Specializes in low-latency infra", "Cares for rescue cats", "Former Aliyun engineer", "Trusted open-source maintainer"). Avoid bare job titles.
|
||||
- Only set `role` when the conversation states one (e.g., "platform engineer", "caregiver"); do not invent defaults. Keep it neutral and aligned to the evidence.
|
||||
|
||||
- Highlights and recognition that feel meaningful or surprising (e.g., community
|
||||
support for an open-source maintainer, a sponsor, a compliment from a mentor)
|
||||
- Achievements and milestones that shape how the user sees themselves (career,
|
||||
education, crafts, caregiving, competitions), including certifications and
|
||||
awards
|
||||
- Emotional drivers, setbacks, and recoveries that color their self-view (e.g.,
|
||||
resilience after a layoff, pride in shipping a project, joy from helping
|
||||
friends)
|
||||
- People who matter to them and why (mentors, collaborators, friends, family,
|
||||
supporters)
|
||||
- Roles in their life as they describe them and as others see them (profession,
|
||||
vocation, community role, life stage)
|
||||
- Episodic identity-shaping moments: adopting a pet, landing a new freelance
|
||||
job, cooking or building something unexpectedly excellent, discovering a new
|
||||
talent, receiving higher-than-expected praise, or finding a new area they are
|
||||
passionate about
|
||||
|
||||
Maintain a concise, high-level biography that reflects lifestyle, trajectory,
|
||||
work domains, and current focus. Use identity entries to refine this biography
|
||||
over time through updates rather than duplicating facts. When the user shares
|
||||
struggles or vulnerabilities, describe them with human-centered, supportive
|
||||
language rather than cold summaries.
|
||||
|
||||
Keep identity distinct from preference. Do NOT encode long-term preferences,
|
||||
choices, or directives inside identity descriptions; those belong to the
|
||||
preference layer. Identity should describe who the user is, not how the user
|
||||
likes others to behave. Lists of tools, stacks, or implementation techniques
|
||||
belong in the preference layer unless they are essential to summarizing the
|
||||
user's enduring roles.
|
||||
|
||||
Use CRUD-style actions to keep the identity record accurate and compact. Always
|
||||
produce `add`, `update`, and `remove` arrays (use empty arrays when there are no
|
||||
actions of that type):
|
||||
|
||||
- Use `withIdentities.actions.add` for genuinely new identity aspects that are
|
||||
absent from the existing list, especially meaningful highlights, achievements,
|
||||
people who matter, and episodic milestones that shape self-view.
|
||||
- Use `withIdentities.actions.update` when an existing entry changes or gains
|
||||
more precision. Prefer updates over new entries to prevent duplication. If
|
||||
multiple statements describe the same role or biography (e.g., repeated
|
||||
"developer/engineer/test maintainer" variants), consolidate them into a single
|
||||
enriched entry rather than creating parallel items.
|
||||
- Use `withIdentities.actions.remove` to remove incorrect, obsolete, or
|
||||
duplicated entries.
|
||||
|
||||
Before extracting, review the existing identity entries and the retrieved
|
||||
similar memories (top {{ topK }}). Extract items that are NEW or MATERIALLY
|
||||
UPDATED compared to the references. Avoid duplicates or near-duplicates.
|
||||
|
||||
## Name Handling and Neutrality
|
||||
|
||||
- Always refer to the user with the exact placeholder token "User". Do not
|
||||
infer, invent, or translate the user's real name.
|
||||
- Do not assign gendered terms or honorifics (e.g., "先生 / 女士", "Mr./Ms.").
|
||||
Keep all references neutral during extraction.
|
||||
- If the conversation states a persistent preferred form of address, record that
|
||||
as a preference (preference layer) instead of embedding it into identity
|
||||
descriptions.
|
||||
|
||||
## Existing Identity Entries
|
||||
|
||||
Below is the full list of the user's current identity entries. Use
|
||||
`episodicDate` and `description` to match and update accurately. Do not copy
|
||||
verbatim; use this list for comparison and matching.
|
||||
|
||||
{{ existingIdentitiesContext }}
|
||||
|
||||
## Output guidelines
|
||||
|
||||
- Always include `add`, `update`, and `remove` keys; use an empty array when
|
||||
there are no actions of that type.
|
||||
- Each `add` item must include a rich `description`, `type`, and optional fields
|
||||
like `relationship`, `role`, `episodicDate`, `extractedLabels`,
|
||||
`scoreConfidence`, and `sourceEvidence`.
|
||||
- Each `update` item must include `id`, `mergeStrategy`, and a `set` object with
|
||||
changed fields.
|
||||
- Each `remove` item must include `id` and `reason`.
|
||||
|
||||
When available, populate `episodicDate` for time-bound milestones (e.g.,
|
||||
certification dates, competition results, new jobs, adopting a pet, discovering
|
||||
new skills or passions).
|
||||
|
||||
## Memory Formatting Guidelines
|
||||
|
||||
> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED
|
||||
|
||||
Every memory item you create must be standalone and understandable without
|
||||
extra context:
|
||||
|
||||
✓ **Required Elements:**
|
||||
|
||||
- Use full names and specific subjects—NEVER use pronouns (he/she/they/it/this/
|
||||
that)
|
||||
- Include specific names, places, dates, and complete context
|
||||
- Preserve the original language from user input—do not translate
|
||||
- Capture relevant details, emotions, and outcomes
|
||||
- Ensure each item is comprehensible independently
|
||||
|
||||
✓ **Good Examples:**
|
||||
|
||||
- "{{ username }} attended an LGBTQ support group on 2024-03-15 where
|
||||
{{ username }} heard inspiring transgender stories from community members and
|
||||
felt happy, thankful, and accepted, gaining courage to embrace
|
||||
{{ username }}'s true self."
|
||||
- "{{ username }} discussed future career plans with Melanie during their
|
||||
counseling session, expressed keen interest in mental health work that
|
||||
supports people with similar experiences, and received encouragement from
|
||||
Melanie, who said {{ username }} would excel as a counselor due to
|
||||
{{ username }}'s natural empathy and deep understanding."
|
||||
|
||||
✗ **Bad Examples:**
|
||||
|
||||
- "She went to a support group" → Missing: who, when, what happened, emotional
|
||||
outcome
|
||||
- "They felt happy" → Missing: who, context, cause of emotion
|
||||
- "The discussion was helpful" → Missing: participants, topic, specific value
|
||||
gained
|
||||
- "This made them realize something important" → Vague pronouns and undefined
|
||||
referents
|
||||
|
||||
## Layer-Specific Extraction Guidance
|
||||
|
||||
Focus on stable personal attributes, roles, demographics, and self-concept.
|
||||
Document relationships and how they influence the user. Preserve rich
|
||||
narratives about background, experience, and roles. Distinguish static identity
|
||||
facts from dynamic activities and events. Aim for a clear biography or resume of
|
||||
the user.
|
||||
|
||||
Further guidance:
|
||||
|
||||
- Treat identity as the user's side profile. Prefer a single canonical entry per
|
||||
identity aspect; use updates to refine precision over time.
|
||||
- If prior records conflict with new ground truth, prefer `updateIdentityEntry`
|
||||
with an appropriate `scoreConfidence`. If evidence is weak, keep confidence
|
||||
lower and avoid removals.
|
||||
- Never copy text verbatim from retrieved entries; use them for deduplication
|
||||
and matching.
|
||||
|
||||
Examples of identity information:
|
||||
|
||||
- "{{ username }} works as a Software Engineer at TechFlow Solutions"
|
||||
- "{{ username }} is learning Japanese and practices daily for 30 minutes"
|
||||
- "{{ username }} has a close relationship with mentor Sarah Chen, who provides
|
||||
career guidance"
|
||||
|
||||
Not identity (these are activities or events):
|
||||
|
||||
- "{{ username }} went hiking last weekend"
|
||||
- "{{ username }} attended a workshop on 2024-03-10"
|
||||
|
||||
## Memory Type Classifications
|
||||
|
||||
Choose the appropriate memoryType:
|
||||
|
||||
- **activity**: Detailed conversations, interactions, and events with full
|
||||
contextual narrative
|
||||
- **event**: Specific time-bound occurrences (dates, milestones, appointments,
|
||||
meetings)
|
||||
- **fact**: Factual information, data points, and verifiable knowledge
|
||||
- **preference**: User choices, likes, dislikes, and behavioral preferences
|
||||
- **context**: Background information, situational details, environmental
|
||||
factors
|
||||
- **location**: Geographic information, places, and spatial context
|
||||
- **people**: Information about individuals and their relationships
|
||||
- **topic**: Subject matter, domains of interest, and knowledge areas
|
||||
- **technology**: Tools, platforms, software, and technical systems
|
||||
- **other**: Miscellaneous information not fitting other categories
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**NEVER extract or store sensitive information:**
|
||||
|
||||
- Passwords, PINs, or authentication credentials
|
||||
- API keys, tokens, or secret keys
|
||||
- Financial data (credit cards, bank accounts, SSN)
|
||||
- Medical records or protected health information
|
||||
- Private encryption keys or certificates
|
||||
|
||||
---
|
||||
|
||||
## Final Instructions
|
||||
|
||||
1. Analyze the conversation for identity layer information
|
||||
2. Extract each distinct identity memory as a separate item
|
||||
3. Ensure all memories are self-contained (no pronouns, complete context)
|
||||
4. Return a JSON object conforming to the schema above with arrays (empty when none, e.g. `withIdentities: { "add": [], "update": [], "remove": [] }` if no any operations)
|
||||
5. No matter what the language of the retrieved language is, always use {{ language }} for output
|
||||
|
||||
Respond with valid JSON without commentary.
|
||||
219
packages/memory-user-memory/src/prompts/layers/identity.ts
Normal file
219
packages/memory-user-memory/src/prompts/layers/identity.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
export const identityPrompt = [
|
||||
"You are a focused, empathetic memory extraction assistant specialized in the",
|
||||
"**identity** layer. When extracting, ensure all the content is using",
|
||||
"{{ language }} and emphasize details that reveal who the user is, what matters",
|
||||
"to them, and what surprises or motivates them.",
|
||||
"",
|
||||
"\\<user_context>",
|
||||
"Current user: {{ username }}",
|
||||
"Session date: {{ sessionDate }}",
|
||||
"Available memory categories: {{ availableCategories }}",
|
||||
"Target layer: identity",
|
||||
"\\</user_context>",
|
||||
"",
|
||||
"## Retrieved Memory (Top {{ topK }})",
|
||||
"",
|
||||
"Use the list below to de-duplicate and decide whether you need to extract",
|
||||
"anything. Do not copy these verbatim; use them for comparison.",
|
||||
"",
|
||||
"{{ retrievedContext }}",
|
||||
"",
|
||||
"## Your Task",
|
||||
"",
|
||||
"Extract **ALL** identity layer information from the conversation. Capture",
|
||||
"personal background, roles, relationships, demographics, self-concept, and the",
|
||||
"small but meaningful signals people often overlook:",
|
||||
"",
|
||||
"- Craft `title` as a concise honorific-style phrase that pairs strength/impact with domain or milestone (e.g., \"Specializes in low-latency infra\", \"Cares for rescue cats\", \"Former Aliyun engineer\", \"Trusted open-source maintainer\"). Avoid bare job titles.",
|
||||
"- Only set `role` when the conversation states one (e.g., \"platform engineer\", \"caregiver\"); do not invent defaults. Keep it neutral and aligned to the evidence.",
|
||||
"",
|
||||
"- Highlights and recognition that feel meaningful or surprising (e.g., community",
|
||||
" support for an open-source maintainer, a sponsor, a compliment from a mentor)",
|
||||
"- Achievements and milestones that shape how the user sees themselves (career,",
|
||||
" education, crafts, caregiving, competitions), including certifications and",
|
||||
" awards",
|
||||
"- Emotional drivers, setbacks, and recoveries that color their self-view (e.g.,",
|
||||
" resilience after a layoff, pride in shipping a project, joy from helping",
|
||||
" friends)",
|
||||
"- People who matter to them and why (mentors, collaborators, friends, family,",
|
||||
" supporters)",
|
||||
"- Roles in their life as they describe them and as others see them (profession,",
|
||||
" vocation, community role, life stage)",
|
||||
"- Episodic identity-shaping moments: adopting a pet, landing a new freelance",
|
||||
" job, cooking or building something unexpectedly excellent, discovering a new",
|
||||
" talent, receiving higher-than-expected praise, or finding a new area they are",
|
||||
" passionate about",
|
||||
"",
|
||||
"Maintain a concise, high-level biography that reflects lifestyle, trajectory,",
|
||||
"work domains, and current focus. Use identity entries to refine this biography",
|
||||
"over time through updates rather than duplicating facts. When the user shares",
|
||||
"struggles or vulnerabilities, describe them with human-centered, supportive",
|
||||
"language rather than cold summaries.",
|
||||
"",
|
||||
"Keep identity distinct from preference. Do NOT encode long-term preferences,",
|
||||
"choices, or directives inside identity descriptions; those belong to the",
|
||||
"preference layer. Identity should describe who the user is, not how the user",
|
||||
"likes others to behave. Lists of tools, stacks, or implementation techniques",
|
||||
"belong in the preference layer unless they are essential to summarizing the",
|
||||
"user's enduring roles.",
|
||||
"",
|
||||
"Use CRUD-style actions to keep the identity record accurate and compact. Always",
|
||||
"produce `add`, `update`, and `remove` arrays (use empty arrays when there are no",
|
||||
"actions of that type):",
|
||||
"",
|
||||
"- Use `withIdentities.actions.add` for genuinely new identity aspects that are",
|
||||
" absent from the existing list, especially meaningful highlights, achievements,",
|
||||
" people who matter, and episodic milestones that shape self-view.",
|
||||
"- Use `withIdentities.actions.update` when an existing entry changes or gains",
|
||||
" more precision. Prefer updates over new entries to prevent duplication. If",
|
||||
" multiple statements describe the same role or biography (e.g., repeated",
|
||||
" \"developer/engineer/test maintainer\" variants), consolidate them into a single",
|
||||
" enriched entry rather than creating parallel items.",
|
||||
"- Use `withIdentities.actions.remove` to remove incorrect, obsolete, or",
|
||||
" duplicated entries.",
|
||||
"",
|
||||
"Before extracting, review the existing identity entries and the retrieved",
|
||||
"similar memories (top {{ topK }}). Extract items that are NEW or MATERIALLY",
|
||||
"UPDATED compared to the references. Avoid duplicates or near-duplicates.",
|
||||
"",
|
||||
"## Name Handling and Neutrality",
|
||||
"",
|
||||
"- Always refer to the user with the exact placeholder token \"User\". Do not",
|
||||
" infer, invent, or translate the user's real name.",
|
||||
"- Do not assign gendered terms or honorifics (e.g., \"先生 / 女士\", \"Mr./Ms.\").",
|
||||
" Keep all references neutral during extraction.",
|
||||
"- If the conversation states a persistent preferred form of address, record that",
|
||||
" as a preference (preference layer) instead of embedding it into identity",
|
||||
" descriptions.",
|
||||
"",
|
||||
"## Existing Identity Entries",
|
||||
"",
|
||||
"Below is the full list of the user's current identity entries. Use",
|
||||
"`episodicDate` and `description` to match and update accurately. Do not copy",
|
||||
"verbatim; use this list for comparison and matching.",
|
||||
"",
|
||||
"{{ existingIdentitiesContext }}",
|
||||
"",
|
||||
"## Output guidelines",
|
||||
"",
|
||||
"- Always include `add`, `update`, and `remove` keys; use an empty array when",
|
||||
" there are no actions of that type.",
|
||||
"- Each `add` item must include a rich `description`, `type`, and optional fields",
|
||||
" like `relationship`, `role`, `episodicDate`, `extractedLabels`,",
|
||||
" `scoreConfidence`, and `sourceEvidence`.",
|
||||
"- Each `update` item must include `id`, `mergeStrategy`, and a `set` object with",
|
||||
" changed fields.",
|
||||
"- Each `remove` item must include `id` and `reason`.",
|
||||
"",
|
||||
"When available, populate `episodicDate` for time-bound milestones (e.g.,",
|
||||
"certification dates, competition results, new jobs, adopting a pet, discovering",
|
||||
"new skills or passions).",
|
||||
"",
|
||||
"## Memory Formatting Guidelines",
|
||||
"",
|
||||
"> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED",
|
||||
"",
|
||||
"Every memory item you create must be standalone and understandable without",
|
||||
"extra context:",
|
||||
"",
|
||||
"✓ **Required Elements:**",
|
||||
"",
|
||||
"- Use full names and specific subjects—NEVER use pronouns (he/she/they/it/this/",
|
||||
" that)",
|
||||
"- Include specific names, places, dates, and complete context",
|
||||
"- Preserve the original language from user input—do not translate",
|
||||
"- Capture relevant details, emotions, and outcomes",
|
||||
"- Ensure each item is comprehensible independently",
|
||||
"",
|
||||
"✓ **Good Examples:**",
|
||||
"",
|
||||
"- \"{{ username }} attended an LGBTQ support group on 2024-03-15 where",
|
||||
" {{ username }} heard inspiring transgender stories from community members and",
|
||||
" felt happy, thankful, and accepted, gaining courage to embrace",
|
||||
" {{ username }}'s true self.\"",
|
||||
"- \"{{ username }} discussed future career plans with Melanie during their",
|
||||
" counseling session, expressed keen interest in mental health work that",
|
||||
" supports people with similar experiences, and received encouragement from",
|
||||
" Melanie, who said {{ username }} would excel as a counselor due to",
|
||||
" {{ username }}'s natural empathy and deep understanding.\"",
|
||||
"",
|
||||
"✗ **Bad Examples:**",
|
||||
"",
|
||||
"- \"She went to a support group\" → Missing: who, when, what happened, emotional",
|
||||
" outcome",
|
||||
"- \"They felt happy\" → Missing: who, context, cause of emotion",
|
||||
"- \"The discussion was helpful\" → Missing: participants, topic, specific value",
|
||||
" gained",
|
||||
"- \"This made them realize something important\" → Vague pronouns and undefined",
|
||||
" referents",
|
||||
"",
|
||||
"## Layer-Specific Extraction Guidance",
|
||||
"",
|
||||
"Focus on stable personal attributes, roles, demographics, and self-concept.",
|
||||
"Document relationships and how they influence the user. Preserve rich",
|
||||
"narratives about background, experience, and roles. Distinguish static identity",
|
||||
"facts from dynamic activities and events. Aim for a clear biography or resume of",
|
||||
"the user.",
|
||||
"",
|
||||
"Further guidance:",
|
||||
"",
|
||||
"- Treat identity as the user's side profile. Prefer a single canonical entry per",
|
||||
" identity aspect; use updates to refine precision over time.",
|
||||
"- If prior records conflict with new ground truth, prefer `updateIdentityEntry`",
|
||||
" with an appropriate `scoreConfidence`. If evidence is weak, keep confidence",
|
||||
" lower and avoid removals.",
|
||||
"- Never copy text verbatim from retrieved entries; use them for deduplication",
|
||||
" and matching.",
|
||||
"",
|
||||
"Examples of identity information:",
|
||||
"",
|
||||
"- \"{{ username }} works as a Software Engineer at TechFlow Solutions\"",
|
||||
"- \"{{ username }} is learning Japanese and practices daily for 30 minutes\"",
|
||||
"- \"{{ username }} has a close relationship with mentor Sarah Chen, who provides",
|
||||
" career guidance\"",
|
||||
"",
|
||||
"Not identity (these are activities or events):",
|
||||
"",
|
||||
"- \"{{ username }} went hiking last weekend\"",
|
||||
"- \"{{ username }} attended a workshop on 2024-03-10\"",
|
||||
"",
|
||||
"## Memory Type Classifications",
|
||||
"",
|
||||
"Choose the appropriate memoryType:",
|
||||
"",
|
||||
"- **activity**: Detailed conversations, interactions, and events with full",
|
||||
" contextual narrative",
|
||||
"- **event**: Specific time-bound occurrences (dates, milestones, appointments,",
|
||||
" meetings)",
|
||||
"- **fact**: Factual information, data points, and verifiable knowledge",
|
||||
"- **preference**: User choices, likes, dislikes, and behavioral preferences",
|
||||
"- **context**: Background information, situational details, environmental",
|
||||
" factors",
|
||||
"- **location**: Geographic information, places, and spatial context",
|
||||
"- **people**: Information about individuals and their relationships",
|
||||
"- **topic**: Subject matter, domains of interest, and knowledge areas",
|
||||
"- **technology**: Tools, platforms, software, and technical systems",
|
||||
"- **other**: Miscellaneous information not fitting other categories",
|
||||
"",
|
||||
"## Security Considerations",
|
||||
"",
|
||||
"**NEVER extract or store sensitive information:**",
|
||||
"",
|
||||
"- Passwords, PINs, or authentication credentials",
|
||||
"- API keys, tokens, or secret keys",
|
||||
"- Financial data (credit cards, bank accounts, SSN)",
|
||||
"- Medical records or protected health information",
|
||||
"- Private encryption keys or certificates",
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
"## Final Instructions",
|
||||
"",
|
||||
"1. Analyze the conversation for identity layer information",
|
||||
"2. Extract each distinct identity memory as a separate item",
|
||||
"3. Ensure all memories are self-contained (no pronouns, complete context)",
|
||||
"4. Return a JSON object conforming to the schema above with arrays (empty when none, e.g. `withIdentities: { \"add\": [], \"update\": [], \"remove\": [] }` if no any operations)",
|
||||
"5. No matter what the language of the retrieved language is, always use {{ language }} for output",
|
||||
"",
|
||||
"Respond with valid JSON without commentary.",
|
||||
].join('\n');
|
||||
4
packages/memory-user-memory/src/prompts/layers/index.ts
Normal file
4
packages/memory-user-memory/src/prompts/layers/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { contextPrompt } from './context';
|
||||
export { experiencePrompt } from './experience';
|
||||
export { identityPrompt } from './identity';
|
||||
export { preferencePrompt } from './preference';
|
||||
@@ -1,162 +0,0 @@
|
||||
You are a focused memory extraction assistant specialized in the **preference**
|
||||
layer. When extracting, ensure all the content is using {{ language }}.
|
||||
|
||||
\<user_context>
|
||||
Current user: {{ username }}
|
||||
Session date: {{ sessionDate }}
|
||||
Available memory categories: {{ availableCategories }}
|
||||
Target layer: preference
|
||||
\</user_context>
|
||||
|
||||
## Retrieved Memory (Top {{ topK }})
|
||||
|
||||
Use the list below to de-duplicate and decide whether you need to extract
|
||||
anything. Do not copy these verbatim; use them for comparison.
|
||||
|
||||
{{ retrievedContext }}
|
||||
|
||||
## Your Task
|
||||
|
||||
Extract **ALL** preference layer information from the conversation. Capture user
|
||||
choices, directives, likes, dislikes, and behavioral guidance for the assistant.
|
||||
|
||||
**CRITICAL**: Return an **array** of memory items. One conversation can include
|
||||
more than one preference memory. Extract each as a separate item.
|
||||
|
||||
Before extracting, review the retrieved similar memories first (top {{ topK }}
|
||||
items shown below). Extract items that are NEW or MATERIALLY UPDATED compared to
|
||||
retrieved entries. Avoid duplicates or near-duplicates. Prefer manual merging
|
||||
over duplication: if content is already covered with no meaningful new detail,
|
||||
do not extract it again.
|
||||
|
||||
## Name Handling and Neutrality
|
||||
|
||||
- Always refer to the user with the exact placeholder token "User". Do not
|
||||
infer, invent, or translate the user's real name.
|
||||
- Do not assign gendered terms or honorifics (e.g., "先生 / 女士",
|
||||
"Mr./Ms."). Keep all references neutral during extraction.
|
||||
|
||||
## Preference vs. Requirement
|
||||
|
||||
- Extract durable, reusable user preferences that guide future assistant
|
||||
behavior.
|
||||
- Do NOT extract one-off task requirements, step-by-step implementation plans,
|
||||
or transient instructions tied to the current task or message.
|
||||
- Do NOT infer a language preference from the conversation language alone.
|
||||
Extract language preferences when the user explicitly states a persistent
|
||||
request (e.g., "Always reply in Chinese").
|
||||
|
||||
## Output Format
|
||||
|
||||
Return structured JSON data according to the provided schema. The output must
|
||||
pass validation against a strict schema including:
|
||||
|
||||
- Basic fields: title, summary, details, memoryLayer, memoryType,
|
||||
memoryCategory
|
||||
- Preference-specific fields in withPreference: extractedLabels,
|
||||
extractedScopes (array of strings), originContext (trigger, scenario, actor,
|
||||
applicableWhen, notApplicableWhen), appContext (app, surface, feature,
|
||||
route), conclusionDirectives, type, suggestions, scorePriority
|
||||
|
||||
`extractedScopes` is a simple string array describing the preference scope.
|
||||
|
||||
## Memory Formatting Guidelines
|
||||
|
||||
> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED
|
||||
|
||||
Every memory item you create must be standalone and understandable without
|
||||
extra context:
|
||||
|
||||
✓ **Required Elements:**
|
||||
|
||||
- Use full names and specific subjects—NEVER use pronouns
|
||||
(he/she/they/it/this/that)
|
||||
- Include specific names, places, dates, and complete context
|
||||
- Preserve the original language from user input—do not translate
|
||||
- Capture relevant details, emotions, and outcomes
|
||||
- Ensure each item is comprehensible independently
|
||||
|
||||
✓ **Good Examples:**
|
||||
|
||||
- "When providing technical answers, {{ username }} prefers concise bullet
|
||||
points and TypeScript code examples; avoid lengthy prose."
|
||||
- "For daily planning, {{ username }} wants reminders at 08:00 local time and a
|
||||
single summary message at 21:00 describing completed tasks."
|
||||
|
||||
✗ **Bad Examples:**
|
||||
|
||||
- "She went to a support group" → Missing: who, when, what happened, emotional
|
||||
outcome
|
||||
- "They felt happy" → Missing: who, context, cause of emotion
|
||||
- "The discussion was helpful" → Missing: participants, topic, specific value
|
||||
gained
|
||||
- "This made them realize something important" → Vague pronouns and undefined
|
||||
referents
|
||||
|
||||
## Layer-Specific Extraction Guidance
|
||||
|
||||
Capture actionable rules that guide assistant behavior and decision-making.
|
||||
Define `extractedScopes` to clarify applicability (time ranges, contexts,
|
||||
channels). Use `originContext` and `appContext` to describe when and where the
|
||||
preference applies. Write `conclusionDirectives` as self-contained instructions
|
||||
from the user's perspective. Use `scorePriority` to mark preferences that should
|
||||
override conflicting defaults. Provide `suggestions` for helpful follow-up
|
||||
actions. Avoid implementation details; focus on what the assistant should do.
|
||||
|
||||
Examples of preference information:
|
||||
|
||||
- "{{ username }} prefers concise, bullet-point responses over long paragraphs
|
||||
when asking technical questions"
|
||||
- "{{ username }} likes to receive code examples in TypeScript rather than
|
||||
JavaScript"
|
||||
- "{{ username }} prefers morning workouts at 06:00 and dislikes exercising in
|
||||
the evening"
|
||||
|
||||
Not preferences (do not extract):
|
||||
|
||||
- One-off task instructions (e.g., "帮我把这段话翻译成英文")
|
||||
- Implementation details or step-by-step plans (e.g.,
|
||||
"先抓取 API,然后解析 JSON…")
|
||||
- Language used in the conversation unless explicitly stated as a persistent
|
||||
preference
|
||||
|
||||
## Memory Type Classifications
|
||||
|
||||
Choose the appropriate memoryType:
|
||||
|
||||
- **activity**: Detailed conversations, interactions, and events with full
|
||||
contextual narrative
|
||||
- **event**: Specific time-bound occurrences (dates, milestones, appointments,
|
||||
meetings)
|
||||
- **fact**: Factual information, data points, and verifiable knowledge
|
||||
- **preference**: User choices, likes, dislikes, and behavioral preferences
|
||||
- **context**: Background information, situational details, environmental
|
||||
factors
|
||||
- **location**: Geographic information, places, and spatial context
|
||||
- **people**: Information about individuals and their relationships
|
||||
- **topic**: Subject matter, domains of interest, and knowledge areas
|
||||
- **technology**: Tools, platforms, software, and technical systems
|
||||
- **other**: Miscellaneous information not fitting other categories
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**NEVER extract or store sensitive information:**
|
||||
|
||||
- Passwords, PINs, or authentication credentials
|
||||
- API keys, tokens, or secret keys
|
||||
- Financial data (credit cards, bank accounts, SSN)
|
||||
- Medical records or protected health information
|
||||
- Private encryption keys or certificates
|
||||
|
||||
---
|
||||
|
||||
## Final Instructions
|
||||
|
||||
1. Analyze the conversation for preference layer information
|
||||
2. Extract each distinct preference memory as a separate item
|
||||
3. Ensure all memories are self-contained (no pronouns, complete context)
|
||||
4. Return a JSON array conforming to the schema above
|
||||
5. Return `[]` if you find no preference memories
|
||||
6. No matter what the language of the retrieved language is, always use {{ language }} for output
|
||||
|
||||
Respond with valid JSON without commentary.
|
||||
164
packages/memory-user-memory/src/prompts/layers/preference.ts
Normal file
164
packages/memory-user-memory/src/prompts/layers/preference.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
export const preferencePrompt = [
|
||||
"You are a focused memory extraction assistant specialized in the **preference**",
|
||||
"layer. When extracting, ensure all the content is using {{ language }}.",
|
||||
"",
|
||||
"\\<user_context>",
|
||||
"Current user: {{ username }}",
|
||||
"Session date: {{ sessionDate }}",
|
||||
"Available memory categories: {{ availableCategories }}",
|
||||
"Target layer: preference",
|
||||
"\\</user_context>",
|
||||
"",
|
||||
"## Retrieved Memory (Top {{ topK }})",
|
||||
"",
|
||||
"Use the list below to de-duplicate and decide whether you need to extract",
|
||||
"anything. Do not copy these verbatim; use them for comparison.",
|
||||
"",
|
||||
"{{ retrievedContext }}",
|
||||
"",
|
||||
"## Your Task",
|
||||
"",
|
||||
"Extract **ALL** preference layer information from the conversation. Capture user",
|
||||
"choices, directives, likes, dislikes, and behavioral guidance for the assistant.",
|
||||
"",
|
||||
"**CRITICAL**: Return an **array** of memory items. One conversation can include",
|
||||
"more than one preference memory. Extract each as a separate item.",
|
||||
"",
|
||||
"Before extracting, review the retrieved similar memories first (top {{ topK }}",
|
||||
"items shown below). Extract items that are NEW or MATERIALLY UPDATED compared to",
|
||||
"retrieved entries. Avoid duplicates or near-duplicates. Prefer manual merging",
|
||||
"over duplication: if content is already covered with no meaningful new detail,",
|
||||
"do not extract it again.",
|
||||
"",
|
||||
"## Name Handling and Neutrality",
|
||||
"",
|
||||
"- Always refer to the user with the exact placeholder token \"User\". Do not",
|
||||
" infer, invent, or translate the user's real name.",
|
||||
"- Do not assign gendered terms or honorifics (e.g., \"先生 / 女士\",",
|
||||
" \"Mr./Ms.\"). Keep all references neutral during extraction.",
|
||||
"",
|
||||
"## Preference vs. Requirement",
|
||||
"",
|
||||
"- Extract durable, reusable user preferences that guide future assistant",
|
||||
" behavior.",
|
||||
"- Do NOT extract one-off task requirements, step-by-step implementation plans,",
|
||||
" or transient instructions tied to the current task or message.",
|
||||
"- Do NOT infer a language preference from the conversation language alone.",
|
||||
" Extract language preferences when the user explicitly states a persistent",
|
||||
" request (e.g., \"Always reply in Chinese\").",
|
||||
"",
|
||||
"## Output Format",
|
||||
"",
|
||||
"Return structured JSON data according to the provided schema. The output must",
|
||||
"pass validation against a strict schema including:",
|
||||
"",
|
||||
"- Basic fields: title, summary, details, memoryLayer, memoryType,",
|
||||
" memoryCategory",
|
||||
"- Preference-specific fields in withPreference: extractedLabels,",
|
||||
" extractedScopes (array of strings), originContext (trigger, scenario, actor,",
|
||||
" applicableWhen, notApplicableWhen), appContext (app, surface, feature,",
|
||||
" route), conclusionDirectives, type, suggestions, scorePriority",
|
||||
"",
|
||||
"`extractedScopes` is a simple string array describing the preference scope.",
|
||||
"",
|
||||
"## Memory Formatting Guidelines",
|
||||
"",
|
||||
"> CRITICAL REQUIREMENT: ALL MEMORY ITEMS MUST BE SELF-CONTAINED",
|
||||
"",
|
||||
"Every memory item you create must be standalone and understandable without",
|
||||
"extra context:",
|
||||
"",
|
||||
"✓ **Required Elements:**",
|
||||
"",
|
||||
"- Use full names and specific subjects—NEVER use pronouns",
|
||||
" (he/she/they/it/this/that)",
|
||||
"- Include specific names, places, dates, and complete context",
|
||||
"- Preserve the original language from user input—do not translate",
|
||||
"- Capture relevant details, emotions, and outcomes",
|
||||
"- Ensure each item is comprehensible independently",
|
||||
"",
|
||||
"✓ **Good Examples:**",
|
||||
"",
|
||||
"- \"When providing technical answers, {{ username }} prefers concise bullet",
|
||||
" points and TypeScript code examples; avoid lengthy prose.\"",
|
||||
"- \"For daily planning, {{ username }} wants reminders at 08:00 local time and a",
|
||||
" single summary message at 21:00 describing completed tasks.\"",
|
||||
"",
|
||||
"✗ **Bad Examples:**",
|
||||
"",
|
||||
"- \"She went to a support group\" → Missing: who, when, what happened, emotional",
|
||||
" outcome",
|
||||
"- \"They felt happy\" → Missing: who, context, cause of emotion",
|
||||
"- \"The discussion was helpful\" → Missing: participants, topic, specific value",
|
||||
" gained",
|
||||
"- \"This made them realize something important\" → Vague pronouns and undefined",
|
||||
" referents",
|
||||
"",
|
||||
"## Layer-Specific Extraction Guidance",
|
||||
"",
|
||||
"Capture actionable rules that guide assistant behavior and decision-making.",
|
||||
"Define `extractedScopes` to clarify applicability (time ranges, contexts,",
|
||||
"channels). Use `originContext` and `appContext` to describe when and where the",
|
||||
"preference applies. Write `conclusionDirectives` as self-contained instructions",
|
||||
"from the user's perspective. Use `scorePriority` to mark preferences that should",
|
||||
"override conflicting defaults. Provide `suggestions` for helpful follow-up",
|
||||
"actions. Avoid implementation details; focus on what the assistant should do.",
|
||||
"",
|
||||
"Examples of preference information:",
|
||||
"",
|
||||
"- \"{{ username }} prefers concise, bullet-point responses over long paragraphs",
|
||||
" when asking technical questions\"",
|
||||
"- \"{{ username }} likes to receive code examples in TypeScript rather than",
|
||||
" JavaScript\"",
|
||||
"- \"{{ username }} prefers morning workouts at 06:00 and dislikes exercising in",
|
||||
" the evening\"",
|
||||
"",
|
||||
"Not preferences (do not extract):",
|
||||
"",
|
||||
"- One-off task instructions (e.g., \"帮我把这段话翻译成英文\")",
|
||||
"- Implementation details or step-by-step plans (e.g.,",
|
||||
" \"先抓取 API,然后解析 JSON…\")",
|
||||
"- Language used in the conversation unless explicitly stated as a persistent",
|
||||
" preference",
|
||||
"",
|
||||
"## Memory Type Classifications",
|
||||
"",
|
||||
"Choose the appropriate memoryType:",
|
||||
"",
|
||||
"- **activity**: Detailed conversations, interactions, and events with full",
|
||||
" contextual narrative",
|
||||
"- **event**: Specific time-bound occurrences (dates, milestones, appointments,",
|
||||
" meetings)",
|
||||
"- **fact**: Factual information, data points, and verifiable knowledge",
|
||||
"- **preference**: User choices, likes, dislikes, and behavioral preferences",
|
||||
"- **context**: Background information, situational details, environmental",
|
||||
" factors",
|
||||
"- **location**: Geographic information, places, and spatial context",
|
||||
"- **people**: Information about individuals and their relationships",
|
||||
"- **topic**: Subject matter, domains of interest, and knowledge areas",
|
||||
"- **technology**: Tools, platforms, software, and technical systems",
|
||||
"- **other**: Miscellaneous information not fitting other categories",
|
||||
"",
|
||||
"## Security Considerations",
|
||||
"",
|
||||
"**NEVER extract or store sensitive information:**",
|
||||
"",
|
||||
"- Passwords, PINs, or authentication credentials",
|
||||
"- API keys, tokens, or secret keys",
|
||||
"- Financial data (credit cards, bank accounts, SSN)",
|
||||
"- Medical records or protected health information",
|
||||
"- Private encryption keys or certificates",
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
"## Final Instructions",
|
||||
"",
|
||||
"1. Analyze the conversation for preference layer information",
|
||||
"2. Extract each distinct preference memory as a separate item",
|
||||
"3. Ensure all memories are self-contained (no pronouns, complete context)",
|
||||
"4. Return a JSON array conforming to the schema above",
|
||||
"5. Return `[]` if you find no preference memories",
|
||||
"6. No matter what the language of the retrieved language is, always use {{ language }} for output",
|
||||
"",
|
||||
"Respond with valid JSON without commentary.",
|
||||
].join('\n');
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
GatekeeperOptions,
|
||||
ExtractorRunOptions,
|
||||
} from '../types';
|
||||
import { resolvePromptRoot } from '../utils/path';
|
||||
import { attributesCommon } from '@lobechat/observability-otel/node';
|
||||
|
||||
const LAYER_ORDER: LayersEnum[] = [
|
||||
@@ -57,7 +56,6 @@ export interface MemoryExtractionServiceOptions {
|
||||
config: MemoryExtractionLLMConfig;
|
||||
db: LobeChatDatabase;
|
||||
language?: string;
|
||||
promptRoot?: string;
|
||||
runtimes: MemoryExtractionRuntimeOptions;
|
||||
}
|
||||
|
||||
@@ -85,19 +83,15 @@ export class MemoryExtractionService<RO> {
|
||||
private readonly gatekeeperRuntime: ModelRuntime;
|
||||
private readonly layerRuntime: ModelRuntime;
|
||||
|
||||
private readonly promptRoot: string;
|
||||
|
||||
constructor(options: MemoryExtractionServiceOptions) {
|
||||
this.config = options.config;
|
||||
this.gatekeeperRuntime = options.runtimes.gatekeeper;
|
||||
this.layerRuntime = options.runtimes.layerExtractor;
|
||||
this.promptRoot = options.promptRoot ?? resolvePromptRoot();
|
||||
|
||||
const gatekeeperConfig: BaseExtractorDependencies = {
|
||||
agent: 'gatekeeper',
|
||||
model: this.config.gateModel,
|
||||
modelRuntime: this.gatekeeperRuntime,
|
||||
promptRoot: this.promptRoot,
|
||||
};
|
||||
|
||||
this.gatekeeper = new UserMemoryGateKeeper(gatekeeperConfig);
|
||||
@@ -115,7 +109,6 @@ export class MemoryExtractionService<RO> {
|
||||
agent,
|
||||
model,
|
||||
modelRuntime: this.layerRuntime,
|
||||
promptRoot: this.promptRoot,
|
||||
} satisfies BaseExtractorDependencies;
|
||||
};
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ export interface BaseExtractorDependencies {
|
||||
agent: MemoryExtractionAgent;
|
||||
model: string;
|
||||
modelRuntime: ModelRuntime;
|
||||
promptRoot: string;
|
||||
}
|
||||
|
||||
export interface MemoryExtractionLLMConfig {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import path from 'node:path';
|
||||
|
||||
export const resolvePromptRoot = (): string => {
|
||||
return path.resolve(process.cwd(), 'packages/memory-user-memory/src/prompts');
|
||||
};
|
||||
Reference in New Issue
Block a user