Skip to content

Commit b40eb1f

Browse files
committed
feat: Context Memory — SQLite FTS5 workspace intelligence with {{Memory:}} tag
- New js/context-memory.js: SQLite FTS5 search engine with heading-aware chunking - Three storage modes: browser-only, disk workspace, external memory (IndexedDB) - {{Memory: Name: id}} tag for defining external context sources - Use: field in AI/Think/Agent tags for multi-source context retrieval - Memory card with amber accent: Folder/Files/Rebuild buttons + stats - Context injection into buildPrompt, generateAndReview, generateAgentFlow - 📚 Memory button in AI Tags overflow dropdown - Reuses existing sql.js WASM (zero bundle size increase) - DOMPurify: allow data-memory-name, data-step attributes - MEMORY_DB key in storage-keys.js - 30 Playwright tests (context-memory.spec.js) - Updated README, Feature Showcase template, changelog
1 parent 8d386d5 commit b40eb1f

13 files changed

Lines changed: 1376 additions & 16 deletions

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@
3434
| **Desktop** | Native app via Neutralino.js with system tray and offline support |
3535
| **Code Execution** | 6 languages in-browser: Bash ([just-bash](https://justbash.dev/)), Math (Nerdamer), Python ([Pyodide](https://pyodide.org/)), HTML (sandboxed iframe, `html-autorun` for widgets/quizzes), JavaScript (sandboxed iframe), SQL ([sql.js](https://sql.js.org/) SQLite) · 25+ compiled languages via [Judge0 CE](https://ce.judge0.com): C, C++, Rust, Go, Java, TypeScript, Kotlin, Scala, Ruby, Swift, Haskell, Dart, C#, and more |
3636
| **Security** | Content Security Policy (CSP), SRI integrity hashes, XSS sanitization (DOMPurify), ReDoS protection, Firestore write-token ownership, API keys via HTTP headers, postMessage origin validation, 8-char passphrase minimum, sandboxed code execution |
37-
| **AI Document Tags** | `{{AI:}}` text generation, `{{Think:}}` deep reasoning, `{{Image:}}` image generation (Gemini Imagen) — per-card model selector, concurrent block operations |
37+
| **AI Document Tags** | `{{AI:}}` text generation, `{{Think:}}` deep reasoning, `{{Image:}}` image generation (Gemini Imagen), `{{Memory:}}` context attachment (workspace files + external folders via SQLite FTS5, `Use:` field for multi-source retrieval) — per-card model selector, concurrent block operations |
3838
| **🔌 API Calls** | `{{API:}}` REST API integration — GET/POST/PUT/DELETE methods, custom headers, JSON body, response stored in `$(api_varName)` variables; inline review panel; toolbar GET/POST buttons |
3939
| **🔗 Agent Flow** | `{{Agent:}}` multi-step pipeline — define Step 1/2/3, chain outputs, per-card model + search provider selector, live step status indicators (⏳/✅/❌), review combined output |
4040
| **🔍 Web Search** | Toggle web search for AI — DuckDuckGo (free), Brave Search, Serper.dev; search results injected into LLM context; source citations in responses; per-agent-card search provider selector |
4141
| **🐧 Linux Terminal** | `{{Linux:}}` tag — two modes: (1) Terminal mode opens full Debian Linux ([WebVM](https://webvm.io)) in new window with `Packages:` field; (2) Compile & Run mode (`Language:` + `Script:`) compiles/executes 25+ languages (C++, Rust, Go, Java, Python, TypeScript, Kotlin, Scala…) via [Judge0 CE](https://ce.judge0.com) with inline output, execution time & memory stats |
4242
| **❓ Help Mode** | Interactive learning mode — click ❓ Help to highlight all buttons, click any button for description + keyboard shortcut + animated demo video; 50% screen demo panel with fullscreen expand; 16 dedicated demo videos mapped to every toolbar button |
4343
| **Extras** | Auto-save (localStorage + cloud), table of contents, image paste, 103+ templates (11 categories: AI, Agents, Coding, Creative, Documentation, Maths, PPT, Project, Quiz, Tables, Technical), template variable substitution (`$(varName)` with auto-detect), table spreadsheet tools (sort, filter, stats, chart, add row/col, inline cell edit, CSV/MD export), content statistics, modular codebase (13+ JS modules), fully responsive mobile UI with scrollable Quick Action Bar (Files, Search, TOC, Share, Copy, Tools, AI, Model, Upload, Help) and formatting toolbar, multi-file workspace sidebar, disk-backed folder workspace (File System Access API — open folder, save `.md` files to disk, refresh from disk, auto-reconnect), compact header mode with collapsible Tools dropdown (Presentation, Zen, Word Wrap, Focus, Voice, Dark Mode, Preview Theme) |
44-
| **Dev Tooling** | ESLint + Prettier (lint, format:check), Playwright test suite — 111 tests across smoke, feature, integration, dev, performance, and QA categories (import, export, share, view-mode, editor, email-to-self, secure share, startup timing, export integrity, persistence, module loading, disk workspace, build validation, load-time, accessibility), pre-commit changelog enforcement, GitHub Actions CI |
44+
| **Dev Tooling** | ESLint + Prettier (lint, format:check), Playwright test suite — 141 tests across smoke, feature, integration, dev, performance, and QA categories (import, export, share, view-mode, editor, email-to-self, secure share, startup timing, export integrity, persistence, module loading, disk workspace, context memory, build validation, load-time, accessibility), pre-commit changelog enforcement, GitHub Actions CI |
4545

4646
## 🤖 AI Assistant
4747

@@ -373,6 +373,7 @@ TextAgent has undergone significant evolution since its inception. What started
373373

374374
| Date | Feature / Update |
375375
|------|-----------------|
376+
| **2026-03-10** | 📚 **Context Memory** — new `{{Memory:}}` tag and `Use:` field for workspace intelligence; `js/context-memory.js` module with SQLite FTS5 full-text search (heading-aware chunking, ~1500 chars/chunk); three storage modes: browser-only (IndexedDB blob), disk workspace (`.textagent/memory.db`), external memory (IndexedDB blob); `Use: workspace, my-docs` in AI/Think/Agent tags auto-retrieves relevant context from indexed files; amber-accented Memory card with Folder/Files/Rebuild buttons + stats display; reuses existing sql.js WASM (zero bundle size increase); 30 new Playwright tests (141 total) |
376377
| **2026-03-10** | 🗂️ **Action Modal & Disk UI Polish** — replaced native `confirm()` and inline rename with unified `showActionModal()` for rename (input field, auto-selects filename), duplicate (blue confirmation), and delete (red destructive); header-only disk controls (refresh ↻, disconnect ✕) replacing footer bar; clickable folder name opens folder picker; same-name rename guard with toast feedback; duplicate tree auto-refresh after disk write; merged CI changelog check into deploy workflow (3→2 workflow runs per push); 10 new Playwright tests (112 total) |
377378
| **2026-03-10** | 📂 **Disk-Backed Workspace** — new folder storage mode via File System Access API; "Open Folder" button in sidebar header; `.md` files read/written directly to disk; `.textagent/workspace.json` manifest; debounced autosave to disk ("💾 Saved to disk" indicator); refresh from disk for external changes; disconnect to revert to localStorage; auto-reconnect on reload via IndexedDB-stored handles; Chromium-only (hidden in unsupported browsers); 22 new Playwright tests |
378379
| **2026-03-10** | 🧹 **Clear Text Buttons** — new "Clear" group in formatting toolbar with Clear All (eraser icon) and Clear Selection (backspace icon); custom in-app confirmation modal with smooth animation (replaces flickering native `confirm()`); both undoable via Ctrl+Z; toast feedback; red-accented styling with dark/light theme; Help mode entries |
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Context Memory — SQLite FTS5 Workspace Intelligence
2+
3+
- New `js/context-memory.js` module: SQLite FTS5-powered search engine for local context
4+
- Heading-aware chunking (H1/H2/H3 hierarchy, ~1500 char max per chunk)
5+
- Three storage modes: browser-only (IndexedDB blob), disk workspace (`.textagent/memory.db`), external memory (IndexedDB blob keyed by name)
6+
- Incremental indexing: tracks file modification times, re-indexes only changed files
7+
- Reuses existing `sql.js` WASM from `exec-sandbox.js` — no new bundle size increase
8+
- `{{Memory: Name: my-docs}}` tag for defining external context sources
9+
- `Use: workspace, my-docs` field in AI/Think/Agent tags for multi-source context retrieval
10+
- Memory card renders with amber/orange accent: 📂 Folder, 📄 Files, 🔄 Rebuild buttons + stats display
11+
- Use: hint badge on AI/Think/Agent cards shows active memory sources
12+
- Context injection: memory search results injected into `buildPrompt()`, `generateAndReview()`, and `generateAgentFlow()` per-step
13+
- 30 Playwright tests covering module API, tag parsing, card rendering, DOMPurify allowlist
14+
15+
---
16+
17+
## Summary
18+
Added `{{Memory:}}` tag and `Use:` field for workspace intelligence. AI tags can now leverage indexed local context from workspace files or external folders via SQLite FTS5 full-text search. Three persistence modes ensure memory survives page reloads. Reuses existing sql.js — zero additional bundle size.
19+
20+
---
21+
22+
## Files Changed (9 total)
23+
24+
| File | Lines Changed | Type |
25+
|------|:---:|------|
26+
| `js/context-memory.js` | +447 | New module: FTS5 engine, chunking, 3 storage modes |
27+
| `js/exec-sandbox.js` | +4 | Expose `getSqlJs` on `M._exec` |
28+
| `js/ai-docgen.js` | +95 −10 | Memory tag parsing, Use: field, Memory card HTML, bindings |
29+
| `js/ai-docgen-generate.js` | +35 −3 | Memory context injection into prompts |
30+
| `js/renderer.js` | +1 −1 | DOMPurify: allow `data-memory-name`, `data-step` |
31+
| `js/storage-keys.js` | +3 | `MEMORY_DB` key |
32+
| `src/main.js` | +3 | Import `context-memory.js` in Phase 3b-ext |
33+
| `css/ai-docgen.css` | +90 | Amber Memory card styles, Use: badge |
34+
| `tests/feature/context-memory.spec.js` | +340 | 30 Playwright tests |

css/ai-docgen.css

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,4 +1861,94 @@
18611861

18621862
[data-theme="light"] .fmt-group-dropdown .fmt-btn:hover {
18631863
background: rgba(0, 0, 0, 0.04);
1864+
}
1865+
1866+
/* ============================================
1867+
Memory Card Styles — Amber/Orange accent
1868+
============================================ */
1869+
1870+
/* Memory card — amber accent */
1871+
.ai-placeholder-card[data-ai-type="Memory"] {
1872+
border-color: rgba(245, 158, 11, 0.4);
1873+
background: linear-gradient(135deg, rgba(245, 158, 11, 0.08), rgba(217, 119, 6, 0.04));
1874+
}
1875+
1876+
.ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-header {
1877+
border-bottom-color: rgba(245, 158, 11, 0.2);
1878+
}
1879+
1880+
.ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-icon {
1881+
background: rgba(245, 158, 11, 0.15);
1882+
}
1883+
1884+
.ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-label {
1885+
color: #f59e0b;
1886+
}
1887+
1888+
.ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-btn {
1889+
border-color: rgba(245, 158, 11, 0.3);
1890+
color: #f59e0b;
1891+
}
1892+
1893+
.ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-btn:hover {
1894+
background: rgba(245, 158, 11, 0.15);
1895+
}
1896+
1897+
/* Memory stats display */
1898+
.ai-memory-stats {
1899+
padding: 8px 14px;
1900+
font-size: 0.78em;
1901+
color: rgba(245, 158, 11, 0.7);
1902+
border-top: 1px solid rgba(245, 158, 11, 0.1);
1903+
font-family: 'SF Mono', 'Cascadia Code', monospace;
1904+
}
1905+
1906+
/* Use: hint badge on AI/Think/Agent cards */
1907+
.ai-use-hint {
1908+
display: inline-flex;
1909+
align-items: center;
1910+
gap: 4px;
1911+
padding: 2px 8px;
1912+
border-radius: 12px;
1913+
font-size: 0.72em;
1914+
font-weight: 600;
1915+
background: rgba(245, 158, 11, 0.12);
1916+
color: #f59e0b;
1917+
border: 1px solid rgba(245, 158, 11, 0.25);
1918+
margin-left: 8px;
1919+
white-space: nowrap;
1920+
}
1921+
1922+
/* Memory toolbar button */
1923+
.fmt-memory-btn {
1924+
color: #f59e0b !important;
1925+
}
1926+
1927+
.fmt-memory-btn:hover {
1928+
background: rgba(245, 158, 11, 0.15) !important;
1929+
}
1930+
1931+
/* Light theme overrides */
1932+
[data-theme="light"] .ai-placeholder-card[data-ai-type="Memory"] {
1933+
border-color: rgba(217, 119, 6, 0.35);
1934+
background: linear-gradient(135deg, rgba(245, 158, 11, 0.06), rgba(217, 119, 6, 0.03));
1935+
}
1936+
1937+
[data-theme="light"] .ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-label {
1938+
color: #d97706;
1939+
}
1940+
1941+
[data-theme="light"] .ai-placeholder-card[data-ai-type="Memory"] .ai-placeholder-btn {
1942+
color: #d97706;
1943+
border-color: rgba(217, 119, 6, 0.3);
1944+
}
1945+
1946+
[data-theme="light"] .ai-memory-stats {
1947+
color: rgba(217, 119, 6, 0.7);
1948+
}
1949+
1950+
[data-theme="light"] .ai-use-hint {
1951+
background: rgba(217, 119, 6, 0.1);
1952+
color: #d97706;
1953+
border-color: rgba(217, 119, 6, 0.2);
18641954
}

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,8 @@ <h5>Menu</h5>
622622
title="Tag as AI Image Generate">Image</button>
623623
<button class="fmt-btn fmt-agent-btn" data-action="agent-tag"
624624
title="Tag as Agent Flow Pipeline">Agent</button>
625+
<button class="fmt-btn fmt-memory-btn" data-action="memory-tag"
626+
title="Tag as Context Memory Source">📚 Memory</button>
625627
<button class="fmt-btn fmt-fill-btn" data-action="fill-all" id="docgen-fill-btn"
626628
title="Fill all AI blocks">Fill</button>
627629
</div>

js/ai-docgen-generate.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,21 @@
1111
// PROMPT BUILDING
1212
// ==============================================
1313

14-
function buildPrompt(block, prevSections) {
14+
function buildPrompt(block, prevSections, memoryContext) {
1515
var base = block.type === 'Think'
1616
? 'You are a thoughtful writer. Think carefully about the topic, then produce polished markdown content.\n\n'
1717
+ 'IMPORTANT: Output ONLY the final polished markdown content. Do NOT include your thinking process, '
1818
+ 'reasoning steps, analysis, or any text like "Thinking Process:" or "Drafting:". '
1919
+ 'Just write the final, high-quality markdown article directly.\n\n'
2020
: 'You are an expert writer. Write well-formatted, high-quality markdown content for this section.\n\n';
2121

22+
var retrieval = '';
23+
if (memoryContext) {
24+
retrieval = '### RELEVANT CONTEXT FROM ATTACHED DOCUMENTS ###\n'
25+
+ memoryContext + '\n---\n\n'
26+
+ 'Use the above context to inform your response. Cite file names when relevant.\n\n';
27+
}
28+
2229
var instructions = 'Topic/Instructions:\n' + block.prompt + '\n\n';
2330

2431
var context = '';
@@ -27,7 +34,7 @@
2734
+ prevSections.substring(0, 3000) + '\n\n---\n\n';
2835
}
2936

30-
return base + instructions + context
37+
return base + retrieval + instructions + context
3138
+ 'Write ONLY the markdown content. Do not include any meta-commentary, explanations, '
3239
+ 'thinking process, or notes about what you wrote. Start directly with the content.';
3340
}
@@ -439,10 +446,21 @@
439446
if (block.type === 'Image') {
440447
result = await generateImageForBlock(block, perCardModel);
441448
} else {
449+
// Retrieve memory context if Use: field is present
450+
var memoryContext = '';
451+
if (block.useMemory && block.useMemory.length > 0 && M._memory) {
452+
try {
453+
var chunks = await M._memory.search(block.useMemory, block.prompt, 5);
454+
memoryContext = M._memory.formatForContext(chunks);
455+
} catch (memErr) {
456+
console.warn('Memory search failed:', memErr);
457+
}
458+
}
459+
442460
result = await M.requestAiTask({
443461
taskType: 'generate',
444462
context: prevContent.substring(Math.max(0, prevContent.length - 3000)),
445-
userPrompt: buildPrompt(block, prevContent),
463+
userPrompt: buildPrompt(block, prevContent, memoryContext),
446464
enableThinking: block.type === 'Think',
447465
silent: true
448466
});
@@ -550,6 +568,18 @@
550568
}
551569

552570
stepPrompt += 'Task: ' + steps[i].description + '\n\n';
571+
572+
// Retrieve memory context for this step
573+
if (block.useMemory && block.useMemory.length > 0 && M._memory) {
574+
try {
575+
var memChunks = await M._memory.search(block.useMemory, steps[i].description, 3);
576+
var memCtx = M._memory.formatForContext(memChunks);
577+
if (memCtx) {
578+
stepPrompt += '### RELEVANT CONTEXT FROM ATTACHED DOCUMENTS ###\n' + memCtx + '\n---\n\n';
579+
}
580+
} catch (_) { /* memory search failed, proceed without */ }
581+
}
582+
553583
if (accumulatedContext) {
554584
stepPrompt += 'Previous steps produced:\n' + accumulatedContext.substring(0, 3000) + '\n\n';
555585
}

0 commit comments

Comments
 (0)