Good. Now let me add the new API actions for session CRUD and memory CRUD. Let me find the right place to insert them:


TodoWrite

Make stripQuotedContent() public static in ThreadAnalyzer.php

Making stripQuotedContent() public static

Backend: multi-thread context + token budget + stripped content + agents + auto-memory in ai_chat

Implementing multi-thread context and token budget in api.php

Backend: new API actions (sessions CRUD, contact memory CRUD)

Frontend: provider/model selector + agent selector + constants in app.js

Adding provider/model/agent selectors to frontend

Frontend: context builder (search, thread picker, cart) in app.js

Frontend: session management (save/load/history) in app.js

Frontend: contact memory UI in app.js

HTML: update index.php with new UI sections

Test end-to-end: multi-thread, agents, sessions, memory


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Make stripQuotedContent() public static in ThreadAnalyzer.php

Making stripQuotedContent() public static

Backend: multi-thread context + token budget + stripped content in api.php

Implementing multi-thread context and token budget in api.php

Backend: new API actions (sessions CRUD, contact memory CRUD)

Backend: agent presets + auto-memory extraction in api.php

Adding agent presets and auto-memory extraction

Frontend: provider/model selector + agent selector + constants in app.js

Adding provider/model/agent selectors to frontend

Frontend: context builder (search, thread picker, cart) in app.js

Frontend: session management (save/load/history) in app.js

Frontend: contact memory UI in app.js

HTML: update index.php with new UI sections

Test end-to-end: multi-thread, agents, sessions, memory

Backend: multi-thread context + token budget + stripped content + agents + auto-memory in ai_chat

Frontend: contact memory UI in app.js


