import { embedMany } from './_types/@internal_ai-sdk-v4/dist/index.js'; import type { MastraDBMessage } from '@mastra/core/agent'; import { MastraMemory } from '@mastra/core/memory'; import type { MemoryConfigInternal, SharedMemoryConfig, StorageThreadType, WorkingMemoryTemplate, MessageDeleteInput, ObservationalMemoryOptions, MemoryConfig } from '@mastra/core/memory'; import type { ObservabilityContext } from '@mastra/core/observability'; import type { InputProcessor, InputProcessorOrWorkflow, OutputProcessor, OutputProcessorOrWorkflow } from '@mastra/core/processors'; import type { RequestContext } from '@mastra/core/request-context'; import type { StorageListThreadsInput, StorageListThreadsOutput, StorageListMessagesInput, MemoryStorage, StorageCloneThreadInput, StorageCloneThreadOutput, ThreadCloneMetadata, ObservationalMemoryRecord } from '@mastra/core/storage'; import type { ToolAction } from '@mastra/core/tools'; import type { ObservationalMemory, ObservationalMemoryConfig } from './processors/observational-memory/index.js'; import { deepMergeWorkingMemory } from './tools/working-memory.js'; export { ModelByInputTokens, type ModelByInputTokensConfig, } from './processors/observational-memory/model-by-input-tokens.js'; /** * Normalize a `boolean | object` observational memory config. * Returns the options object if enabled, undefined if disabled. * Inlined here to avoid importing runtime exports that don't exist on older @mastra/core versions. */ type MemoryObservationalMemoryOptions = Omit & { model?: ObservationalMemoryConfig['model']; observation?: ObservationalMemoryConfig['observation']; reflection?: ObservationalMemoryConfig['reflection']; activateAfterIdle?: ObservationalMemoryConfig['activateAfterIdle']; activateOnProviderChange?: ObservationalMemoryConfig['activateOnProviderChange']; temporalMarkers?: boolean; }; type MemoryOptions = Omit & { observationalMemory?: boolean | MemoryObservationalMemoryOptions; }; type MemoryConstructorConfig = Omit & { options?: MemoryOptions; }; export declare function extractWorkingMemoryTags(text: string): string[] | null; export declare function removeWorkingMemoryTags(text: string): string; export declare function extractWorkingMemoryContent(text: string): string | null; export { deepMergeWorkingMemory }; /** * Concrete implementation of MastraMemory that adds support for thread configuration * and message injection. */ export declare class Memory extends MastraMemory { private _omEngine; /** The shared ObservationalMemory engine. Lazily created on first access. */ get omEngine(): Promise; constructor(config?: MemoryConstructorConfig); /** * Gets the memory storage domain, throwing if not available. */ protected getMemoryStore(): Promise; listMessagesByResourceId(args: { resourceId: string; perPage?: number | false; page?: number; orderBy?: { field?: 'createdAt'; direction?: 'ASC' | 'DESC'; }; filter?: { dateRange?: { start?: Date; end?: Date; startExclusive?: boolean; endExclusive?: boolean; }; }; include?: Array<{ id: string; threadId?: string; withPreviousMessages?: number; withNextMessages?: number; }>; }): Promise<{ messages: MastraDBMessage[]; total: number; page: number; perPage: number | false; hasMore: boolean; }>; protected validateThreadIsOwnedByResource(threadId: string, resourceId: string, config: MemoryConfigInternal): Promise; private createMemorySpan; recall(args: StorageListMessagesInput & { threadConfig?: MemoryConfigInternal; vectorSearchString?: string; includeSystemReminders?: boolean; threadId: string; observabilityContext?: Partial; }): Promise<{ messages: MastraDBMessage[]; usage?: { tokens: number; }; total: number; page: number; perPage: number | false; hasMore: boolean; }>; getThreadById({ threadId }: { threadId: string; }): Promise; listThreads(args: StorageListThreadsInput): Promise; private handleWorkingMemoryFromMetadata; saveThread({ thread, memoryConfig, }: { thread: StorageThreadType; memoryConfig?: MemoryConfigInternal; }): Promise; updateThread({ id, title, metadata, memoryConfig, }: { id: string; title: string; metadata: Record; memoryConfig?: MemoryConfigInternal; }): Promise; deleteThread(threadId: string): Promise; /** * Lists all vector indexes that match the memory messages prefix. * Handles separator differences across vector store backends (e.g. '_' vs '-'). */ private getMemoryVectorIndexes; /** * Deletes all vector embeddings associated with a thread. * This is called internally by deleteThread to clean up orphaned vectors. * * @param threadId - The ID of the thread whose vectors should be deleted */ private deleteThreadVectors; updateWorkingMemory({ threadId, resourceId, workingMemory, memoryConfig, observabilityContext, }: { threadId: string; resourceId?: string; workingMemory: string; memoryConfig?: MemoryConfigInternal; observabilityContext?: Partial; }): Promise; private updateWorkingMemoryMutexes; /** * @warning experimental! can be removed or changed at any time */ __experimental_updateWorkingMemoryVNext({ threadId, resourceId, workingMemory, searchString, memoryConfig, }: { threadId: string; resourceId?: string; workingMemory: string; searchString?: string; memoryConfig?: MemoryConfigInternal; }): Promise<{ success: boolean; reason: string; }>; protected chunkText(text: string, tokenSize?: number): string[]; private hasher; private embeddingCache; private firstEmbed; protected embedMessageContent(content: string): Promise<{ chunks: string[]; embeddings: Awaited>["embeddings"]; usage?: { tokens: number; }; dimension: number | undefined; }>; saveMessages({ messages, memoryConfig, observabilityContext, }: { messages: MastraDBMessage[]; memoryConfig?: MemoryConfig | undefined; observabilityContext?: Partial; }): Promise<{ messages: MastraDBMessage[]; usage?: { tokens: number; }; }>; protected updateMessageToHideWorkingMemoryV2(message: MastraDBMessage): MastraDBMessage | null; protected parseWorkingMemory(text: string): string | null; getWorkingMemory({ threadId, resourceId, memoryConfig, }: { threadId: string; resourceId?: string; memoryConfig?: MemoryConfigInternal; }): Promise; /** * Gets the working memory template for the current memory configuration. * Supports both ZodObject and JSONSchema7 schemas. * * @param memoryConfig - The memory configuration containing the working memory settings * @returns The working memory template with format and content, or null if working memory is disabled */ getWorkingMemoryTemplate({ memoryConfig, }: { memoryConfig?: MemoryConfigInternal; }): Promise; getSystemMessage({ threadId, resourceId, memoryConfig, }: { threadId: string; resourceId?: string; memoryConfig?: MemoryConfigInternal; }): Promise; /** * Get everything needed for an LLM call in one shot. * * Assembles the system message (observations + working memory), loads * unobserved messages from storage, and returns them ready to use. * * @example * ```ts * const ctx = await memory.getContext({ threadId }); * const result = await generateText({ * model: openai('gpt-4o'), * system: ctx.systemMessage, * messages: ctx.messages.map(toAiSdkMessage), * }); * ``` */ getContext(opts: { threadId: string; resourceId?: string; memoryConfig?: MemoryConfigInternal; }): Promise<{ /** Fully-formed system message (observations + instructions + working memory), or undefined if none. */ systemMessage: string | undefined; /** Messages for the LLM — unobserved messages if OM is active, or recent messages from history. */ messages: MastraDBMessage[]; /** Whether observations exist for this thread. */ hasObservations: boolean; /** The OM record, if OM is active. */ omRecord: ObservationalMemoryRecord | null; /** The om-continuation reminder message, if OM has observations. Caller decides where to place it. */ continuationMessage: MastraDBMessage | undefined; /** Formatted context blocks from other threads (resource scope only). */ otherThreadsContext: string | undefined; }>; /** * Raw message upsert — persist messages to storage without embedding or working memory processing. * Used by the processor to save sealed messages before firing a background buffer operation. */ persistMessages(messages: MastraDBMessage[]): Promise; /** * One-time initialization of the shared ObservationalMemory engine. * Called lazily by the `omEngine` getter on first access. */ private _initOMEngine; defaultWorkingMemoryTemplate: string; protected getWorkingMemoryToolInstruction({ template, data, }: { template: WorkingMemoryTemplate; data: string | null; }): string; protected __experimental_getWorkingMemoryToolInstructionVNext({ template, data, }: { template: WorkingMemoryTemplate; data: string | null; }): string; /** * Generate read-only working memory instructions. * This provides the working memory context without any tool update instructions. * Used when memory is in readOnly mode. */ protected getReadOnlyWorkingMemoryInstruction({ data }: { template: WorkingMemoryTemplate; data: string | null; }): string; private isVNextWorkingMemoryConfig; private getObservationEmbeddingIndexName; private createObservationEmbeddingIndex; /** * Search observation groups across threads by semantic similarity. * Requires a vector store and embedder to be configured. */ searchMessages({ query, resourceId, topK, filter, }: { query: string; resourceId: string; topK?: number; filter?: { threadId?: string; observedAfter?: Date; observedBefore?: Date; }; }): Promise<{ results: Array<{ threadId: string; score: number; groupId?: string; range?: string; text?: string; observedAt?: Date; }>; }>; /** * Index a single observation group into the observation vector store. */ indexObservation({ text, groupId, range, threadId, resourceId, observedAt, }: { text: string; groupId: string; range: string; threadId: string; resourceId: string; observedAt?: Date; }): Promise; /** * Update per-record observational memory config overrides for a thread. * The provided config is deep-merged, so you only need to specify fields you want to change. * * @example * ```ts * await memory.updateObservationalMemoryConfig({ * threadId: 'thread-1', * config: { * observation: { messageTokens: 2000 }, * reflection: { observationTokens: 8000 }, * }, * }); * ``` */ updateObservationalMemoryConfig({ threadId, resourceId, config, }: { threadId: string; resourceId?: string; config: Record; }): Promise; /** * Index a list of messages directly (without querying storage). * Used by observe-time indexing to vectorize newly-observed messages. */ private indexMessagesList; /** * Check whether retrieval search (vector-based) is enabled. * Returns true when `retrieval: { vector: true }` and Memory has vector + embedder configured. */ hasRetrievalSearch(retrieval: ObservationalMemoryOptions['retrieval']): boolean; listTools(config?: MemoryConfigInternal): Record>; /** * Updates a list of messages and syncs the vector database for semantic recall. * When message content is updated, the corresponding vector embeddings are also updated * to ensure semantic recall stays in sync with the message content. * * @param messages - The list of messages to update (must include id, can include partial content) * @param memoryConfig - Optional memory configuration to determine if semantic recall is enabled * @returns The list of updated messages */ updateMessages({ messages, memoryConfig, }: { messages: (Partial & { id: string; })[]; memoryConfig?: MemoryConfigInternal; }): Promise; /** * Deletes one or more messages * @param input - Must be an array containing either: * - Message ID strings * - Message objects with 'id' properties * @returns Promise that resolves when all messages are deleted */ deleteMessages(input: MessageDeleteInput, observabilityContext?: Partial): Promise; /** * Deletes vector embeddings for specific messages. * This is called internally by deleteMessages to clean up orphaned vectors. * * @param messageIds - The IDs of the messages whose vectors should be deleted */ private deleteMessageVectors; /** * Clone a thread and its messages to create a new independent thread. * The cloned thread will have metadata tracking its source. * * If semantic recall is enabled, the cloned messages will also be embedded * and added to the vector store for semantic search. * * @param args - Clone configuration options * @param args.sourceThreadId - ID of the thread to clone * @param args.newThreadId - ID for the new cloned thread (if not provided, a random UUID will be generated) * @param args.resourceId - Resource ID for the new thread (defaults to source thread's resourceId) * @param args.title - Title for the new cloned thread * @param args.metadata - Additional metadata to merge with clone metadata * @param args.options - Options for filtering which messages to include * @param args.options.messageLimit - Maximum number of messages to copy (from most recent) * @param args.options.messageFilter - Filter messages by date range or specific IDs * @param memoryConfig - Optional memory configuration override * @returns The newly created thread and the cloned messages * * @example * ```typescript * // Clone entire thread * const { thread, clonedMessages } = await memory.cloneThread({ * sourceThreadId: 'thread-123', * }); * * // Clone with custom ID * const { thread, clonedMessages } = await memory.cloneThread({ * sourceThreadId: 'thread-123', * newThreadId: 'my-custom-thread-id', * }); * * // Clone with message limit * const { thread, clonedMessages } = await memory.cloneThread({ * sourceThreadId: 'thread-123', * title: 'My cloned conversation', * options: { * messageLimit: 10, // Only clone last 10 messages * }, * }); * * // Clone with date filter * const { thread, clonedMessages } = await memory.cloneThread({ * sourceThreadId: 'thread-123', * options: { * messageFilter: { * startDate: new Date('2024-01-01'), * endDate: new Date('2024-06-01'), * }, * }, * }); * ``` */ cloneThread(args: StorageCloneThreadInput, memoryConfig?: MemoryConfigInternal): Promise; /** * Clone observational memory records when cloning a thread. * Thread-scoped: always cloned to the new thread. * Resource-scoped: cloned only when the resourceId changes (same resourceId shares OM naturally). * All stored message/thread IDs are remapped to the cloned IDs. */ private cloneObservationalMemory; /** * Create a remapped copy of an OM record with new thread/message IDs. */ private remapObservationalMemoryRecord; /** * Embed cloned messages for semantic recall. * This is similar to the embedding logic in saveMessages but operates on already-saved messages. */ private embedClonedMessages; /** * Get the clone metadata from a thread if it was cloned from another thread. * * @param thread - The thread to check * @returns The clone metadata if the thread is a clone, null otherwise * * @example * ```typescript * const thread = await memory.getThreadById({ threadId: 'thread-123' }); * const cloneInfo = memory.getCloneMetadata(thread); * if (cloneInfo) { * console.log(`This thread was cloned from ${cloneInfo.sourceThreadId}`); * } * ``` */ getCloneMetadata(thread: StorageThreadType | null): ThreadCloneMetadata | null; /** * Check if a thread is a clone of another thread. * * @param thread - The thread to check * @returns True if the thread is a clone, false otherwise * * @example * ```typescript * const thread = await memory.getThreadById({ threadId: 'thread-123' }); * if (memory.isClone(thread)) { * console.log('This is a cloned thread'); * } * ``` */ isClone(thread: StorageThreadType | null): boolean; /** * Get the source thread that a cloned thread was created from. * * @param threadId - ID of the cloned thread * @returns The source thread if found, null if the thread is not a clone or source doesn't exist * * @example * ```typescript * const sourceThread = await memory.getSourceThread('cloned-thread-123'); * if (sourceThread) { * console.log(`Original thread: ${sourceThread.title}`); * } * ``` */ getSourceThread(threadId: string): Promise; /** * List all threads that were cloned from a specific source thread. * * @param sourceThreadId - ID of the source thread * @param resourceId - Optional resource ID to filter by * @returns Array of threads that are clones of the source thread * * @example * ```typescript * const clones = await memory.listClones('original-thread-123', 'user-456'); * console.log(`Found ${clones.length} clones of this thread`); * ``` */ listClones(sourceThreadId: string, resourceId?: string): Promise; /** * Get the clone history chain for a thread (all ancestors back to the original). * * @param threadId - ID of the thread to get history for * @returns Array of threads from oldest ancestor to the given thread (inclusive) * * @example * ```typescript * const history = await memory.getCloneHistory('deeply-cloned-thread'); * // Returns: [originalThread, firstClone, secondClone, deeplyClonedThread] * ``` */ getCloneHistory(threadId: string): Promise; /** * Get input processors for this memory instance. * Extends the base implementation to add ObservationalMemory processor when configured. * * @param configuredProcessors - Processors already configured by the user (for deduplication) * @param context - Request context for runtime configuration * @returns Array of input processors configured for this memory instance */ getInputProcessors(configuredProcessors?: InputProcessorOrWorkflow[], context?: RequestContext): Promise; /** * Extends the base implementation to add ObservationalMemory as an output processor. * OM needs processOutputResult to save messages at the end of the agent turn, * even when the observation threshold was never reached during the loop. */ getOutputProcessors(configuredProcessors?: OutputProcessorOrWorkflow[], context?: RequestContext): Promise; /** * Creates an ObservationalMemory processor wrapping the shared engine. * Returns null if OM is not configured, not supported, or already present * in the user's configured processors. */ private createOMProcessor; } export { SemanticRecall, WorkingMemory, MessageHistory } from '@mastra/core/processors'; export type { StorageCloneThreadInput, StorageCloneThreadOutput, ThreadCloneMetadata } from '@mastra/core/storage'; export { getObservationsAsOf } from './processors/observational-memory/index.js'; //# sourceMappingURL=index.d.ts.map