feat: let one source carry several chats, and open them with a +
Nightly Build / build (push) Successful in 7m49s

A source had exactly one live conversation, so the copilot could only ever
replace a chat, never add one: the trash button reset the source and the old
conversation was left orphaned. Working on two things at once meant losing one.

The tab bar now holds two kinds of tab. A primary tab is a source — it shows
whatever `web` or `project-7` currently points at, which is where background
delivery lands (notify, a finished async task, an inbound Telegram message) and
what a reset moves to a fresh row. A secondary tab, opened with `+`, is one
specific conversation: its source points elsewhere, so it is unreachable by
source name and is addressed by id throughout — REST, WebSocket, event
filtering. `POST /api/sessions/new` creates one without touching `sources`,
which is the whole difference from a reset; its agent and run-context still come
from the source, so an extra project tab is the coordinator with the project's
context. Project "Open chat" is untouched and still resumes the project's own.

The load-bearing half is in ChatHub: the input queue and the model pin are now
keyed by session, not by source. Two tabs on one source would otherwise
serialize into a single queue and a single turn, and share a `/model` pin — the
odd one out, since the security group was already per-session and persisted. The
source-taking methods survive as one-line resolvers, so Telegram, mobile and
cron are untouched. Because queues now grow with conversations rather than with
the handful of sources, a reset retires the queue it replaces instead of leaving
a consumer task parked forever.

Events are filtered per conversation, so anything a chat must see has to carry a
session id: `show_file_to_user`'s OpenFile and the security-group revalidation
were emitting untagged and would have reached nobody. A primary connection
additionally follows NewSession for its source, so a second window does not keep
talking to a conversation another window just reset.

Tabs can be renamed by double-click — `chat_sessions.title` existed and was dead
until now. An empty name stores NULL, so the box is also the undo.
This commit is contained in:
2026-08-04 22:15:20 +01:00
parent 8f5c5382c8
commit 78cdcf4cc7
22 changed files with 1026 additions and 248 deletions
+2
View File
@@ -70,6 +70,8 @@ export default {
'chat.security_group': 'Groupe de sécurité',
'chat.collapse': 'Masquer la discussion',
'chat.close_tab': 'Fermer l\'onglet',
'chat.new_tab': 'Nouvelle discussion',
'chat.new_tab.loading': 'Chargement…',
'chat.privacy': 'Privé pour vous',
'chat.privacy.hint': 'Vous seul(e) pouvez voir cette conversation. Partager quoi que ce soit avec le groupe demande toujours une approbation préalable.',
'chat.suggest.1': 'Que pouvez-vous faire ?',