Skip to content

2.10.0

Choose a tag to compare

@csebold csebold released this 01 Apr 06:51
· 2558 commits to main since this release
2.10.0

Quilltap v2.10.0 Release Notes

Business in the front, party in the back... literary salon on the veranda.

Subsystems

Subsystems are now almost characters in their own right, working to make your estate a great place to interact with LLMs, for business or pleasure.

Name Function
The Foundry The Heart of the Operation - architecture, plugins, packages, LLMs, API keys - the "settings"
Prospero Your majordomo, conducting your projects, agents, the tools and files they access
Aurora Our complex character model, and how it interacts with the LLMs that drive it
The Commonplace Book Your characters' memories, a simple RAG that just works
The Salon The chat interface, so you can talk to one or many characters and LLMs
Calliope The user experience, interface, and our many themes. We like our Art Deco here
Dangermouse Always in the shadows, he can keep you from running afoul of your starched-collar LLM providers... or dodge them; he's a black market of possibilities
The Lantern The image generation support, now featuring atmospheric story backgrounds generated on the fly or on demand while you chat

If you hate the look and feel and weird names, use the Old School theme, it calls things by their boring old names.

Highlights

Agent Mode — LLMs can now use tools iteratively, verify results, and self-correct before delivering a final response. A new submit_final_response tool signals completion, with configurable max turns (1–25) and a settings cascade from global down to per-chat.

Dangerous Content Handling (Dangermouse) — A three-mode gatekeeper system classifies messages for sensitive content using the Cheap LLM, with optional auto-routing to uncensored providers. Includes chat-level danger classification, quick-hide integration, startup scanning, and image generation rerouting.

Story Backgrounds (The Lantern) — AI-generated atmospheric background images for chats, derived from scene context analysis. Includes context-aware character appearance resolution, clothing-appropriate outfit selection, and support on project pages with multiple display modes.

Character Appearance Overhaul — Clothing records are now separated from physical descriptions with full CRUD support. Physical descriptions gain a usageContext field. A new cheap LLM task resolves what each character currently looks like based on narrative context, stored records, and scene appropriateness.

Character Identity — Characters now support aliases (alternate names like "Liz" for "Elizabeth") and pronouns (he/him, she/her, they/them, custom). Both are injected into system prompts, used in multi-character context, and respected by image generation.

Memory Gate — Pre-write similarity checks replace binary duplicate detection. Memories are reinforced, linked, or inserted based on semantic similarity, with logarithmic importance scaling and bidirectional relationship tracking.

Proactive Memory Recall — Characters now analyze recent conversation to extract search keywords and recall relevant memories before responding, running in parallel with compression checks.

New Default Theme: Professional Neutral — A cooler blue-gray palette with system fonts, restrained shadows, and compact UI replaces the original warm default. Two new theme plugins (The Great Estate, Old School) and a major Art Deco overhaul round out the theme work.

Massive Codebase Refactoring — Type-safe query filters, safeQuery() eliminating ~315 redundant catch blocks, ChatsRepository split into five modules, ~65 components migrated to qt-* classes, and a comprehensive security audit.


Major Features

Agent Mode — Iterative Tool Use with Self-Correction

  • LLMs can now use tools iteratively, verify results, and self-correct before delivering a final response
  • New submit_final_response tool signals completion of agent work
  • Configurable max turns (1–25, default 10) with force-final safety limit
  • Settings cascade: Global > Character > Project > Chat (each level can override)
  • Global settings in Foundry > Chat: default enabled toggle and max turns
  • Per-chat toggle in tool palette (Agent button)
  • Agent mode status persists in database and syncs across UI on page load
  • New SSE events: agent_iteration, agent_completed, agent_force_final
  • New help documentation at /help/agent-mode
  • Native tool execution rules injected into system prompt for models with function calling, reinforced in character voice after personality/scenario sections

Dangerous Content Handling (Dangermouse)

  • Gatekeeper service classifies user messages for sensitive content using the Cheap LLM
  • Three modes: Off (default), Detect Only (flag content), Auto-Route (reroute to uncensored providers)
  • Provider routing service resolves uncensored-compatible profiles for flagged content
  • Connection profiles and image profiles gain "Uncensored-Compatible" checkbox
  • Message display with DangerFlagBadge (category badges, rerouted indicator, override button)
  • DangerContentWrapper with Show/Blur/Collapse display modes
  • Content hash caching for classification deduplication (200 entries, 5min TTL)
  • Fail-safe design: classification errors never block messages
  • Image generation integration: classifies user image prompts and expanded prompts, reroutes to uncensored image providers
  • Uncensored fallback for empty LLM responses: when an LLM silently refuses content, retries with uncensored provider in AUTO_ROUTE mode — covers memory extraction (user, character, inter-character), context compression, chat streaming, story background prompt crafting, and appearance resolution
  • New DANGER_CLASSIFICATION system event type for LLM log tracking

