From c51202e3ef754dbdf2091ea7388749c7c03db23c Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Mon, 13 Apr 2026 23:08:07 -0400 Subject: [PATCH] feat: add filter hooks to fully override daily memory storage backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add datamachine_daily_memory_{read,write,list,search,delete} filters to DailyMemoryAbilities. Each filter receives null by default — return a non-null result array to completely replace the flat-file operation. This lets consumers like Intelligence store daily memory as WordPress pages, external services, or anything else without Data Machine needing to know or care. Remove the duplicative datamachine_daily_memory_archived action from DailyMemoryTask — the pre_archive filter already handles the write override, and the new ability-level filters cover read-back. --- inc/Abilities/DailyMemoryAbilities.php | 149 +++++++++++++++--- .../AI/System/Tasks/DailyMemoryTask.php | 33 +--- 2 files changed, 133 insertions(+), 49 deletions(-) diff --git a/inc/Abilities/DailyMemoryAbilities.php b/inc/Abilities/DailyMemoryAbilities.php index 1bc68d20b..bcb062e10 100644 --- a/inc/Abilities/DailyMemoryAbilities.php +++ b/inc/Abilities/DailyMemoryAbilities.php @@ -3,7 +3,14 @@ * Daily Memory Abilities * * WordPress 6.9 Abilities API primitives for daily memory operations. - * Provides read/write/list access to daily memory files (YYYY/MM/DD.md). + * Provides read/write/list/search/delete access to daily memory. + * + * Each operation fires a filter (`datamachine_daily_memory_{operation}`) that + * allows plugins to completely replace the storage backend. If the filter + * returns a non-null value, the flat-file operation is skipped entirely. + * This enables consumers like Intelligence to store daily memory as + * WordPress pages, external services, or anything else — Data Machine + * doesn't need to know or care. * * @package DataMachine\Abilities * @since 0.32.0 @@ -250,10 +257,7 @@ private function registerAbilities(): void { * @return array Result. */ public static function readDaily( array $input ): array { - $user_id = (int) ( $input['user_id'] ?? 0 ); - $agent_id = (int) ( $input['agent_id'] ?? 0 ); - $daily = new DailyMemory( $user_id, $agent_id ); - $date = $input['date'] ?? gmdate( 'Y-m-d' ); + $date = $input['date'] ?? gmdate( 'Y-m-d' ); $parts = DailyMemory::parse_date( $date ); if ( ! $parts ) { @@ -263,6 +267,30 @@ public static function readDaily( array $input ): array { ); } + /** + * Filters the daily memory read result. + * + * Return a non-null array to completely replace the flat-file read. + * The array should match the standard result format: + * `{ success: bool, date?: string, content?: string, message?: string }` + * + * @since 0.47.0 + * + * @param array|null $result Default null (flat-file read proceeds). + * Return an array to short-circuit. + * @param string $date The requested date (YYYY-MM-DD). + * @param array $input Full input parameters (includes user_id, agent_id). + */ + $result = apply_filters( 'datamachine_daily_memory_read', null, $date, $input ); + + if ( null !== $result ) { + return $result; + } + + $user_id = (int) ( $input['user_id'] ?? 0 ); + $agent_id = (int) ( $input['agent_id'] ?? 0 ); + $daily = new DailyMemory( $user_id, $agent_id ); + return $daily->read( $parts['year'], $parts['month'], $parts['day'] ); } @@ -280,12 +308,9 @@ public static function writeDaily( array $input ): array { ); } - $user_id = (int) ( $input['user_id'] ?? 0 ); - $agent_id = (int) ( $input['agent_id'] ?? 0 ); - $daily = new DailyMemory( $user_id, $agent_id ); - $content = $input['content']; - $date = $input['date'] ?? gmdate( 'Y-m-d' ); - $mode = $input['mode'] ?? 'append'; + $date = $input['date'] ?? gmdate( 'Y-m-d' ); + $content = $input['content']; + $mode = $input['mode'] ?? 'append'; $parts = DailyMemory::parse_date( $date ); if ( ! $parts ) { @@ -295,6 +320,31 @@ public static function writeDaily( array $input ): array { ); } + /** + * Filters the daily memory write result. + * + * Return a non-null array to completely replace the flat-file write. + * The array should match: `{ success: bool, message?: string }` + * + * @since 0.47.0 + * + * @param array|null $result Default null (flat-file write proceeds). + * Return an array to short-circuit. + * @param string $date The target date (YYYY-MM-DD). + * @param string $content The content to write. + * @param string $mode Write mode: 'write' or 'append'. + * @param array $input Full input parameters (includes user_id, agent_id). + */ + $result = apply_filters( 'datamachine_daily_memory_write', null, $date, $content, $mode, $input ); + + if ( null !== $result ) { + return $result; + } + + $user_id = (int) ( $input['user_id'] ?? 0 ); + $agent_id = (int) ( $input['agent_id'] ?? 0 ); + $daily = new DailyMemory( $user_id, $agent_id ); + if ( 'write' === $mode ) { return $daily->write( $parts['year'], $parts['month'], $parts['day'], $content ); } @@ -305,10 +355,28 @@ public static function writeDaily( array $input ): array { /** * List all daily memory files. * - * @param array $input Input parameters (unused). + * @param array $input Input parameters. * @return array Result. */ public static function listDaily( array $input ): array { + /** + * Filters the daily memory list result. + * + * Return a non-null array to completely replace the flat-file listing. + * The array should match: `{ months: { 'YYYY/MM': ['DD', ...], ... } }` + * + * @since 0.47.0 + * + * @param array|null $result Default null (flat-file list proceeds). + * Return an array to short-circuit. + * @param array $input Full input parameters (includes user_id, agent_id). + */ + $result = apply_filters( 'datamachine_daily_memory_list', null, $input ); + + if ( null !== $result ) { + return $result; + } + $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $daily = new DailyMemory( $user_id, $agent_id ); @@ -322,12 +390,35 @@ public static function listDaily( array $input ): array { * @return array Search results. */ public static function searchDaily( array $input ): array { + $query = $input['query']; + $from = $input['from'] ?? null; + $to = $input['to'] ?? null; + + /** + * Filters the daily memory search result. + * + * Return a non-null array to completely replace the flat-file search. + * The array should match: + * `{ success: bool, query: string, match_count: int, matches: [...] }` + * + * @since 0.47.0 + * + * @param array|null $result Default null (flat-file search proceeds). + * Return an array to short-circuit. + * @param string $query The search term. + * @param string|null $from Start date (YYYY-MM-DD) or null. + * @param string|null $to End date (YYYY-MM-DD) or null. + * @param array $input Full input parameters (includes user_id, agent_id). + */ + $result = apply_filters( 'datamachine_daily_memory_search', null, $query, $from, $to, $input ); + + if ( null !== $result ) { + return $result; + } + $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $daily = new DailyMemory( $user_id, $agent_id ); - $query = $input['query']; - $from = $input['from'] ?? null; - $to = $input['to'] ?? null; return $daily->search( $query, $from, $to ); } @@ -348,10 +439,7 @@ public static function deleteDaily( array $input ): array { ); } - $user_id = (int) ( $input['user_id'] ?? 0 ); - $agent_id = (int) ( $input['agent_id'] ?? 0 ); - $daily = new DailyMemory( $user_id, $agent_id ); - $date = $input['date'] ?? gmdate( 'Y-m-d' ); + $date = $input['date'] ?? gmdate( 'Y-m-d' ); $parts = DailyMemory::parse_date( $date ); if ( ! $parts ) { @@ -361,6 +449,29 @@ public static function deleteDaily( array $input ): array { ); } + /** + * Filters the daily memory delete result. + * + * Return a non-null array to completely replace the flat-file delete. + * The array should match: `{ success: bool, message?: string }` + * + * @since 0.47.0 + * + * @param array|null $result Default null (flat-file delete proceeds). + * Return an array to short-circuit. + * @param string $date The target date (YYYY-MM-DD). + * @param array $input Full input parameters (includes user_id, agent_id). + */ + $result = apply_filters( 'datamachine_daily_memory_delete', null, $date, $input ); + + if ( null !== $result ) { + return $result; + } + + $user_id = (int) ( $input['user_id'] ?? 0 ); + $agent_id = (int) ( $input['agent_id'] ?? 0 ); + $daily = new DailyMemory( $user_id, $agent_id ); + return $daily->delete( $parts['year'], $parts['month'], $parts['day'] ); } } diff --git a/inc/Engine/AI/System/Tasks/DailyMemoryTask.php b/inc/Engine/AI/System/Tasks/DailyMemoryTask.php index 073260ea0..41a33c79d 100644 --- a/inc/Engine/AI/System/Tasks/DailyMemoryTask.php +++ b/inc/Engine/AI/System/Tasks/DailyMemoryTask.php @@ -226,6 +226,9 @@ public function execute( int $jobId, array $params ): void { * an external service, etc.). When `true` is returned, the flat-file * write to `daily/YYYY/MM/DD.md` is skipped entirely. * + * For a complete storage backend override (read, list, search, delete), + * see the `datamachine_daily_memory_*` filters in DailyMemoryAbilities. + * * @since 0.46.0 * * @param bool $handled Whether a handler has already stored the content. @@ -256,36 +259,6 @@ public function execute( int $jobId, array $params ): void { $daily->append( $parts[0], $parts[1], $parts[2], $archive_text ); } - - /** - * Fires after daily memory archived content has been processed. - * - * This action fires regardless of whether the content was written to a - * flat file or handled by a `datamachine_daily_memory_pre_archive` filter. - * Use this for post-processing, notifications, or secondary storage. - * - * @since 0.46.0 - * - * @param string $content The archived content extracted from MEMORY.md. - * @param string $date The archive date (YYYY-MM-DD). - * @param bool $handled Whether a filter handled storage (true = flat file skipped). - * @param array $context { - * Additional context about the daily memory operation. - * - * @type string $persistent The persistent content remaining in MEMORY.md. - * @type int $original_size Original MEMORY.md size in bytes. - * @type int $new_size New MEMORY.md size in bytes after cleanup. - * @type int $archived_size Archived content size in bytes. - * @type int $job_id The job ID for this task execution. - * } - */ - do_action( - 'datamachine_daily_memory_archived', - $parsed['archived'], - $date, - $handled, - $archive_context - ); } do_action(