Changeset 0.23.0 (#153)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user