Chat-Level Danger Classification

  • Background job classifies entire chats as dangerous using compressed context summary
  • Sticky behavior: once classified as dangerous, stays dangerous (never re-checks); safe chats skip re-classification unless new messages are added
  • Startup scan runs on server boot and every 10 minutes to classify legacy/unclassified chats
  • Context summary → danger classification chaining: completing a summary automatically triggers classification
  • Raw message fallback for chats without context summaries (truncated to 4000 chars)
  • Decision tree: chats with summary → classify directly; long chats (>50 messages) → generate summary first; short chats → classify from raw messages
  • Quick-hide sidebar integration with toggle across homepage, character conversations, project chats, and sidebar
  • Danger indicator (destructive-colored asterisk) on all chat listings
  • POST /api/v1/chats/[id]?action=reclassify-danger endpoint to reset and re-queue
  • Danger classification scoring now uses the maximum of overall score and highest per-category score, and respects the LLM's explicit isDangerous: true response
  • New database fields: isDangerousChat, dangerScore, dangerCategories, dangerClassifiedAt, dangerClassifiedAtMessageCount

Story Backgrounds (The Lantern)

  • AI-generated landscape scene images featuring characters, triggered after chat title updates
  • Background images use 45% opacity behind chat content for atmosphere
  • Scene context derivation: new deriveSceneContext cheap LLM task analyzes recent messages to generate imaginative scene descriptions; if discussing a book or story, characters may be depicted as observers to that world
  • Context-aware character appearance resolution: new cheap LLM task determines what each character currently looks like based on narrative context, clothing records, physical descriptions, and usageContext matching
  • Clothing priority: narrative context (highest) > image prompt > stored records by usageContext > default
  • Story backgrounds respect chat-specific image profile settings (chat profile > story bg default > user default)
  • Support on project detail pages with configurable backgroundDisplayMode
  • Story background thumbnails in chat enrichment and on ChatCard components
  • Chat header shows clickable thumbnail (opens full-screen modal)
  • Manual regeneration via "Regenerate Background" button in chat tool palette
  • Background images pin to top of viewport instead of centering (prevents face cropping)
  • Theme background images yield to story backgrounds via CSS :has() selector
  • Duplicate job prevention and failed-job recovery
  • GET /api/v1/chats/[id]?action=get-background, GET /api/v1/projects/[id]?action=get-background
  • Image profile moved from per-participant to per-chat level (migration auto-populates from first participant)

Character Clothing Records

  • New clothingRecords embedded JSON array on characters (name, usageContext, markdown description)
  • Full CRUD API at /api/v1/characters/[id]/clothing and /api/v1/characters/[id]/clothing/[recordId]
  • Expandable card UI, modal editor with markdown preview, list with empty state
  • "Physical Descriptions" tab renamed to "Appearance" — now shows both physical descriptions and clothing records
  • Clothing records injected into system prompts as ## Clothing / Outfits block after physical appearance
  • Clothing data included in image generation prompt expansion context
  • Story background generation includes primary outfit in character descriptions
  • Backup/restore handles UUID remapping

Physical Description usageContext Field

  • New optional free-text field (up to 200 chars) describes when each appearance is most appropriate
  • Physical descriptions now injected into chat system prompts (previously only used for image generation)
  • Usage context passed through to image generation prompt expansion for scene-appropriate selection
  • Editor form with character counter and helper text; card display shows usage context inline

Character Aliases

  • Characters can have alternate names (e.g., "Liz" for "Elizabeth")
  • Aliases included in the character's own system prompt
  • Other participants' aliases included in multi-character chat context
  • Image prompt placeholders (e.g., {{Liz}}) resolve aliases to correct character
  • Alias-based name prefixes stripped from LLM responses
  • Chip-style editor in character edit form; displayed inline on character view page

Character Pronouns

  • Dropdown selector with common presets (He/Him/His, She/Her/Her, They/Them/Their, It/It/Its) plus custom option
  • Pronouns included in character's own system prompt
  • Other participants' pronouns shown in multi-character chat context
  • User-controlled characters' pronouns included in "You are talking to..." line
  • Displayed inline on character view page next to name and aliases

