mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 23:18:13 +02:00
Un dossier de fichiers par discussion
Les fichiers du chat vivaient dans un pot commun : on changeait de discussion et on revoyait les mêmes pièces jointes, et supprimer une discussion laissait derrière elle tout ce qu'on y avait déposé ou fait écrire à l'agent (seules ses captures, déjà rangées par identifiant, partaient avec). Chaque discussion a désormais son dossier, <workspace>/discussions/<id>/ : - les dépôts (uploads/), les captures (captures/) et ce que l'agent écrit y atterrissent ; le shell et les chemins relatifs du modèle y sont résolus ; - le panneau Fichiers s'ouvre sur ce dossier et n'en sort pas, et se redessine quand la discussion change (bascule ou vidage, signalés par le flux SSE) ; - supprimer une discussion — ou la vider — emporte ses fichiers. Les deux gestes le disent maintenant avant de demander confirmation ; « clear chat » en demandait aucune. La racine du dossier de travail reste la borne de sécurité : les liens des anciens messages (uploads/x.pdf, captures/<id>/y.jpg) continuent d'ouvrir leur fichier par un chemin de repli. Au démarrage, une migration range les captures dans le dossier de leur discussion et rend chaque dépôt à la discussion qui le mentionne dans son journal ; ce que personne ne réclame reste à la racine, atteignable par le bouton « hors discussion » du panneau, qui disparaît une fois le ménage fait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd
This commit is contained in:
21 files changed
+914
-168
No files matched your search
@@ -48,6 +48,8 @@ func TestSafeUploadNameKeepsOrdinaryNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChatUploadWritesFileAndAttachNote(t *testing.T) {
|
||||
withWorkspace(t)
|
||||
|
||||
body, _ := json.Marshal(map[string]any{
|
||||
"name": "../notes.txt",
|
||||
"data": "data:text/plain;base64," + base64.StdEncoding.EncodeToString([]byte("bonjour")),
|
||||
@@ -101,6 +103,8 @@ func TestChatUploadWritesFileAndAttachNote(t *testing.T) {
|
||||
// Le téléchargement est le point sensible : il lit des fichiers du serveur à
|
||||
// partir d'un chemin fourni par le client.
|
||||
func TestChatFileStaysInsideWorkspace(t *testing.T) {
|
||||
withWorkspace(t)
|
||||
|
||||
dir, err := uploadsDir()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -181,6 +185,8 @@ func uploadChunk(t *testing.T, body map[string]any) (int, map[string]any) {
|
||||
// près. C'est ce découpage qui permet le gigaoctet : sans lui, tout le fichier
|
||||
// passait dans un seul corps JSON, gardé en mémoire des deux côtés.
|
||||
func TestChatUploadChunked(t *testing.T) {
|
||||
withWorkspace(t)
|
||||
|
||||
part1 := strings.Repeat("A", 5000)
|
||||
part2 := strings.Repeat("B", 3000)
|
||||
part3 := "fin"
|
||||
@@ -239,6 +245,8 @@ func TestChatUploadUnknownSessionRefused(t *testing.T) {
|
||||
// réponse en JSON, où du binaire ne survit pas. Le handler doit donc annoncer
|
||||
// qu'on est derrière le tunnel, puis savoir servir des tranches base64.
|
||||
func TestChatFileB64ForE2E(t *testing.T) {
|
||||
withWorkspace(t)
|
||||
|
||||
dir, _ := uploadsDir()
|
||||
// Des octets NON-UTF8 : c'est exactement ce que le réemballage JSON massacre.
|
||||
raw := make([]byte, 5000)
|
||||
@@ -308,6 +316,8 @@ func TestChatFileB64ForE2E(t *testing.T) {
|
||||
// jointe). Les sessions doivent donc être indépendantes : le verrou global ne
|
||||
// protège que la table, l'écriture se fait sous le verrou de la session.
|
||||
func TestChatUploadConcurrentSessions(t *testing.T) {
|
||||
withWorkspace(t)
|
||||
|
||||
const files, chunks = 4, 6
|
||||
var wg sync.WaitGroup
|
||||
paths := make([]string, files)
|
||||
|
||||
Reference in new issue
Block a user