feat: MEMANTO integration — persistent memory for cross-session context (Phases 1-4)

Phase 1: Core Client
- New class-memanto-client.php: Singleton PHP client for MEMANTO API v2
  - Health check with 5-min transient caching
  - Agent CRUD (ensure, activate, deactivate sessions)
  - Memory operations (remember, batch_remember, recall, recall_recent)
  - Auto re-activation on expired session tokens (401 retry)

Phase 2: Write-Through Memory Hooks
- New class-memanto-context-enhancer.php: Orchestrates remember/recall
  - Fires on: user message, plan generated/approved/rejected,
    section written, block refined, config saved, session start/end
  - All hooks via do_action() — zero coupling to MEMANTO when disabled

Phase 3: Context Enrichment
- Context builder injects recalled memories into AI prompts
  via build_memanto_context() in build_working_context()
- 3-recall strategy: recent post memories, semantic search, user preferences
- Deduplication by content hash

Phase 4: Cross-Session Restore
- New REST endpoints: /memanto/restore, /memanto/preferences
- restore_session() recalls 15 recent memories + user preferences on editor load
- build_session_restore_message() creates AI-ready system message
- get_user_preferences_for_new_post() extracts tone/audience/length/language
- Frontend: 🧠 Restored badge in status bar with memory count tooltip
- Preference carry-over: auto-fills post config from stored user preferences
- deactivate_session() called on session end (triggers MEMANTO summary)
- Badge clears on new conversation start

Settings UI:
- MEMANTO Context Keeper section with enable toggle, URL, API key, test connection
- Settings registered via class-settings-v2.php + tab-memanto.php view

Graceful degradation: all MEMANTO calls guarded by is_active(),
frontend catches silently, plugin works identically when disabled.
This commit is contained in:
Dwindi Ramadhana
2026-06-08 12:42:04 +07:00
parent 379a72e52d
commit 619d36d3c8
11 changed files with 28226 additions and 18716 deletions

View File