Character Identity Reinforcement

  • Short ## Identity Reminder block appended as the very last content before conversation messages
  • Reminds the LLM which character it is and who it must not write for
  • Multi-character variant explicitly names all other participants
  • Placed after memories and summaries for maximum compliance near the generation boundary

Proactive Memory Recall

  • Characters analyze recent conversation to recall relevant memories before responding
  • New cheap LLM task extracts search keywords from messages since the character last spoke
  • Keywords search the character's memory store for contextually relevant memories
  • Pre-searched memories passed to context builder, skipping default single-message search
  • Works naturally in multi-character chats: each character recalls based on their own conversation gap
  • Runs in parallel with compression cache check to minimize latency
  • Status indicators: "Analyzing recent conversation..." and "Searching {name}'s memories..."
  • Graceful fallback when cheap LLM unavailable or keyword extraction fails

Memory Gate — Pre-Write Similarity Check

  • Three-tier decision at write time: REINFORCE near-duplicates (≥ 0.80 similarity), LINK related-but-distinct (0.70–0.80), or INSERT genuinely new
  • Reinforced memories track observation count (reinforcementCount), last reinforcement time, and boosted importance (reinforcedImportance = min(1.0, importance + log2(count+1) * 0.05))
  • Related memories bidirectionally linked via relatedMemoryIds for thematic graph discovery
  • Novel detail extraction appends new facts as [+] footnotes when reinforcing
  • Housekeeping uses reinforcedImportance for protection/scoring; memories reinforced 5+ times always protected
  • Hard-cap scoring rebalanced: importance 0.4, recency 0.2, access 0.2, reinforcement 0.2
  • API supports skipGate for force-insert and relatedMemoryIds for manual link management
  • Falls back to keyword-based gate when embeddings unavailable
  • Database migration adds 4 columns with automatic backfill

Memory Deduplication Tool

  • New tool card on /foundry page for finding and merging duplicate memories across all characters
  • Cosine similarity with configurable threshold (0.70–0.95, default 0.80) to cluster duplicates
  • Union-Find clustering identifies transitive duplicate groups
  • Best survivor selected by importance, content length, and specificity scoring
  • Novel details from discarded memories preserved as [+] footnotes
  • Groups memories by embedding dimension to handle mixed-dimension vectors
  • Preview mode shows per-character analysis before any changes
  • Cleans up vector store entries for removed memories

UI Improvements

Foundry Hub Restructure

  • New /foundry landing page with 8 subsystem navigation cards (Aurora, The Forge, The Salon, The Commonplace Book, Prospero, Dangermouse, Calliope, The Lantern)
  • 8 new sub-routes (/foundry/aurora, /foundry/forge, /foundry/salon, etc.)
  • New CollapsibleCard component with qt-collapsible-card-* CSS classes
  • Sidebar permanently collapsed: removed expand/collapse toggle, resize handle, width persistence
  • Sidebar footer: merged Settings + Tools into single "Foundry" link
  • /settings redirects to /foundry for backward compatibility

