Changeset 0.23.0 (#153)

This commit is contained in:
2026-03-05 22:40:26 +00:00
parent 40d9834f64
commit 2fc620e1ac
62 changed files with 6214 additions and 362 deletions

View File

@@ -263,6 +263,30 @@ scope='personal' → owner_id=user.id → User-managed, visible to owner
Used by: `provider_configs`, `personas`, `model_catalog` (visibility column adds `enabled`/`disabled`/`team` states on top), `projects`.
## Personas
Personas are named AI configurations: a system prompt, base model, provider
config, and behavioral parameters (temperature, max tokens, thinking budget).
Each persona has a unique `handle` field (e.g. `veronica-sharpe`) used for
@mention routing.
**Handle Generation:** Auto-generated from name on create (`HandleFromName()`):
lowercase, spaces→hyphens, alphanumeric only, max 50 chars. Editable via the
persona form. Unique index prevents collisions.
**Scope Model:** Same as other resources — global, team, personal. Personal
personas are only visible to the creator. Team and global personas are visible
to all users with the appropriate access.
**Resolution Chain (completion):**
```
Explicit persona (req.PersonaID) → Project persona → @mention persona → dropdown selection
```
**Memory:** Personas have `memory_enabled` and `memory_extraction_prompt` fields.
When memory is enabled, the persona's memory scope is independent — facts
extracted in conversations with Persona A are not visible to Persona B.
## Projects (v0.19.0)
Projects are organizational containers that group channels, knowledge bases,
@@ -324,19 +348,42 @@ in Settings → Notifications.
**Cleanup:** Background goroutine deletes notifications older than retention
period (default 90 days, configurable via admin settings).
## @mention Routing + Multi-model (v0.20.0)
## @mention Routing (v0.23.0)
Channels support multiple AI models. The `channel_models` table (schema 001)
holds the roster; `mentions.Parse()` extracts @mentions from message content
and resolves against display names (case-insensitive, longest-match-first).
Type `@handle` or `@model-id` in any chat to route the completion to a
different persona or model. No roster, group, or channel setup required.
**Completion Fan-out:** When mentions resolve to channel models, the completion
handler fires sequentially for each target, producing one assistant message
per model. Without @mention, the default channel model responds (backward
compatible). Frontend renders model attribution labels on multi-model responses.
**Resolution (`resolveMention`):** Extracts the first `@token` from message
content and queries the DB directly:
**Autocomplete:** CM6 `mentionCompletion` extension triggers on `@` in the
chat input, showing a dropdown of channel model display names.
1. Persona handle — exact match against `personas.handle` (case-insensitive)
2. Persona handle — prefix match (unambiguous only)
3. Model ID — exact match against `model_catalog.model_id` (enabled + active provider)
4. Model ID — prefix match (unambiguous only)
Persona resolution returns the persona's model, provider config, and system
prompt. Model resolution returns the raw model ID and config — no persona
character, no system prompt override.
**Context Boundaries:** When @mentioning a persona, a system message is
injected before the user's message telling the target to ignore previous
personas' styles. When no @mention is used but persona responses exist in
history, a boundary tells the default model to respond in its own style.
**Participant Hint:** `buildParticipantHint()` injects a system message
listing all @mentionable personas (handle + name + description). This tells
the LLM who it can invoke, enabling AI-to-AI chaining.
**AI-to-AI Chaining:** After each completion, `chainIfMentioned()` runs
`resolveMention()` on the assistant's response. If it @mentions another
persona, a follow-up completion fires asynchronously. Result delivered via
WebSocket (`message.created`). Self-mention blocked. Depth capped at 5.
Same resolution function for user→LLM and LLM→LLM routing.
**Autocomplete (Frontend):** `ChannelModels.onInput()` triggers on `@` in
the chat input, matching against all `App.models` (enabled, non-hidden) by
persona handle, model ID, and display name. Popup shows avatar, name,
`@handle` hint, and provider. Selection inserts `@handle` into the input.
## Frontend Architecture
@@ -356,9 +403,11 @@ src/
│ ├── api.js # HTTP client with token refresh
│ ├── app.js # Application state machine, startup, routing
│ ├── chat.js # Chat input abstraction, message send/receive
│ ├── channel-models.js # @mention autocomplete, channel model roster
│ ├── events.js # Labeled event bus + WebSocket bridge
│ ├── debug.js # Debug panel, diagnostics, state export
│ ├── ui-core.js # DOM rendering, sidebar, modals, panels
│ ├── ui-format.js # Markdown rendering, @mention pills, code blocks
│ ├── ui-settings.js # Settings tabs, theme, appearance, teams
│ ├── ui-admin.js # Admin panel rendering
│ ├── admin-handlers.js # Admin CRUD operations + extension editors

View File

@@ -114,7 +114,9 @@ v0.22.7 Surface Prototypes (Theme + ChatPane + Splash) ✅
|
v0.22.8 Surface Integration (Wire into existing JS)
|
v0.23.0 Multi-Participant Channels + Presence
v0.23.0 @mention Routing + Persona Handles + Proxy ✅
v0.23.1 Multi-User: DMs + Group Chat
v0.24.0 Auth Strategy (mTLS/OIDC) + Full RBAC + Group permissions
@@ -1198,32 +1200,83 @@ Depends on: surface prototypes (v0.22.7).
---
## v0.23.0 — Multi-Participant Channels + Presence
## v0.23.0 — @mention Routing + Persona Handles + Proxy
The channel foundation for workflows and real-time collaboration. Today
channels are single-user direct chats. This release makes channels a
shared space that multiple actors can inhabit.
@mention routing works in any chat against the full model catalog and persona
registry. No roster, groups, or participant setup required — just type `@handle`
or `@model-id` and send.
Depends on: extension surfaces (v0.21.3), WebSocket infrastructure (already exists).
**@mention Resolution**
- [x] `resolveMention()`: direct DB lookup — persona handle (exact/prefix) → model catalog (exact/prefix)
- [x] Autocomplete popup on `@` in any chat — all enabled models + personas
- [x] Handle field on personas: auto-generated from name, unique, editable
- [x] @mention pill rendering in message content (accent-colored, code-aware)
- [x] Context boundaries: persona→plain and persona→persona style isolation
- [x] Participant list injection: system prompt tells LLM who it can @mention
_(Shifted from v0.20.0 — no content changes)_
**AI-to-AI Chaining**
- [x] `chainIfMentioned()`: uses `resolveMention()` on assistant response content
- [x] Self-mention blocked, depth capped at 5
- [x] WebSocket delivery (`message.created` + typing indicators)
- [x] Same resolution path for user→LLM and LLM→LLM routing
**Channel Participants**
- [ ] `channel_participants` table: `channel_id`, `participant_type` (user, session, persona), `participant_id`, `role` (owner, member, observer), `joined_at`
- [ ] Channel access queries rewritten: `WHERE user_id = $1` → participant-based lookup
- [ ] Backward compatible: existing single-user channels auto-have one participant (owner)
- [ ] Channel `type` column: `direct` (current), `group` (multi-user), `workflow` (staged)
**Provider Proxy**
- [x] `proxy_mode` (system/direct/custom) + `proxy_url` on `provider_configs`
- [x] All four providers use `cfg.Client()` with mode-aware HTTP transport
- [x] Bad custom URL falls back to system (not direct) — safe for mandatory-proxy environments
**Channel Infrastructure**
- [x] `channel_participants` table with polymorphic types and roles
- [x] `channel_models` partial indexes: persona entries keyed per-persona, raw models per-provider
- [x] Per-provider model preferences (composite keys in `user_model_settings`)
- [x] `persona_groups` + `persona_group_members` tables (schema ready, CRUD not yet wired)
---
## v0.23.1 — Multi-User: DMs + Group Chat
Real human-to-human messaging. Builds on v0.23.0's participant infrastructure
(`channel_participants`, @mention routing, WebSocket events). The @mention
system already resolves personas — this release extends it to resolve users.
Depends on: @mention routing (v0.23.0), WebSocket infrastructure (exists).
**User-to-User DMs**
- [ ] `@username` resolution in `resolveMention()`: extend DB lookup to `users` table
- [ ] When `resolveMention()` returns a user (not persona): skip completion, deliver as notification
- [ ] DM channel type: two user participants, no AI unless explicitly @mentioned
- [ ] DM creation flow: user picker, creates channel with both users as participants
- [ ] Unread count per channel per user (read cursor in `channel_participants`)
- [ ] Real-time message delivery via WebSocket to recipient's active session
**Group Chat (Human + AI)**
- [ ] Persona group CRUD: create/edit/delete saved roster templates (`persona_groups`)
- [ ] "New Chat with Group" flow: pick a template, stamp onto fresh channel
- [ ] Group leader (default responder): `is_leader` flag on `persona_group_members`
- [ ] No @mention in group = leader responds. @mention overrides.
- [ ] Group editing: add/remove personas, change leader — affects future chats only
- [ ] `@all` routing: every persona participant responds (existing `multiModelStream` path)
**Presence + Real-time**
- [ ] Typing indicators and presence (who's online, who's in this channel)
- [ ] Participant join/leave events via WebSocket
- [ ] Co-editing for extension surfaces (editor mode, article mode)
- [ ] Cursor sharing, selection highlighting
- [ ] Typing indicators for human participants (extend existing persona typing events)
- [ ] Online/offline status per user (heartbeat-based, stored in memory not DB)
- [ ] Participant join/leave WebSocket events
- [ ] Unread badge on sidebar chat items
**Channel-Scoped Notes**
- [ ] Optional `channel_id` FK on notes (NULL = personal notebook, set = channel-attached)
- [ ] Notes created by tool calls within a channel auto-attach to that channel
- [ ] Channel notes visible to all participants (not just creator)
**User @mention UX**
- [ ] Autocomplete includes users alongside models and personas (different icon)
- [ ] @mention pills distinguish user mentions (different color) from persona/model mentions
- [ ] Notification center: @mention notifications with channel deep-link
**Message Attribution**
- [ ] Messages from human users show their avatar + display name (not "You" for other participants)
- [ ] Messages from personas retain current avatar + handle rendering
- [ ] Thread view: flat chronological for now, threading deferred
**Migration**
- [ ] `users.handle` column (unique, auto-generated from username or display_name)
- [ ] Read cursor columns on `channel_participants`: `last_read_message_id`, `last_read_at`
- [ ] Notification table: `user_notifications` (type, channel_id, message_id, actor_id, read_at)
---