@@ -0,0 +1,435 @@
# MEMANTO Integration Plan — Optional Context Enhancement
**Version:** 1.0
**Date:** 2026-06-07
**Status:** Planning
**Depends on:** MEMANTO_PRICING_STRATEGY.md
---
## Design Principles
1. **MEMANTO is optional.** The plugin's built-in Context Builder (`class-context-builder.php`) remains the default and always works without MEMANTO.
2. **MEMANTO enhances, never replaces.** MySQL sessions (`wpaw_conversations`) remain the primary session store. MEMANTO runs parallel.
3. **Zero disruption on failure.** If MEMANTO is unreachable, the plugin falls back to existing behavior with no error shown to the user.
4. **Server-side only.** All MEMANTO API calls happen in PHP. The frontend (sidebar.js) is unaware of MEMANTO — it just sees richer or leaner context in AI responses.
5. **User brings own Moorcheh key.** Plugin stores MEMANTO URL + Moorcheh API key in WordPress settings. Never hardcoded.
---
## Architecture Overview
```
┌────────────────────────────────────────────────┐
│ WordPress Backend │
│ │
User Message ──────► │ Gutenberg Sidebar (handle_chat_request) │
│ │ │
│ ▼ │
│ Context Builder (build_system_message) │
│ │ │
│ ├──► MySQL Session (wpaw_conversations) │
│ │ primary store │
│ │ │
│ ├──► Memanto Client ──► MEMANTO API │
│ │ (if configured) │
│ │ │ │
│ │ ├── recall (retrieve) │
│ │ └── remember (store) │
│ │ │
│ ▼ │
│ Merged Context → AI Provider → Response │
└────────────────────────────────────────────────┘
```
### Data Flow: Two Paths
| Path | When | What Happens |
|---|---|---|
| **Default (no MEMANTO)** | MEMANTO URL not configured in settings | Context Builder uses MySQL session only. Identical to current behavior. |
| **MEMANTO active** | MEMANTO URL + Moorcheh key configured and validated | Context Builder queries MEMANTO for relevant memories before building context. After AI response, significant events are stored in MEMANTO. |
---
## Agent Design
### Agent Naming Convention
| Agent ID | Scope | Purpose |
|---|---|---|
| `wp-user-{wordpress_user_id}` | Per WordPress user | Cross-post preferences: writing style, tone, audience, language, brand voice |
| `wp-post-{wordpress_post_id}` | Per post | Article-specific: plan decisions, rejections, research, section progress |
### Memory Types Used
| MEMANTO Type | When Stored | Example |
|---|---|---|
| `preference` | User sets/changes post config | "User prefers conversational tone, intermediate audience" |
| `instruction` | User sends chat message | "Focus on plugin vulnerabilities only" |
| `decision` | User approves/rejects plan | "Approved 5-section outline for WordPress security" |
| `artifact` | Plan generated, section written | "Plan: 5 sections covering X, Y, Z" |
| `context` | Session ends / summarize | "Article at 60% completion, 3 of 5 sections done" |
| `error` | User corrects AI output | "User rejected generic tips approach, wants specific plugin recommendations" |
### Tags Convention
Tags enable targeted recall. Every memory includes:
| Tag | Example | Purpose |
|---|---|---|
| `post:{id}` | `post:42` | Scope recall to specific post |
| `site:{domain}` | `site:example.com` | Scope to WordPress site |
| `mode:{mode}` | `mode:planning` | What mode was active |
| `model:{model}` | `model:deepseek-chat` | Which model was used |
---
## New Files to Create
### `includes/class-memanto-client.php`
PHP client for MEMANTO API v2. Singleton class.
**Public Methods:**
| Method | Description |
|---|---|
| `is_configured()` | Returns true if MEMANTO URL + Moorcheh key are set in settings |
| `is_healthy()` | Calls `/health` endpoint, caches result for 5 minutes |
| `ensure_agent( $agent_id )` | Creates agent via `POST /api/v2/agents` if not exists |
| `activate_session( $agent_id )` | `POST /api/v2/agents/{id}/activate`, caches session token in transient |
| `remember( $agent_id, $content, $type, $tags, $title )` | `POST /api/v2/agents/{id}/remember` |
| `batch_remember( $agent_id, $memories )` | `POST /api/v2/agents/{id}/batch-remember` |
| `recall( $agent_id, $query, $type, $limit )` | `POST /api/v2/agents/{id}/recall` |
| `recall_recent( $agent_id, $limit )` | `POST /api/v2/agents/{id}/recall/recent` |
| `deactivate_session( $agent_id )` | `POST /api/v2/agents/{id}/deactivate` |
**Internal Mechanics:**
- Session token stored in WP transient: `wpaw_memanto_token_{agent_id}` (6-hour TTL matching MEMANTO JWT)
- Auto-reactivates on expired token (catches 401, re-activates, retries)
- All calls use `wp_remote_post` / `wp_remote_get` with 10-second timeout
- All calls wrapped in try/catch with `wpaw_debug_log` on failure
- Moorcheh API key passed via `X-API-Key` header or configured in MEMANTO instance (depending on MEMANTO's auth model)
### `includes/class-memanto-context-enhancer.php`
Orchestrates when and what to remember/recall. Hooks into existing Context Service.
**Public Methods:**
| Method | Hook Point | Description |
|---|---|---|
| `on_session_start( $session_id, $post_id, $user_id )` | Session creation | Ensures user + post agents exist; recalls previous session state |
| `on_user_message( $session_id, $content, $post_id )` | After user sends message | Stores instruction-type memory |
| `on_plan_generated( $post_id, $plan )` | After plan creation | Stores artifact-type memory |
| `on_plan_approved( $post_id, $plan )` | User approves plan | Stores decision-type memory |
| `on_plan_rejected( $post_id, $reason )` | User rejects/requests changes | Stores error-type memory with rejection reason |
| `on_section_written( $post_id, $section_id, $summary )` | After section generation | Stores artifact-type memory |
| `on_block_refined( $post_id, $block_id, $instruction )` | After refinement | Stores instruction-type memory |
| `on_config_saved( $post_id, $config )` | Post config updated | Stores preference-type memory to both user and post agents |
| `on_session_end( $session_id, $post_id )` | Session completed/archived | Summarizes session, stores context-type memory, deactivates session |
| `recall_for_context( $post_id, $user_id, $current_message )` | Before building context | Returns recalled memories to enrich prompt |
**Recall Strategy (`recall_for_context`):**
1. Recall recent memories from post agent (limit: 10)
2. Recall semantically relevant memories from post agent (query: user's current message, limit: 5)
3. Recall user preferences from user agent (query: "writing preferences tone audience", limit: 5)
4. Deduplicate by content hash
5. Return structured array of recalled items
---
## Files to Modify
### `includes/class-settings-v2.php`
Add MEMANTO configuration section:
```
MEMANTO Context Keeper
├── Enable MEMANTO integration (checkbox, default: off)
├── MEMANTO Instance URL (text, e.g., https://abc123.context.wpagentic.dev)
├── Moorcheh API Key (password, user's own key)
└── Connection Status (read-only, shows "Connected" / "Not configured" / "Error: ...")
```
Add a "Test Connection" button that calls MEMANTO `/health` endpoint.
### `includes/class-context-builder.php`
Modify `build_for_task()` method. After line ~52 where `$saved_context` is loaded:
```php
// Existing: MySQL context
$saved_context = $context_service->get_context( $session_id, $post_id );
// NEW: MEMANTO enhancement (if configured)
$memanto_context = array();
$memanto_client = WP_Agentic_Writer_Memanto_Client::get_instance();
if ( $memanto_client->is_configured() && $memanto_client->is_healthy() ) {
$enhancer = WP_Agentic_Writer_Memanto_Context_Enhancer::get_instance();
$memanto_context = $enhancer->recall_for_context(
$post_id,
get_current_user_id(),
$request_params['latestUserMessage'] ?? ''
);
}
```
Modify `build_working_context()` to include a new section:
```php
// After existing sections, before "Recent saved conversation excerpts"
if ( ! empty( $memanto_context ) ) {
$memory_lines = $this->format_memanto_memories( $memanto_context );
if ( '' !== $memory_lines ) {
$sections[] = "PERSISTENT MEMORY (recalled from MEMANTO):\n" . $memory_lines;
}
}
```
**Key rule:** MEMANTO context is **additive**. It never replaces the existing `BACKEND CONTINUITY CONTEXT` section. It supplements it.
### `includes/class-context-service.php`
Add MEMANTO write-through hooks in key methods:
| Method | Hook Added |
|---|---|
| `save_plan()` | `$enhancer->on_plan_generated( $post_id, $plan )` |
| `update_session_context()` | `$enhancer->on_config_saved()` if config changed |
| `add_message()` | `$enhancer->on_user_message()` for user-role messages |
| `clear_context()` | Optionally clear MEMANTO post agent memories |
### `includes/class-gutenberg-sidebar.php`
Add MEMANTO hooks in key handler methods:
| Handler | Hook Added |
|---|---|
| `handle_chat_request()` | `$enhancer->on_user_message()` after saving to MySQL |
| `handle_generate_plan()` | `$enhancer->on_plan_generated()` after successful plan |
| `handle_execute_article()` | `$enhancer->on_section_written()` per section |
| `handle_refine_block()` | `$enhancer->on_block_refined()` |
| `handle_summarize_context()` | Skip AI call if MEMANTO active — return cached recall instead |
| `handle_detect_intent()` | Skip AI call if MEMANTO active — use regex + MEMANTO context instead |
Add new REST endpoint:
```
POST /wp-agentic-writer/v1/memanto/status
→ Returns: { connected: bool, agent_count: int, memory_count: int, last_recall: string }
```
### `includes/class-autoloader.php`
Register the two new classes:
- `class-memanto-client.php``WP_Agentic_Writer_Memanto_Client`
- `class-memanto-context-enhancer.php``WP_Agentic_Writer_Memanto_Context_Enhancer`
### `assets/js/sidebar.js` (minimal change)
No MEMANTO-specific logic needed. Optional enhancement:
- Show a small "🧠 Memory active" indicator when MEMANTO is connected
- Show "memories recalled: N" in the context audit display
---
## Graceful Degradation Strategy
```
MEMANTO call succeeds?
├── YES → Merge MEMANTO context into working context
└── NO
├── MEMANTO not configured → Use MySQL-only context (default behavior)
├── MEMANTO timeout (>10s) → Log warning, use MySQL-only context
├── MEMANTO 401 (token expired) → Re-activate session, retry once, then fallback
└── MEMANTO 5xx (server error) → Log error, use MySQL-only context
```
User **never** sees an error from MEMANTO. The worst case is they get the same experience as users without MEMANTO.
---
## Implementation Phases
### Phase 1: Core Client (Week 1)
**Goal:** MEMANTO client class + settings UI + connection validation
| Task | File | Details |
|---|---|---|
| Create Memanto Client | `class-memanto-client.php` | All API methods, session token management, error handling |
| Create Context Enhancer shell | `class-memanto-context-enhancer.php` | Skeleton with `is_configured()` check on every method |
| Add settings section | `class-settings-v2.php` | URL field, API key field, enable checkbox, test button |
| Register in autoloader | `class-autoloader.php` | Add both new classes |
| Add REST status endpoint | `class-gutenberg-sidebar.php` | `/memanto/status` endpoint |
**Validation:** Admin can configure MEMANTO URL + Moorcheh key, test connection, see "Connected" status. No functional changes to AI features yet.
### Phase 2: Write-Through Memory (Week 2)
**Goal:** Store memories on every meaningful action
| Task | Hook Point | Memory Type |
|---|---|---|
| Store on user message | `handle_chat_request()` | `instruction` |
| Store on plan generated | `handle_generate_plan()` | `artifact` |
| Store on plan approved | After plan save in frontend | `decision` |
| Store on plan rejected | Plan revision flow | `error` |
| Store on section written | `handle_execute_article()` | `artifact` |
| Store on block refined | `handle_refine_block()` | `instruction` |
| Store on config saved | `update_session_context()` | `preference` |
| Store on session end | Session completed/archived | `context` |
**Validation:** Write an article with MEMANTO enabled. Check MEMANTO API (via recall endpoint) that memories were stored. Verify plugin still works perfectly with MEMANTO disabled.
### Phase 3: Context Enrichment (Week 3)
**Goal:** Recall memories to enrich AI prompts
| Task | File | Details |
|---|---|---|
| Add `recall_for_context()` | `class-memanto-context-enhancer.php` | 3-recall strategy (recent, semantic, preferences) |
| Modify `build_for_task()` | `class-context-builder.php` | Merge recalled memories into working context |
| Add `format_memanto_memories()` | `class-context-builder.php` | Format recalled items as compact prompt text |
| Skip summarize-context when MEMANTO active | `class-gutenberg-sidebar.php` | Return cached recall instead of AI call |
| Skip detect-intent when MEMANTO active | `class-gutenberg-sidebar.php` | Use regex + MEMANTO context instead |
**Validation:** Write an article. Mid-session, close the browser. Reopen the post. Verify AI "remembers" context from recalled memories. Compare AI response quality with/without MEMANTO.
### Phase 4: Cross-Session Restore (Week 4)
**Goal:** Seamless experience when returning to a post after days/weeks
| Task | Details |
|---|---|
| Session restore on load | When post editor opens, recall recent post memories. Build a "restored session" system message. |
| Frontend indicator | Show "🧠 Restored from memory" badge in sidebar |
| User preference carry-over | On new post creation, recall user agent preferences for default post config |
| Session deactivation | On session end, call MEMANTO deactivate to trigger summary generation |
**Validation:** Create an article. Complete 50%. Wait 1 day. Open the post again. Verify AI picks up where it left off without user re-explaining context.
### Phase 5: Polish & Edge Cases (Week 5)
| Task | Details |
|---|---|
| Memory pruning | On session end, summarize verbose raw messages into compact context memories |
| Connection health UI | Real-time status indicator in plugin sidebar header |
| Moorcheh limit warning | When approaching 10K vectors, show admin notice with upgrade link |
| Error logging | Detailed MEMANTO error logging with `wpaw_debug_log` |
| Settings validation | Validate URL format, API key format, connection test before saving |
---
## Testing Strategy
### Unit Tests
| Test | Description |
|---|---|
| `test_memanto_client_not_configured` | Client returns false when settings empty |
| `test_memanto_client_health_check` | Mock `/health` response, verify caching |
| `test_memanto_client_remember` | Mock remember API, verify payload structure |
| `test_memanto_client_recall` | Mock recall API, verify response parsing |
| `test_memanto_client_session_lifecycle` | Activate → remember → recall → deactivate |
| `test_enhancer_graceful_fallback` | MEMANTO returns error, context builder still works |
| `test_context_builder_with_memanto` | Verify MEMANTO context is included in working context |
| `test_context_builder_without_memanto` | Verify no MEMANTO content when not configured |
### Integration Tests
| Test | Description |
|---|---|
| Full article with MEMANTO | Chat → Plan → Write → Refine. Verify memories stored at each step. |
| Full article without MEMANTO | Same flow. Verify no MEMANTO calls made. Plugin works identically. |
| MEMANTO goes down mid-session | Start with MEMANTO active. Simulate timeout. Verify graceful fallback. |
| Cross-session restore | Write 50% of article. Simulate new session. Verify AI context restored. |
| Multi-site with same MEMANTO | Use same MEMANTO instance across 2 sites. Verify agent isolation. |
### Manual Test Checklist
- [ ] Plugin activates with no MEMANTO settings — works normally
- [ ] MEMANTO URL set but Moorcheh key empty — shows "not configured"
- [ ] MEMANTO URL + invalid key — shows "connection error"
- [ ] MEMANTO URL + valid key — shows "connected"
- [ ] Write article with MEMANTO on — AI responses include recalled memory
- [ ] Write article with MEMANTO off — identical to current behavior
- [ ] Disable MEMANTO mid-session — no errors, fallback to MySQL-only
- [ ] Re-enable MEMANTO — picks up from where it left off
- [ ] Check MEMANTO recall endpoint — memories exist for test post
---
## Performance Considerations
| Concern | Mitigation |
|---|---|
| MEMANTO recall adds latency to every AI call | Cache recall results in transient (5-min TTL). Only recall when context builder runs. |
| Session token expires mid-request | Auto-reactivate on 401. Single retry. |
| Too many memories stored | Batch-remember to reduce HTTP calls. Summarize on session end. |
| MEMANTO instance overloaded | 10-second timeout on all calls. Graceful fallback. |
| WordPress transient cache bloat | Use specific key patterns. Clean up on session end. |
---
## Settings UI Specification
### MEMANTO Context Keeper Section
Located in WP Agentic Writer → Settings → MEMANTO tab.
```
┌─────────────────────────────────────────────────────────────────┐
│ MEMANTO Context Keeper │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ☑ Enable MEMANTO integration │
│ │
│ MEMANTO Instance URL │
│ ┌──────────────────────────────────────────────────┐ │
│ │ https://abc123.context.wpagentic.dev │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ Moorcheh API Key │
│ ┌──────────────────────────────────────────────────┐ │
│ │ •••••••••••••••••••••••• │ │
│ └──────────────────────────────────────────────────┘ │
Get a free API key at moorcheh.ai (10K vectors/month) │
│ │
│ Connection Status: 🟢 Connected │
│ Last checked: 2 minutes ago │
│ │
│ [Test Connection] │
│ │
├─────────────────────────────────────────────────────────────────┤
MEMANTO is an optional add-on that provides persistent │
│ memory for your AI writing assistant. Your AI will remember │
│ context across sessions and posts. The plugin works │
│ perfectly without MEMANTO. │
│ │
│ Get MEMANTO at: wpagentic.dev/memanto │
└─────────────────────────────────────────────────────────────────┘
```
---
## Summary
| Aspect | Decision |
|---|---|
| **Scope** | Optional enhancement, not a dependency |
| **New files** | `class-memanto-client.php`, `class-memanto-context-enhancer.php` |
| **Modified files** | `class-context-builder.php`, `class-context-service.php`, `class-gutenberg-sidebar.php`, `class-settings-v2.php`, `class-autoloader.php` |
| **Frontend changes** | Minimal: status indicator only |
| **Fallback behavior** | Full graceful degradation to MySQL-only context |
| **Implementation time** | 5 weeks (1 week per phase) |
| **Testing priority** | Phase 2 (write-through) and Phase 3 (recall) are critical paths |
---
**Document Date:** June 7, 2026
**Status:** Draft — Ready for Phase 1 implementation