UI Route Renaming

  • /characters/aurora (character model system)
  • /chats/salon (chat interface)
  • /projects/prospero (agentic and tool-using systems)
  • /tools/foundry (architecture, plugins, and services)
  • Old routes redirect to new ones; API routes (/api/v1/*) unchanged

Turn-Order Participant Sidebar

  • Participants sorted by predicted turn order instead of static display order
  • Numbered position badges: green pulsing (generating), green (next), blue (queued), neutral (eligible), amber (user turn), dimmed (spoken)
  • Inactive participants shown at bottom with dimmed appearance instead of hidden
  • Stop/interrupt button on generating character's card replaces composer stop button in multi-character chats
  • Active/inactive toggle as visible eye icon button on each card
  • Connection profile dropdown on each card for instant model switching
  • "User (you type)" option allows switching characters to user control
  • Expandable per-card settings: system prompt override textarea and active toggle

Chat Composer Tool Palette Revamp

  • Hamburger menu reorganized into four labeled sections: Chat, Organize, Edit Content, Memory
  • Composer gutter tools: Attach, Generate Image, and RNG as icon buttons
  • RNG icon changed to recognizable dice face with pips
  • Dice roll options now have up/down spinner buttons to adjust count; counts persist within session
  • Preview toggle moved to formatting toolbar
  • Full-width mode properly expands composer textarea

Tool Message UI Improvements

  • Tool messages embedded inside message bubbles (assistant or user) instead of standalone
  • User-initiated tools embed in user messages; character-initiated tools in assistant messages
  • Collapsed state shows truncated preview text for request/response
  • Text content wraps properly instead of horizontal scrolling
  • Copy buttons for tool request and response sections; image copy to clipboard
  • Consistent vertical spacing between all messages

Chat Settings Simplification

  • Chat settings modal now only contains roleplay template and image generation settings
  • Per-participant settings (connection profile, system prompt override, active toggle) moved to sidebar cards
  • Image profile moved from per-participant to per-chat level

Unified ChatCard Component

  • Reusable ChatCard component across /salon, /prospero/[id], and /aurora/[id]/view
  • Configurable via props: showAvatars, showProject, showPreview, useRelativeDates, actionType
  • Chat cards display story background thumbnails when available
  • Highlight animation for newly imported chats

Queue Status Badges

  • Compact badge group in page toolbar shows active job counts for memory, summarization, danger classification, and story background queues
  • Color-coded: blue (memory), green (summary), red (danger), dark gray (story background)
  • Fully themeable via qt-queue-badge-* CSS variables
  • Event-driven polling: starts on route change or job enqueue, stops when all counts reach zero

Tag Management

  • New "Tag Management" section in Settings > Tags tab lists all tags with usage counts
  • Delete button with confirmation popover showing affected entity count
  • Deletion cascades across all 6 entity types (characters, chats, connection profiles, image profiles, embedding profiles, files)
  • Tag usage counts now include all entity types with totalUsage computed field

Theme System

Professional Neutral Default Theme

  • Color palette shifted from warm slate-blue (hue 220) to cool blue-gray (hue 225)
  • System font stack throughout — Inter and EB Garamond dropped in favor of OS defaults
  • Lower saturation, tighter fixed border radii, restrained shadows, compact UI
  • Qt-* variables scoped to [data-theme="default"] selector

The Great Estate Theme

  • Manor house library aesthetic — mahogany (hue 20) and gold (hue 43) palette
  • Full-page background image with carbon-fibre texture overlay
  • Playfair Display serif headings with Inter sans-serif body text
  • Gold left border on assistant messages, brown right border on user messages
  • Full light/dark mode support

Art Deco Theme Overhaul

  • Darker light mode palette, background images for both modes
  • Left sidebar fixed from dark navy to warm ivory in light mode
  • Assistant message font weight set to 500 via new --qt-chat-assistant-font-weight variable

Old School Theme

  • Preserves the original warm slate-blue palette with Inter and EB Garamond fonts
  • Plain-English subsystem name overrides (Settings, Prompts, Data, Chat Behavior, etc.)
  • Foundry cards redesigned with CSS grid layout; background images suppressed

Theme-Overridable Subsystem Names

  • SubsystemOverrides interface and optional subsystems field in ThemePlugin (@quilttap/plugin-types 1.13.0)
  • Override display names, descriptions, thumbnails, and background images for any Foundry subsystem
  • API returns overrides; new useSubsystemInfo() hooks in theme provider

Theme Package Sync

  • @quilttap/theme-storybook (1.0.18 → 1.0.20): ~120 missing CSS variables, ~15 missing class definitions, phantom class name fixes, removed phantom story sections
  • create-quilltap-theme (1.0.5 → 1.0.6): template and docs fixes matching class renames
  • Rains (→ 1.3.5) and Earl Grey (→ 1.3.3): ~120 missing qt-* variables backfilled for self-containment
  • Ocean theme removed from distribution

Refactoring & Technical Debt

Type-Safe Query Filters

  • New TypedQueryFilter<T> mapped type constrains filter fields to keyof T at compile time
  • Removed 138 unnecessary as QueryFilter casts across 26 repository files
  • 6 compile-time type assertion tests; zero runtime changes

safeQuery() Helper

  • Standalone function and AbstractBaseRepository protected method
  • Converted ~315 catch blocks across 29 files
  • Three failure modes preserved: rethrow (writes), fallback (reads), silent (non-critical)

ChatsRepository SRP Split

  • Facade + 5 focused modules: Participants, Impersonation, TokenTracking, Messages, SearchReplace
  • Shared ChatOpsContext interface — zero changes to callers
  • 1,115 → 422 lines in facade

Theme Utility Class Migration

  • ~65 component files migrated from raw Tailwind to qt-* theme utility classes
  • Additional settings components cleaned up (modals, alerts, toggles, checkboxes, provider buttons)

Other Refactoring

  • UsersRepository.migrateUserId replaced direct SQLite access with database abstraction layer
  • Cheap LLM selection lifted out of compression guard (unconditional resolution)
  • sendToProvider() extracted in cheap-llm-tasks.ts, eliminating triple code duplication
  • pseudoToolInstructions renamed to toolInstructions throughout the pipeline
  • Replaced 19 empty if/else blocks with debug logging across 10 repository files
  • Inlined CHEAPEST_MODEL_MAP reference; removed deprecated tool-registry wrappers

Security

  • ReDoS fix: Spin-bottle regex bounded .* to .{0,50}
  • Query injection prevention: 1000-character max query length in memory and chat search methods
  • Command injection: exec()execFile() in data-dir route
  • XSS prevention: Removed allowDangerousHtml from markdown renderer; raw HTML in messages now escaped
  • Input validation: Range checking for parseInt/parseFloat params in memories housekeeping endpoint

Performance & Backend

Visible Message Filtering

  • Chat messageCount now only counts visible bubbles (USER/ASSISTANT); system events, SYSTEM/TOOL messages, and context summaries no longer inflate counts
  • extractVisibleConversation() utility filters to USER/ASSISTANT and strips tool artifacts for all cheap LLM content-judging tasks (titles, summaries, backgrounds, compression, keyword extraction)
  • Title generation now uses up to 100 messages weighted toward end of conversation instead of just the first 6

Server-Side Markdown Pre-Rendering

  • Simple messages pre-rendered to HTML on the server with roleplay pattern support
  • Pre-rendered HTML returned in API response and rendered directly without client-side processing
  • Complex messages with embedded tools or attachments fall back to client-side rendering
  • Comprehensive CSS rules for all markdown elements in .qt-chat-message-content

Background Job Fixes

  • Per-job execution timeout (3 minutes) via Promise.race prevents indefinite hangs on LLM calls
  • Periodic stuck job recovery every 5 minutes (previously only on startup)
  • Failed jobs no longer block new job creation for the same chat
  • $expr operator support for field-to-field comparisons in SQLite query translator
  • Fixed findOneAndUpdate to correctly return updated document

Bug Fixes

Critical

  • Story backgrounds not generated on inline title updates (only unused background job path had the queue call)
  • Agent mode toggle showing "off" after navigating back to chat (agentModeEnabled missing from GET response)
  • Race condition in plugin initialization causing "Provider not found" errors in Docker (initialized flag set too early)
  • Danger classification re-queuing all chats on every server restart (off-by-one between messageCount and dangerClassifiedAtMessageCount)
  • Story backgrounds settings race condition causing data loss on rapid changes
  • BaseModal z-index stacking issue on project pages (now uses React portal)
  • ImageModal z-index stacking (also moved to React portal)
  • Plugin loading fails in Turbopack production builds (replaced __non_webpack_require__ with createRequire)

Data Integrity

  • Chat timestamps now always reflect last actual message (system events no longer update lastMessageAt/updatedAt)
  • Project chats sorted by lastMessageAt instead of updatedAt
  • Danger classification scoring now uses maximum of overall and per-category scores
  • Search and Replace now searches all memory fields (content, summary, keywords)

UI

  • Server-rendered code blocks overlapping and corrupted (roleplay patterns applied inside code blocks)
  • Markdown elements missing spacing in server-rendered messages (Tailwind Typography plugin not installed in v4)
  • SelectLLMProfileDialog using wrong API endpoint
  • Chat image profile setting not loading in Chat Settings modal
  • Thumbnail cache misses logging as errors (now uses fileExists check first)
  • Template Import modal not showing templates (response handling fix)
  • Dangerous content settings not persisting (missing field in PUT handler)
  • Image description fallback crash (wrong repository reference)

Housekeeping

  • Removed ~160 logger.debug() and console.debug() call sites across 53 files
  • Deleted Ocean theme plugin
  • Comprehensive dead code audit and removal (unused hooks, components, MongoDB stubs, migration stubs, webpack suppressions)
  • Updated DEAD-CODE-REPORT.md, migrations/README.md, appearance settings README
  • EmbeddingProfilesRepository.unsetAllDefaults return type standardized to Promise<number>
  • 13 unit tests for markdown renderer canPreRenderMessage; 22 for RNG pattern detector; 17 for base repository helpers; 35 for vector store against SQLite backend

Known Technical Debt

Identified in audit, deferred to future releases:

  • Inconsistent error handling: Some repositories throw, some return null, some return empty arrays — needs a unified convention
  • Duplicated search/replace logic: MemoriesRepository and ChatsRepository could share a SearchableRepository mixin

Previously identified items resolved in this release:

  • ChatsRepository SRP split
  • Redundant try-catch wrappers (safeQuery() helper)
  • UsersRepository.migrateUserId bypasses database abstraction
  • ~45 remaining component files with raw Tailwind violations
  • QueryFilter loosely typed across all repositories