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:
@@ -6,24 +6,24 @@
|
||||
* @var array $view_data Prepared view data from class-settings-v2.php
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
}
|
||||
|
||||
// Extract view data for easier access
|
||||
extract( $view_data );
|
||||
extract($view_data);
|
||||
?>
|
||||
<div class="wrap wpaw-settings-v2-wrap">
|
||||
<!-- Agentic IDE Split View Layout -->
|
||||
<div class="wpaw-ide-container d-flex">
|
||||
|
||||
|
||||
<!-- Left Sidebar: Settings Navigation -->
|
||||
<div class="wpaw-sidebar-nav flex-shrink-0">
|
||||
<!-- Header inside Sidebar -->
|
||||
<div class="wpaw-sidebar-header p-3 mb-2 border-bottom border-dark">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<img src="<?php echo esc_url( WP_AGENTIC_WRITER_URL . 'assets/img/icon.svg' ); ?>"
|
||||
alt="WP Agentic Writer"
|
||||
<img src="<?php echo esc_url(WP_AGENTIC_WRITER_URL . "assets/img/icon.svg"); ?>"
|
||||
alt="WP Agentic Writer"
|
||||
style="width: 24px; height: 24px; filter: invert(1)">
|
||||
<h1 class="h6 mb-0 text-white fw-bold">Agentic Writer</h1>
|
||||
</div>
|
||||
@@ -39,19 +39,25 @@ extract( $view_data );
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active w-100 text-start d-flex align-items-center gap-2" id="general-tab" data-bs-toggle="pill" data-bs-target="#general" type="button" role="tab" aria-controls="general" aria-selected="true">
|
||||
<i class="bi bi-sliders"></i>
|
||||
<?php esc_html_e( 'General', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("General", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link w-100 text-start d-flex align-items-center gap-2" id="models-tab" data-bs-toggle="pill" data-bs-target="#models" type="button" role="tab" aria-controls="models" aria-selected="false">
|
||||
<i class="bi bi-stars"></i>
|
||||
<?php esc_html_e( 'AI Models', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("AI Models", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link w-100 text-start d-flex align-items-center gap-2" id="local-backend-tab" data-bs-toggle="pill" data-bs-target="#local-backend" type="button" role="tab" aria-controls="local-backend" aria-selected="false">
|
||||
<i class="bi bi-house-fill"></i>
|
||||
<?php esc_html_e( 'Local Backend', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("Local Backend", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link w-100 text-start d-flex align-items-center gap-2" id="memanto-tab" data-bs-toggle="pill" data-bs-target="#memanto" type="button" role="tab" aria-controls="memanto" aria-selected="false">
|
||||
<i class="bi bi-cpu"></i>
|
||||
<?php esc_html_e("MEMANTO", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -59,13 +65,13 @@ extract( $view_data );
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link w-100 text-start d-flex align-items-center gap-2" id="cost-log-tab" data-bs-toggle="pill" data-bs-target="#cost-log" type="button" role="tab" aria-controls="cost-log" aria-selected="false">
|
||||
<i class="bi bi-graph-up"></i>
|
||||
<?php esc_html_e( 'OpenRouter Cost Log', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("OpenRouter Cost Log", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link w-100 text-start d-flex align-items-center gap-2" id="guide-tab" data-bs-toggle="pill" data-bs-target="#guide" type="button" role="tab" aria-controls="guide" aria-selected="false">
|
||||
<i class="bi bi-book"></i>
|
||||
<?php esc_html_e( 'Model Guide', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("Model Guide", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -75,7 +81,7 @@ extract( $view_data );
|
||||
<!-- Right Content Pane: Settings Forms -->
|
||||
<div class="wpaw-content-pane flex-grow-1 d-flex flex-column h-100">
|
||||
<form method="post" action="options.php" id="wpaw-settings-form" class="h-100 d-flex flex-column">
|
||||
<?php settings_fields( 'wp_agentic_writer_settings' ); ?>
|
||||
<?php settings_fields("wp_agentic_writer_settings"); ?>
|
||||
|
||||
<!-- Workflow Pipeline Progress -->
|
||||
<div class="wpaw-workflow-progress wpaw-workflow-compact mb-4" id="wpaw-workflow-display">
|
||||
@@ -140,7 +146,7 @@ extract( $view_data );
|
||||
<h2 class="h4 text-white m-0">General Settings</h2>
|
||||
<p class="text-secondary small mt-1">Configure global API keys, budget, and content parameters.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . 'views/settings/tab-general.php'; ?>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-general.php"; ?>
|
||||
</div>
|
||||
|
||||
<!-- Models Tab -->
|
||||
@@ -149,7 +155,7 @@ extract( $view_data );
|
||||
<h2 class="h4 text-white m-0">AI Models</h2>
|
||||
<p class="text-secondary small mt-1">Select logic engines for different stages of the writing pipeline.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . 'views/settings/tab-models.php'; ?>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-models.php"; ?>
|
||||
</div>
|
||||
|
||||
<!-- Local Backend Tab -->
|
||||
@@ -158,16 +164,25 @@ extract( $view_data );
|
||||
<h2 class="h4 text-white m-0">Local Backend</h2>
|
||||
<p class="text-secondary small mt-1">Configure connections to local LM Studio or Ollama instances.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . 'views/settings/tab-local-backend.php'; ?>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-local-backend.php"; ?>
|
||||
</div>
|
||||
|
||||
<!-- Cost Log Tab -->
|
||||
<!-- MEMANTO Tab -->
|
||||
<div class="tab-pane fade" id="memanto" role="tabpanel" aria-labelledby="memanto-tab">
|
||||
<div class="mb-4 pb-3 border-bottom border-dark">
|
||||
<h2 class="h4 text-white m-0">MEMANTO Context Keeper</h2>
|
||||
<p class="text-secondary small mt-1">Optional persistent memory for your AI writing assistant. The plugin works perfectly without it.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-memanto.php"; ?>
|
||||
</div>
|
||||
|
||||
<!-- Cost Log Tab -->
|
||||
<div class="tab-pane fade" id="cost-log" role="tabpanel" aria-labelledby="cost-log-tab">
|
||||
<div class="mb-4 pb-3 border-bottom border-dark">
|
||||
<h2 class="h4 text-white m-0">OpenRouter Cost Analytics</h2>
|
||||
<p class="text-secondary small mt-1">Track API token usage and expenses across all generations.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . 'views/settings/tab-cost-log.php'; ?>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-cost-log.php"; ?>
|
||||
</div>
|
||||
|
||||
<!-- Guide Tab -->
|
||||
@@ -176,7 +191,7 @@ extract( $view_data );
|
||||
<h2 class="h4 text-white m-0">Provider Documentation</h2>
|
||||
<p class="text-secondary small mt-1">Reference materials for selecting the right model constraints.</p>
|
||||
</div>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . 'views/settings/tab-guide.php'; ?>
|
||||
<?php include WP_AGENTIC_WRITER_DIR . "views/settings/tab-guide.php"; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,18 +200,28 @@ extract( $view_data );
|
||||
<div class="wpaw-save-bar p-3 border-top border-dark d-flex justify-content-between align-items-center bg-transparent mt-auto sticky-bottom">
|
||||
<div class="text-secondary small d-flex align-items-center gap-2">
|
||||
<span class="dashicons dashicons-plugin text-primary"></span>
|
||||
<?php printf( esc_html__( 'v%s', 'wp-agentic-writer' ), esc_html( WP_AGENTIC_WRITER_VERSION ) ); ?>
|
||||
<?php printf(
|
||||
esc_html__("v%s", "wp-agentic-writer"),
|
||||
esc_html(WP_AGENTIC_WRITER_VERSION),
|
||||
); ?>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="wpaw-reset-settings">
|
||||
<?php esc_html_e( 'Reset Defaults', 'wp-agentic-writer' ); ?>
|
||||
<?php esc_html_e("Reset Defaults", "wp-agentic-writer"); ?>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary px-4 fw-semibold" id="wpaw-save-settings">
|
||||
<?php
|
||||
$is_mac = isset( $_SERVER['HTTP_USER_AGENT'] ) && strpos( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), 'Mac OS' ) !== false;
|
||||
$cmd_key = $is_mac ? '⌘' : 'Ctrl';
|
||||
?>
|
||||
<?php esc_html_e( 'Save Settings', 'wp-agentic-writer' ); ?> <kbd class="ms-1 bg-dark text-white border-0 py-0"><?php echo esc_html( $cmd_key ); ?>+S</kbd>
|
||||
$is_mac =
|
||||
isset($_SERVER["HTTP_USER_AGENT"]) &&
|
||||
strpos(wp_unslash($_SERVER["HTTP_USER_AGENT"]), "Mac OS") !== false;
|
||||
$cmd_key = $is_mac ? "⌘" : "Ctrl";
|
||||
?>
|
||||
<?php esc_html_e(
|
||||
"Save Settings",
|
||||
"wp-agentic-writer",
|
||||
); ?> <kbd class="ms-1 bg-dark text-white border-0 py-0"><?php echo esc_html(
|
||||
$cmd_key,
|
||||
); ?>+S</kbd>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,7 +235,10 @@ extract( $view_data );
|
||||
<div id="wpaw-toast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<span class="me-2">✨</span>
|
||||
<strong class="me-auto"><?php esc_html_e( 'WP Agentic Writer', 'wp-agentic-writer' ); ?></strong>
|
||||
<strong class="me-auto"><?php esc_html_e(
|
||||
"WP Agentic Writer",
|
||||
"wp-agentic-writer",
|
||||
); ?></strong>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="wpaw-toast-message"></div>
|
||||
|
||||
Reference in New Issue
Block a user