|
| 1 | +/* ============================================================ |
| 2 | + MemroOS — Ask MemroOS (LLM) |
| 3 | + Same engine as the Lab's "Ask" surface, regrounded on the |
| 4 | + MemroOS product. Powers the header command palette (⌘K) and |
| 5 | + the below-fold ask band. Grounded, plain, concise answers. |
| 6 | + ============================================================ */ |
| 7 | +(function () { |
| 8 | + 'use strict'; |
| 9 | + |
| 10 | + var CONTEXT = [ |
| 11 | + "You are the assistant for MemroOS, an agentic memory and orchestration platform at memroos.com.", |
| 12 | + "What it is: shared memory and governed orchestration for product, sales, and engineering agents, with an operator console (NOC) for memory, orchestration, skills, dispatch, evals, and trust. It is local-first and self-hosted, not a chatbot wrapper or a passive knowledge base.", |
| 13 | + "The operating loop is five verbs: RETAIN (capture decisions, files, calls, incidents, customer context, and outcomes into a governed memory layer), RETRIEVE (assemble a permission-aware context pack before an agent starts), DISPATCH (send work to local, REST, MCP, or A2A agents with source-backed context), GOVERN (pause, inspect, edit, resume, retry, and roll back long-running work with audit lineage, security, and residual-risk proof), and IMPROVE (promote repeated successful workflows into durable governed skills).", |
| 14 | + "Memory model is multi-tier: vector, graph, episodic, knowledge, and skill surfaces, each with provenance.", |
| 15 | + "Who it serves: product teams (discovery, launch, roadmap, customer context), sales teams (account history, objections, competitive context, follow-up), engineering teams (architecture decisions, incidents, repo patterns, fixes, tests, runbooks), and AI operations teams (agent registry, capability policy, auth posture, security findings, local footprint, eval history).", |
| 16 | + "Proof: ranked first on the public-evidence agentic-memory benchmark with a score of 84.06; the latest validation passed 1079 tests with zero failures; 4.47 GB of local footprint is mapped by permanence, cloud target, and prune safety.", |
| 17 | + "Interop: Claude Code (MCP), Codex, Google ADK, LangGraph, CrewAI, AutoGen, the A2A protocol, and a REST API.", |
| 18 | + "Stance: memory should be visible as retained and consumed context, not hidden infrastructure; dispatch should prove what an agent actually received; governance should show evidence, lineage, and residual risk in language an operator can act on.", |
| 19 | + "Tone: editorial, precise, senior, plain language. No hype, no emoji." |
| 20 | + ].join(" "); |
| 21 | + |
| 22 | + var STYLE = "Answer the visitor's question in their words, grounded ONLY in the context above. Be specific and concrete. 2-4 short paragraphs max, or a short intro plus a tight bullet list. Use **bold** for key terms. If asked about pricing or specifics not in context, say it's best covered on a short working session. Invite them to schedule a working session only when it fits naturally. Never invent client names, numbers, or guarantees."; |
| 23 | + |
| 24 | + var SUGGESTIONS = [ |
| 25 | + "What is agent memory and why does it matter?", |
| 26 | + "How does the retain \u2192 retrieve \u2192 dispatch \u2192 govern \u2192 improve loop work?", |
| 27 | + "How do you keep long-running agent work governable?", |
| 28 | + "How does MemroOS work with Claude Code over MCP?", |
| 29 | + "What do the memory tiers actually store?", |
| 30 | + "How is MemroOS different from a vector database?" |
| 31 | + ]; |
| 32 | + |
| 33 | + function available() { return !!(window.claude && typeof window.claude.complete === 'function'); } |
| 34 | + |
| 35 | + function ask(question) { |
| 36 | + var prompt = CONTEXT + "\n\n" + STYLE + "\n\nVisitor question: \"" + question + "\"\n\nAnswer:"; |
| 37 | + if (!available()) { return Promise.resolve(FALLBACK(question)); } |
| 38 | + return window.claude.complete({ messages: [{ role: 'user', content: prompt }] }) |
| 39 | + .then(function (t) { return (t || '').trim() || FALLBACK(question); }) |
| 40 | + .catch(function () { return FALLBACK(question); }); |
| 41 | + } |
| 42 | + |
| 43 | + function FALLBACK() { |
| 44 | + return "MemroOS gives agents **shared memory** and **governed orchestration**: it retains what your team learns, retrieves the right **context pack** before an agent starts, dispatches work with source-backed context, governs the run with audit lineage, and promotes repeated work into durable **skills**.\n\nThe live answer engine isn't reachable in this view \u2014 but this is exactly the kind of question worth a short **working session**, where we map one workflow where your agents keep rediscovering the same context."; |
| 45 | + } |
| 46 | + |
| 47 | + function esc(s) { return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); } |
| 48 | + function inline(s) { |
| 49 | + return esc(s) |
| 50 | + .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>') |
| 51 | + .replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g, '$1<em>$2</em>'); |
| 52 | + } |
| 53 | + function render(text) { |
| 54 | + var lines = text.replace(/\r/g, '').split('\n'); |
| 55 | + var html = '', list = null; |
| 56 | + lines.forEach(function (ln) { |
| 57 | + var t = ln.trim(); |
| 58 | + if (/^[-*\u2022]\s+/.test(t)) { |
| 59 | + if (!list) { list = ''; } |
| 60 | + list += '<li>' + inline(t.replace(/^[-*\u2022]\s+/, '')) + '</li>'; |
| 61 | + return; |
| 62 | + } |
| 63 | + if (list) { html += '<ul>' + list + '</ul>'; list = null; } |
| 64 | + if (t) html += '<p>' + inline(t) + '</p>'; |
| 65 | + }); |
| 66 | + if (list) html += '<ul>' + list + '</ul>'; |
| 67 | + return html || '<p>' + inline(text) + '</p>'; |
| 68 | + } |
| 69 | + |
| 70 | + function typeOut(el, text, done) { |
| 71 | + var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches || document.body.classList.contains('motion-off'); |
| 72 | + if (reduce) { el.innerHTML = render(text); if (done) done(); return; } |
| 73 | + var i = 0, n = text.length; |
| 74 | + el.innerHTML = '<span class="ask-cursor"></span>'; |
| 75 | + var step = Math.max(1, Math.round(n / 140)); |
| 76 | + function tick() { |
| 77 | + i = Math.min(n, i + step + Math.floor(Math.random() * 2)); |
| 78 | + el.innerHTML = render(text.slice(0, i)) + (i < n ? '<span class="ask-cursor"></span>' : ''); |
| 79 | + var body = el.closest('.ap-body'); |
| 80 | + if (body) body.scrollTop = body.scrollHeight; |
| 81 | + if (i < n) setTimeout(tick, 16); else if (done) done(); |
| 82 | + } |
| 83 | + tick(); |
| 84 | + } |
| 85 | + |
| 86 | + function thinkingHTML() { return '<span class="ask-thinking">Consulting MemroOS<i></i><i></i><i></i></span>'; } |
| 87 | + function bookCTA() { |
| 88 | + return '<div class="ask-followup"><a class="btn btn--solid" href="https://calendar.google.com/calendar/appointments/schedules/AcZssZ2JkygvmpuopbcqA_NAPJZDRp0RfmZGa2x_w_oV_dFm-cYVGEyEYG9vy80meCKZzyianVC6P2vJ" target="_blank" rel="noopener">Schedule a working session <span class="arr">\u2197</span></a><span class="note">Bring one workflow your agents keep relearning.</span></div>'; |
| 89 | + } |
| 90 | + |
| 91 | + function runInto(thread, scroller, question) { |
| 92 | + var q = document.createElement('p'); q.className = 'ask-q'; q.textContent = question; |
| 93 | + var a = document.createElement('div'); a.className = 'ask-a'; a.innerHTML = thinkingHTML(); |
| 94 | + thread.appendChild(q); thread.appendChild(a); |
| 95 | + if (scroller) scroller.scrollTop = scroller.scrollHeight; |
| 96 | + return ask(question).then(function (text) { |
| 97 | + typeOut(a, text, function () { |
| 98 | + var cta = document.createElement('div'); cta.innerHTML = bookCTA(); |
| 99 | + thread.appendChild(cta.firstChild); |
| 100 | + if (scroller) scroller.scrollTop = scroller.scrollHeight; |
| 101 | + }); |
| 102 | + }); |
| 103 | + } |
| 104 | + |
| 105 | + function initOverlay() { |
| 106 | + var triggers = document.querySelectorAll('[data-ask-open]'); |
| 107 | + if (!triggers.length) return; |
| 108 | + var overlay = document.createElement('div'); |
| 109 | + overlay.className = 'ask-overlay'; |
| 110 | + overlay.innerHTML = |
| 111 | + '<div class="ask-panel" role="dialog" aria-modal="true" aria-label="Ask MemroOS">' + |
| 112 | + '<div class="ap-top">' + |
| 113 | + '<img class="ap-mark" src="/landing/assets/memroos-mark.svg" alt="" />' + |
| 114 | + '<input class="ap-input" type="text" placeholder="Ask MemroOS anything\u2026" aria-label="Ask MemroOS" />' + |
| 115 | + '<button class="ap-esc" type="button">ESC</button>' + |
| 116 | + '</div>' + |
| 117 | + '<div class="ap-body">' + |
| 118 | + '<p class="ask-suggest-lab">Try asking</p>' + |
| 119 | + '<div class="ask-suggest"></div>' + |
| 120 | + '<div class="ask-thread"></div>' + |
| 121 | + '</div>' + |
| 122 | + '</div>'; |
| 123 | + document.body.appendChild(overlay); |
| 124 | + |
| 125 | + var input = overlay.querySelector('.ap-input'); |
| 126 | + var suggest = overlay.querySelector('.ask-suggest'); |
| 127 | + var thread = overlay.querySelector('.ask-thread'); |
| 128 | + var body = overlay.querySelector('.ap-body'); |
| 129 | + var busy = false; |
| 130 | + |
| 131 | + SUGGESTIONS.forEach(function (s) { |
| 132 | + var b = document.createElement('button'); b.className = 'ask-chip'; b.type = 'button'; b.textContent = s; |
| 133 | + b.addEventListener('click', function () { input.value = s; submit(); }); |
| 134 | + suggest.appendChild(b); |
| 135 | + }); |
| 136 | + |
| 137 | + function open() { |
| 138 | + overlay.classList.add('open'); |
| 139 | + document.documentElement.style.overflow = 'hidden'; |
| 140 | + setTimeout(function () { input.focus(); }, 40); |
| 141 | + } |
| 142 | + function close() { |
| 143 | + overlay.classList.remove('open'); |
| 144 | + document.documentElement.style.overflow = ''; |
| 145 | + } |
| 146 | + function submit() { |
| 147 | + var q = input.value.trim(); |
| 148 | + if (!q || busy) return; |
| 149 | + busy = true; input.value = ''; |
| 150 | + var lab = overlay.querySelector('.ask-suggest-lab'); |
| 151 | + if (lab) lab.style.display = 'none'; |
| 152 | + suggest.style.display = 'none'; |
| 153 | + runInto(thread, body, q).then(function () { busy = false; input.focus(); }); |
| 154 | + } |
| 155 | + |
| 156 | + triggers.forEach(function (t) { t.addEventListener('click', open); }); |
| 157 | + overlay.querySelector('.ap-esc').addEventListener('click', close); |
| 158 | + overlay.addEventListener('mousedown', function (e) { if (e.target === overlay) close(); }); |
| 159 | + input.addEventListener('keydown', function (e) { if (e.key === 'Enter') submit(); }); |
| 160 | + document.addEventListener('keydown', function (e) { |
| 161 | + if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { |
| 162 | + e.preventDefault(); |
| 163 | + if (overlay.classList.contains('open')) close(); |
| 164 | + else open(); |
| 165 | + } |
| 166 | + if (e.key === 'Escape' && overlay.classList.contains('open')) close(); |
| 167 | + }); |
| 168 | + } |
| 169 | + |
| 170 | + function initBand() { |
| 171 | + var band = document.querySelector('[data-ask-band]'); |
| 172 | + if (!band) return; |
| 173 | + var form = band.querySelector('.ask-form'); |
| 174 | + var input = band.querySelector('input'); |
| 175 | + var btn = band.querySelector('button'); |
| 176 | + var suggest = band.querySelector('.ask-suggest'); |
| 177 | + var thread = band.querySelector('.ask-thread'); |
| 178 | + var busy = false; |
| 179 | + |
| 180 | + SUGGESTIONS.slice(0, 4).forEach(function (s) { |
| 181 | + var b = document.createElement('button'); b.className = 'ask-chip'; b.type = 'button'; b.textContent = s; |
| 182 | + b.addEventListener('click', function () { input.value = s; submit(); }); |
| 183 | + suggest.appendChild(b); |
| 184 | + }); |
| 185 | + |
| 186 | + function submit() { |
| 187 | + var q = input.value.trim(); |
| 188 | + if (!q || busy) return; |
| 189 | + busy = true; btn.disabled = true; input.value = ''; |
| 190 | + runInto(thread, null, q).then(function () { busy = false; btn.disabled = false; }); |
| 191 | + } |
| 192 | + form.addEventListener('submit', function (e) { e.preventDefault(); submit(); }); |
| 193 | + } |
| 194 | + |
| 195 | + function boot() { initOverlay(); initBand(); } |
| 196 | + if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); |
| 197 | + else boot(); |
| 198 | +})(); |
0 commit comments