Now add the new API actions before the `default` case:


  4155→
  4156→            $enrichment = new DataEnrichment();
  4157→
  4158→            // Queue or immediately enrich based on config
  4159→            if (defined('AI_AUTO_ENRICH') && AI_AUTO_ENRICH) {
  4160→                if ($entityType === 'contact') {
  4161→                    $result = $enrichment->enrichContact($entityId, null, $sources);
  4162→                } else {
  4163→                    $result = $enrichment->enrichCompany($entityId, $sources);
  4164→                }
  4165→            } else {
  4166→                $result = $enrichment->queueEnrichment($entityType, $entityId, $sources, $priority);
  4167→            }
  4168→
  4169→            jsonResponse($result);
  4170→            break;
  4171→
  4172→        case 'enrichment_status':
  4173→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4174→
  4175→            $entityType = $_GET['entity_type'] ?? '';
  4176→            $entityId = $_GET['entity_id'] ?? '';
  4177→
  4178→            if (!$entityType || !$entityId) {
  4179→                jsonError('entity_type and entity_id required');
  4180→            }
  4181→
  4182→            $enrichment = new DataEnrichment();
  4183→            $status = $enrichment->getEnrichmentStatus($entityType, $entityId);
  4184→            jsonResponse([

            $enrichment = new DataEnrichment();

            // Queue or immediately enrich based on config
            if (defined('AI_AUTO_ENRICH') && AI_AUTO_ENRICH) {
                if ($entityType === 'contact') {
                    $result = $enrichment->enrichContact($entityId, null, $sources);
                } else {
                    $result = $enrichment->enrichCompany($entityId, $sources);
                }
            } else {
                $result = $enrichment->queueEnrichment($entityType, $entityId, $sources, $priority);
            }

            jsonResponse($result);
            break;

        case 'enrichment_status':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $entityType = $_GET['entity_type'] ?? '';
            $entityId = $_GET['entity_id'] ?? '';

            if (!$entityType || !$entityId) {
                jsonError('entity_type and entity_id required');
            }

            $enrichment = new DataEnrichment();
            $status = $enrichment->getEnrichmentStatus($entityType, $entityId);
            jsonResponse([


  4193→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4194→
  4195→            $enrichment = new DataEnrichment();
  4196→            $queueStatus = $enrichment->getQueueStatus();
  4197→            jsonResponse([
  4198→                'success' => true,
  4199→                'queue' => $queueStatus
  4200→            ]);
  4201→            break;
  4202→
  4203→        case 'process_enrichment_queue':
  4204→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4205→
  4206→            $batchSize = (int) ($_POST['batch_size'] ?? 10);
  4207→
  4208→            $enrichment = new DataEnrichment();
  4209→            $results = $enrichment->processQueue($batchSize);
  4210→            jsonResponse([
  4211→                'success' => true,
  4212→                'results' => $results
  4213→            ]);
  4214→            break;
  4215→
  4216→        case 'enrichment_logs':
  4217→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4218→
  4219→            $entityType = $_GET['entity_type'] ?? null;
  4220→            $entityId = $_GET['entity_id'] ?? null;
  4221→            $limit = (int) ($_GET['limit'] ?? 50);
  4222→

            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $enrichment = new DataEnrichment();
            $queueStatus = $enrichment->getQueueStatus();
            jsonResponse([
                'success' => true,
                'queue' => $queueStatus
            ]);
            break;

        case 'process_enrichment_queue':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $batchSize = (int) ($_POST['batch_size'] ?? 10);

            $enrichment = new DataEnrichment();
            $results = $enrichment->processQueue($batchSize);
            jsonResponse([
                'success' => true,
                'results' => $results
            ]);
            break;

        case 'enrichment_logs':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $entityType = $_GET['entity_type'] ?? null;
            $entityId = $_GET['entity_id'] ?? null;
            $limit = (int) ($_GET['limit'] ?? 50);


  4240→            break;
  4241→
  4242→        case 'contact_enrichment':
  4243→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4244→
  4245→            $contactId = $_GET['contact_id'] ?? '';
  4246→            if (!$contactId) {
  4247→                jsonError('contact_id required');
  4248→            }
  4249→
  4250→            $enrichment = new DataEnrichment();
  4251→            $data = $enrichment->getContactEnrichment($contactId);
  4252→            jsonResponse([
  4253→                'success' => true,
  4254→                'contact_id' => $contactId,
  4255→                'enrichment' => $data
  4256→            ]);
  4257→            break;
  4258→
  4259→        case 'company_enrichment':
  4260→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4261→
  4262→            $domain = $_GET['domain'] ?? '';
  4263→            if (!$domain) {
  4264→                jsonError('domain required');
  4265→            }
  4266→
  4267→            $enrichment = new DataEnrichment();
  4268→            $data = $enrichment->getCompanyEnrichment($domain);
  4269→            jsonResponse([

            break;

        case 'contact_enrichment':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $contactId = $_GET['contact_id'] ?? '';
            if (!$contactId) {
                jsonError('contact_id required');
            }

            $enrichment = new DataEnrichment();
            $data = $enrichment->getContactEnrichment($contactId);
            jsonResponse([
                'success' => true,
                'contact_id' => $contactId,
                'enrichment' => $data
            ]);
            break;

        case 'company_enrichment':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $domain = $_GET['domain'] ?? '';
            if (!$domain) {
                jsonError('domain required');
            }

            $enrichment = new DataEnrichment();
            $data = $enrichment->getCompanyEnrichment($domain);
            jsonResponse([


  4270→                'success' => true,
  4271→                'domain' => $domain,
  4272→                'enrichment' => $data
  4273→            ]);
  4274→            break;
  4275→
  4276→        case 'apollo_status':
  4277→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4278→
  4279→            $enrichment = new DataEnrichment();
  4280→            $status = $enrichment->getApolloStatus();
  4281→            jsonResponse([
  4282→                'success' => true,
  4283→                'apollo' => $status
  4284→            ]);
  4285→            break;
  4286→
  4287→        case 'puppeteer_status':
  4288→            require_once dirname(__DIR__) . '/src/DataEnrichment.php';
  4289→
  4290→            $enrichment = new DataEnrichment();
  4291→            $status = $enrichment->getPuppeteerStatus();
  4292→            jsonResponse([
  4293→                'success' => true,
  4294→                'puppeteer' => $status
  4295→            ]);
  4296→            break;
  4297→
  4298→        case 'enrichment_sources':
  4299→            // Return configured enrichment sources

                'success' => true,
                'domain' => $domain,
                'enrichment' => $data
            ]);
            break;

        case 'apollo_status':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $enrichment = new DataEnrichment();
            $status = $enrichment->getApolloStatus();
            jsonResponse([
                'success' => true,
                'apollo' => $status
            ]);
            break;

        case 'puppeteer_status':
            require_once dirname(__DIR__) . '/src/DataEnrichment.php';

            $enrichment = new DataEnrichment();
            $status = $enrichment->getPuppeteerStatus();
            jsonResponse([
                'success' => true,
                'puppeteer' => $status
            ]);
            break;

        case 'enrichment_sources':
            // Return configured enrichment sources


  4298→        case 'enrichment_sources':
  4299→            // Return configured enrichment sources
  4300→            $sources = defined('ENRICHMENT_SOURCES') ? ENRICHMENT_SOURCES : [];
  4301→            jsonResponse([
  4302→                'success' => true,
  4303→                'sources' => $sources
  4304→            ]);
  4305→            break;
  4306→
  4307→        // ==========================================
  4308→        // Default
  4309→        // ==========================================
  4310→        default:
  4311→            jsonError('Unknown action: ' . $action, 400);
  4312→    }
  4313→
  4314→} catch (Exception $e) {
  4315→    jsonError('Server error: ' . $e->getMessage(), 500);
  4316→}
  4317→

        case 'enrichment_sources':
            // Return configured enrichment sources
            $sources = defined('ENRICHMENT_SOURCES') ? ENRICHMENT_SOURCES : [];
            jsonResponse([
                'success' => true,
                'sources' => $sources
            ]);
            break;

        // ==========================================
        // Default
        // ==========================================
        default:
            jsonError('Unknown action: ' . $action, 400);
    }

} catch (Exception $e) {
    jsonError('Server error: ' . $e->getMessage(), 500);
}


