# Changelog All notable changes to Chat Switchboard. ## [0.17.1] — 2026-02-27 ### Added - **SQLite backend.** Full dual-driver database layer — set `DB_DRIVER=sqlite` to run with an embedded SQLite database. Pure Go (no CGO), zero external dependencies. 19 store files covering all domain stores: channels, messages, users, teams, personas, knowledge bases, notes, usage, audit, extensions, and more. Feature parity with Postgres including knowledge base vector search via app-level cosine similarity computed in Go. - **Dialect-aware test infrastructure.** `database.SetupTestDB()` detects `DB_DRIVER` and provisions either a Postgres test database or a SQLite temp file. Exported `database.PH(n)` returns `$N` or `?` per dialect. `database.TruncateAll()` uses `TRUNCATE CASCADE` on Postgres and `DELETE FROM` with `PRAGMA foreign_keys` toggling on SQLite. `dialectSQL()` helper in handler tests converts `$N` placeholders and strips `::jsonb` casts at runtime. - **SQLite CI pipeline.** New `test-sqlite` job runs the full handler integration test suite and store tests against an embedded SQLite database. Parallel with the existing Postgres test job. Build gate verifies `CGO_ENABLED=0` compilation. - **Generic provider test config.** Live provider integration tests now read `PROVIDER`, `PROVIDER_KEY`, and `PROVIDER_URL` environment variables instead of hardcoded `VENICE_API_KEY`. Legacy fallback preserved. Model selection prefers non-reasoning models to avoid thinking budget requirements with low `max_tokens`. ### Changed - `kb_chunks` table in SQLite schema includes `embedding TEXT` column for JSON-encoded float64 vectors (previously omitted as feature-gated). - `SimilaritySearch` on SQLite loads candidate chunks, decodes JSON embeddings, and computes cosine distance in Go — replacing the previous "not available" error. - `InsertChunks` on SQLite now stores embedding vectors as JSON text. - Live test names genericized: `TestLive_Venice*` → `TestLive_*`. - CI `build-and-deploy` depends on `[test, test-frontend, test-sqlite]`. ### Fixed - **SQLite `RETURNING` + `time.Time` scan failure.** The modernc/sqlite driver cannot scan `datetime('now')` TEXT columns into `time.Time` via `RETURNING`. All 13 SQLite store `Create` methods rewritten to set timestamps in Go (`time.Now().UTC()`) and use `ExecContext` instead of `QueryRowContext(...).Scan()`. Format: `2006-01-02 15:04:05` (`timeFmt` constant in `helpers.go`). - **SQLite missing `id` in INSERTs.** Unlike Postgres (`DEFAULT gen_random_uuid()`), SQLite `TEXT PRIMARY KEY` columns have no auto-generation. Added `store.NewID()` / `uuid.New()` to: `usage_log`, `model_pricing` (both upsert paths), `team_members` (AddMember), `group_members` (AddMember), `refresh_tokens` (CreateRefreshToken). - **Test seed helpers SQLite-aware.** `SeedTestUser`, `SeedTestChannel`, `SeedTestTeam`, `SeedTestTeamMember`, `SeedTestGroup`, `SeedGroupMember` now branch on `IsSQLite()` to provide application-generated UUIDs instead of relying on `RETURNING id`. - **Postgres-isms in SQLite stores.** `extension.go` Update used `now()` → `datetime('now')`; `ListForUser` COALESCE used `true` → `1`. - SQLite store bool/int type mismatches: `persona.go` auto-fetch flag, `usage.go` exclude-BYOK filter, `user_settings.go` visibility map values — all corrected from `0`/`1` to `false`/`true`. ## [0.17.0] — 2026-02-27 ### Added - **Persona-KB binding.** Personas can now have knowledge bases directly bound to them. When a user selects a persona with bound KBs, the `kb_search` tool is automatically scoped to those KBs and the persona's system prompt includes a KB listing hint. Admin and team admin preset forms include a KB picker with per-KB auto-search toggles. Migration adds `persona_knowledge_bases` join table. - **Enterprise KB mode.** New `discoverable` flag on knowledge bases controls whether users can see and attach KBs directly. When `kb_direct_access` platform policy is set to `true`, users cannot attach KBs to channels directly — they access KBs exclusively through persona bindings curated by admins. New `ListDiscoverableKBs` and `SetDiscoverable` endpoints. - **Role fallback alerts (issue #69).** When a role's primary provider fails and the fallback activates, the resolver emits a `role.fallback` event on the EventBus with audit log entry. Admin users see a persistent dismissable banner. 5-minute per-role cooldown prevents flooding. - **Chat rename.** Double-click any chat title in the sidebar to edit inline. Enter saves, Escape cancels. - **Utility model auto-naming.** After the first assistant response, a background request to the utility role generates a concise title. Falls back to truncation when no utility model is configured. New endpoint: `POST /channels/:id/generate-title`. - **Chat token count.** Conversation token estimate shown in the model bar, color-coded against context budget. - **State restore on refresh.** Active chat ID persisted to `sessionStorage`, auto-restored on page reload. ### Fixed - **ResolvePreset group access bypass.** `ResolvePreset()` used raw SQL that skipped `resource_grants` checks from v0.16.0. Now uses `PersonaStore.UserCanAccess()`. - **KB create scope authorization.** Now enforces admin role for global KBs and team admin role for team KBs. - **Completion handler persona ID scoping.** `personaID` variable scoped inside an `if` block but referenced downstream. Fixed by threading through function signatures. - **Nil slice JSON marshaling.** `ListDiscoverableKBs` returns `[]` instead of `null` when no KBs match. ### Changed - `UpdateDocumentStorageKey` moved from raw `ExecContext` to store method. - EventBus route table: `role.fallback` → `DirToClient`. - Resolver gains `.WithBus(bus)` builder (nil-safe, backwards compatible). - Service worker: `/extensions/` excluded from fetch handler. - Mermaid renderer v2.0 (pan/zoom, export) promoted to builtin. - Removed DIAG diagnostics from `TestGroupBasedPersonaAccess`. - Paste-to-file threshold synced from backend `PublicSettings` (`storage.paste_to_file_chars`, admin-configurable, default 2000). Resolves hardcoded constant in `attachments.js`. - Embedding dropdown already had tolerant type filter, manual model ID fallback, and auto-switch on empty — confirmed complete, checkbox updated. ## [0.16.0] — 2026-02-27 ### Added - **User groups.** Global and team-scoped groups decoupled from team membership. `groups` and `group_members` tables. Admin and team admin CRUD for group management. Groups serve as ACL targets for resources. - **Resource grants.** Three-way grant model (`team_only`, `global`, `groups`) for Personas and Knowledge Bases. `resource_grants` table with `grant_scope` and `granted_groups UUID[]` columns. Grant picker UI on Persona and KB forms with group multi-select. - **Schema consolidation.** 9 incremental migrations collapsed into single `001_v016_schema.sql`. Fresh installs use the consolidated file; upgrade path preserved via migration version tracking. ### Changed - Persona and KB list queries now filter through `resource_grants` for non-admin users. Team-only remains the default scope. - Admin panel shows group membership counts and grant summaries. ## [0.15.1] — 2026-02-26 ### Added - **`attachment_recall` tool.** Two operations: `list` returns filenames and metadata for the current channel's attachments; `read` extracts and returns content by attachment ID. Channel-scoped access control. - **`conversation_search` tool.** Full-text search across the current channel's message history using PostgreSQL `plainto_tsquery`. Returns matching messages with timestamps and role context. - **Token estimator attachment awareness.** `Tokens.estimateAttachments()` accounts for staged file sizes in context budget calculations. Warning thresholds include attachment estimates. ## [0.15.0] — 2026-02-26 ### Added - **Background compaction scanner.** Periodic scan identifies channels exceeding configurable context thresholds. Automatic summarization via utility role compresses old messages into summary nodes. Per-channel opt-in/out via `auto_compact` channel setting. - **Compaction service.** `compaction.Service` orchestrates summary generation: estimates token usage, selects messages for compression, calls utility role, inserts summary as tree boundary node with metadata. - **Context budget guard rail.** 80% ceiling prevents compaction from triggering mid-generation. Cooldown timer prevents repeated compaction of the same channel. - **Summarize & Continue button.** User-triggered compaction from the context warning bar. Reuses compaction service with immediate execution. ### Changed - Scanner configurable via `global_settings`: threshold percentage, cooldown duration, enabled/disabled toggle. Channel-level overrides. ## [0.14.0] — 2026-02-26 ### Added - **Knowledge bases.** RAG pipeline: upload documents → chunk (recursive text splitter) → embed via pgvector → `kb_search` tool for semantic retrieval. Team and personal KB scopes. Channel KB toggle enables per-conversation knowledge access. - **Document ingestion.** `knowledge.Ingest()` pipeline: file upload → text extraction (reuses v0.12.0 pipeline) → chunking with configurable overlap → embedding via the embedding role → storage as `kb_chunks` with vector index. - **KB admin panel.** Knowledge Bases section under AI category. Create, delete, upload documents, view chunk counts and storage usage. Team admin scoped to team KBs. - **Notes semantic search.** Note search upgraded from exact text match to pgvector cosine similarity when embeddings are available. - **`kb_search` tool.** Registered when embedding role is configured. Accepts query text, returns top-K chunks with source document attribution. Channel KB bindings control which KBs are searched. ### Changed - pgvector extension enabled in schema (`CREATE EXTENSION IF NOT EXISTS vector`). `kb_chunks` table includes `embedding vector(1536)` column with IVFFlat index. ## [0.13.1] — 2026-02-26 ### Added - **`web_search` tool.** Search provider abstraction with two backends: DuckDuckGo (HTML scraping, zero config) and SearXNG (self-hosted, JSON API). Returns title, URL, and snippet for each result. Configured via `SEARCH_PROVIDER` and `SEARXNG_URL` env vars. - **`url_fetch` tool.** Fetches and extracts text content from URLs. Respects robots.txt. Content-type detection with HTML-to-text conversion. Configurable timeout and size limits. - **Tool categories.** Tools now have a `category` field (builtin, search, knowledge, browser). Tools toggle UI in chat bar groups by category with per-tool enable/disable. - **Tools toggle UI.** Popup menu on chat input toolbar showing all available tools. Per-tool checkbox state sent as `disabled_tools[]` in completion requests. Browser extension tools included. ## [0.13.0] — 2026-02-25 ### Changed - **Admin panel refactor.** Replaced 12-tab modal with fullscreen admin panel. Four categories (People, AI, System, Monitoring) with section sidebar navigation. URL-based routing (`#admin/people/users`). Responsive layout, classification banner-aware positioning. - **CSS design token cleanup.** Consolidated duplicate color/spacing variables. Admin panel uses shared token system with main UI. ## [0.12.0] — 2026-02-25 ### Added - **File handling and vision support.** Upload images, PDFs, and documents into chat via 📎 button, drag-and-drop, or paste. Multimodal message assembly injects base64 images for vision-capable models and extracted text for documents. Staged attachment strip shows upload progress and extraction status. Auth-aware blob rendering with Bearer tokens. Image lightbox viewer. Vision capability hints on image attachments. - **Storage backend abstraction.** `ObjectStore` interface with two implementations: PVC (local filesystem) for single-node/dev and S3 (minio-go) for multi-node production. S3 backend works with any S3-compatible API: MinIO, Ceph RGW, AWS S3. Auto-detection when `STORAGE_BACKEND` is not set (tries PVC, disables if not writable). Both backends share identical semantics — all handlers, attachment CRUD, multimodal assembly, and orphan cleanup work regardless of backend. - **S3 configuration.** `S3_ENDPOINT`, `S3_BUCKET`, `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_REGION`, `S3_PREFIX`, `S3_FORCE_PATH_STYLE` env vars. Endpoint auto-detects SSL from scheme. Path-style URLs default on (required for MinIO/Ceph). Optional key prefix for shared buckets. CI pipeline syncs S3 secrets to K8s when `STORAGE_BACKEND=s3`. - **Text extraction pipeline.** PDF, DOCX, XLSX, PPTX, ODT, RTF text extraction via filesystem-based queue. Inline and sidecar modes. Crash recovery for items stuck in processing state. - **Admin storage panel.** Backend health, file count, total size, orphan detection and cleanup. Shows PVC path or S3 endpoint/bucket depending on active backend. Extraction queue status. - **Vault CLI commands.** `switchboard vault rekey` re-encrypts all provider API keys when rotating the encryption key. `switchboard vault status` shows encryption health. Admin UI encryption status indicator in Settings tab. - **Per-chat model persistence.** Server-side `channels.settings` JSONB field stores `last_selector_id`. Roams across devices with localStorage write-through cache as fallback. ## [0.11.0] — 2026-02-25 ### Added - **Browser extension system.** Full lifecycle: manifest registration, script injection, scoped context (`ctx.renderers`, `ctx.tools`, `ctx.events`, `ctx.storage`, `ctx.ui`), permission-aware API proxying. Extensions self- register via `Extensions.register()` and receive isolated contexts during `initAll()`. Admin CRUD endpoints, asset serving (public, no auth needed for `