Edit

        // ==========================================
        // AI Chat Sessions - List recent sessions
        // ==========================================
        case 'ai_chat_sessions':
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $limit = (int)($_GET['limit'] ?? 20);
            $sessions = $ctxMongo->findAll('ai_chat_sessions', [], [
                'sort' => ['updated_at' => -1],
                'limit' => $limit,
            ]);
            // Strip full messages from list view (just return metadata)
            $sessionList = array_map(function($s) {
                return [
                    'session_id' => $s['session_id'] ?? '',
                    'title' => $s['title'] ?? 'Untitled',
                    'agent' => $s['agent'] ?? 'general',
                    'provider' => $s['provider'] ?? '',
                    'model' => $s['model'] ?? '',
                    'contact_name' => $s['contact_name'] ?? null,
                    'contact_id' => $s['contact_id'] ?? null,
                    'context_thread_ids' => $s['context_thread_ids'] ?? [],
                    'message_count' => count($s['messages'] ?? []),
                    'created_at' => $s['created_at'] ?? '',
                    'updated_at' => $s['updated_at'] ?? '',
                ];
            }, $sessions);
            jsonResponse(['success' => true, 'sessions' => $sessionList]);
            break;

        // ==========================================
        // AI Chat Session - Load a specific session
        // ==========================================
        case 'ai_chat_session':
            $sessionId = $_GET['session_id'] ?? '';
            if (!$sessionId) jsonError('session_id required');
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $session = $ctxMongo->findOne('ai_chat_sessions', ['session_id' => $sessionId]);
            if (!$session) jsonError('Session not found', 404);
            jsonResponse(['success' => true, 'session' => [
                'session_id' => $session['session_id'],
                'title' => $session['title'] ?? 'Untitled',
                'agent' => $session['agent'] ?? 'general',
                'provider' => $session['provider'] ?? '',
                'model' => $session['model'] ?? '',
                'contact_id' => $session['contact_id'] ?? null,
                'contact_name' => $session['contact_name'] ?? null,
                'context_thread_ids' => $session['context_thread_ids'] ?? [],
                'messages' => $session['messages'] ?? [],
                'created_at' => $session['created_at'] ?? '',
                'updated_at' => $session['updated_at'] ?? '',
            ]]);
            break;

        // ==========================================
        // AI Chat Session Delete
        // ==========================================
        case 'ai_chat_session_delete':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('POST required', 405);
            $jsonData = json_decode(file_get_contents('php://input'), true) ?? [];
            $sessionId = $jsonData['session_id'] ?? '';
            if (!$sessionId) jsonError('session_id required');
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $deleted = $ctxMongo->delete('ai_chat_sessions', ['session_id' => $sessionId]);
            jsonResponse(['success' => true, 'deleted' => $deleted]);
            break;

        // ==========================================
        // AI Contact Memories - Get memories for a contact
        // ==========================================
        case 'ai_contact_memories':
            $contactId = (int)($_GET['contact_id'] ?? 0);
            if (!$contactId) jsonError('contact_id required');
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $memDoc = $ctxMongo->findOne('ai_contact_memory', ['contact_id' => $contactId]);
            jsonResponse([
                'success' => true,
                'contact_id' => $contactId,
                'memories' => $memDoc ? ($memDoc['memories'] ?? []) : [],
            ]);
            break;

        // ==========================================
        // AI Contact Memory Add - Manually add a memory fact
        // ==========================================
        case 'ai_contact_memory_add':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('POST required', 405);
            $jsonData = json_decode(file_get_contents('php://input'), true) ?? [];
            $contactId = (int)($jsonData['contact_id'] ?? 0);
            $fact = trim($jsonData['fact'] ?? '');
            if (!$contactId || !$fact) jsonError('contact_id and fact required');
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $existing = $ctxMongo->findOne('ai_contact_memory', ['contact_id' => $contactId]);
            $memories = $existing ? ($existing['memories'] ?? []) : [];
            $newMem = [
                'id' => uniqid('mem_', true),
                'fact' => $fact,
                'source' => 'manual',
                'created_at' => date('Y-m-d H:i:s'),
            ];
            $memories[] = $newMem;
            $ctxMongo->insertOrUpdate('ai_contact_memory', [
                'contact_id' => $contactId,
                'memories' => $memories,
                'updated_at' => date('Y-m-d H:i:s'),
            ], ['contact_id']);
            jsonResponse(['success' => true, 'memory' => $newMem]);
            break;

        // ==========================================
        // AI Contact Memory Delete - Remove a memory fact
        // ==========================================
        case 'ai_contact_memory_delete':
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') jsonError('POST required', 405);
            $jsonData = json_decode(file_get_contents('php://input'), true) ?? [];
            $contactId = (int)($jsonData['contact_id'] ?? 0);
            $memoryId = $jsonData['memory_id'] ?? '';
            if (!$contactId || !$memoryId) jsonError('contact_id and memory_id required');
            $ctxMongo = \EmailIntelligence\MongoDatabase::getInstance();
            $existing = $ctxMongo->findOne('ai_contact_memory', ['contact_id' => $contactId]);
            if ($existing && !empty($existing['memories'])) {
                $memories = array_values(array_filter($existing['memories'], function($m) use ($memoryId) {
                    return ($m['id'] ?? '') !== $memoryId;
                }));
                $ctxMongo->insertOrUpdate('ai_contact_memory', [
                    'contact_id' => $contactId,
                    'memories' => $memories,
                    'updated_at' => date('Y-m-d H:i:s'),
                ], ['contact_id']);
            }
            jsonResponse(['success' => true]);
            break;

        // ==========================================
        // Default
        // ==========================================
        default:
            jsonError('Unknown action: ' . $action, 400);
    }