Compare commits

..
3 Commits
73 changed files with 1753 additions and 112 deletions

No files matched your search

+110
View File
@@ -0,0 +1,110 @@
# Lassistanoque
Assistant IA auto-hébergé : backend Go (API + SPA embarquée), base SQLite, connecteurs LLM multiples (via [any-llm](https://github.com/mozilla-ai/any-llm-go)), authentification par mot de passe ou OpenID Connect.
## Prérequis
- Go >= 1.26
- Node.js + npm (build du frontend)
- (optionnel) un serveur OpenID Connect, ex. [Keycloak](https://www.keycloak.org/)
## Installation
```bash
# 1. frontend : build la SPA et l'écrit dans backend/internal/http/web
cd backend/web
npm install
npm run build
# 2. backend
cd ..
go build -o lassistanoque .
```
Le `Makefile` du backend enchaîne les deux et produit les binaires multi-plateformes dans `build/` :
```bash
make build # linux/amd64, linux/arm64, windows, darwin...
```
## Configuration
La configuration se fait par variables d'environnement, chargeables depuis un fichier `.env` placé dans le répertoire de lancement (backend) :
| Variable | Défaut | Description |
|----------------------------|--------------------|----------------------------------------------------|
| `LASSISTANOQUE_DB_TYPE` | `turso` | Type de base (seul `turso`/SQLite est implémenté) |
| `LASSISTANOQUE_DB_URL` | `lassistanoque.db` | Chemin du fichier SQLite |
| `LASSISTANOQUE_HTTP_PORT` | `3000` | Port du serveur HTTP |
| `LASSISTANOQUE_JWT_SECRET` | *(obligatoire)* | Secret de signature des tokens, ex. `openssl rand -base64 32` |
| `LASSISTANOQUE_STORAGE_TYPE`| `database` | Stockage des fichiers (seul `database` est implémenté) |
| `LASSISTANOQUE_SERVER_ID` | `default` | Identifiant du serveur |
Exemple `backend/.env` :
```env
LASSISTANOQUE_JWT_SECRET=<secret généré>
LASSISTANOQUE_HTTP_PORT=3000
```
## Lancement
```bash
./lassistanoque serve
```
- Les migrations de la base sont appliquées automatiquement au démarrage (ou manuellement avec `./lassistanoque migrate`).
- L'application est servie sur `http://localhost:3000` (SPA + API `/api`).
- Créez le premier compte depuis la page d'inscription (`/register`), puis configurez un fournisseur LLM et sa clé d'API dans les réglages de l'espace (`settings/models`).
## Authentification OpenID Connect
Les fournisseurs OIDC sont enregistrés dans la table `oidc` :
```sql
insert into oidc (id, label, domain, client_id, client_secret, wellknown_url, _date_created, _version)
values (
'keycloak', -- identifiant du fournisseur
'Keycloak', -- libellé affiché sur la page de connexion
'sso.example.com', -- domaine du fournisseur
'lassistanoque', -- client_id
'<client_secret>',
'https://<keycloak>/realms/<realm>/.well-known/openid-configuration',
datetime('now'),
'v1'
);
```
Côté fournisseur (Keycloak) :
- client de type *confidential*, *Standard Flow* (authorization code) activé ;
- *Valid Redirect URIs* : `http://localhost:3000/api/auth/oidc/callback` (l'URL de callback est reconstruite depuis le `Host` de la requête ; derrière un reverse proxy, transmettre `X-Forwarded-Proto` et `X-Forwarded-Host`).
Flux : les fournisseurs configurés apparaissent comme boutons sur la page de connexion → redirection vers le fournisseur → au retour, le backend valide le `state` signé, échange le code, vérifie le token ID (signature JWKS, émetteur, audience) puis délivre les tokens applicatifs. À la première connexion, l'utilisateur est créé automatiquement avec son espace personnel.
## Développement
```bash
# backend (API sur :3000)
cd backend
go run . serve
# frontend en mode dev (Vite sur :5173, API proxyfiée vers :3000)
cd web
npm run dev
```
Structure :
```
backend/
├── cmd/ # CLI (serve, migrate, version) et assemblage IoC
├── internal/
│ ├── adapter/ # implémentations : db (turso/SQLite), auth (password, oidc), llm, tools, security (JWT)
│ ├── domain/ # entités et interfaces des repositories
│ ├── http/ # serveur HTTP, routes, SPA embarquée
│ └── service/ # logique métier (auth, chat, agents, tasks...)
└── web/ # frontend SvelteKit
```
Tests : `go test ./backend/...`
+13
View File
@@ -10,6 +10,7 @@ import (
"trankilou.fr/lassistanoque/backend/internal/adapter/llm" "trankilou.fr/lassistanoque/backend/internal/adapter/llm"
"trankilou.fr/lassistanoque/backend/internal/adapter/security" "trankilou.fr/lassistanoque/backend/internal/adapter/security"
"trankilou.fr/lassistanoque/backend/internal/adapter/tools/browser" "trankilou.fr/lassistanoque/backend/internal/adapter/tools/browser"
"trankilou.fr/lassistanoque/backend/internal/adapter/tools/scheduler"
"trankilou.fr/lassistanoque/backend/internal/adapter/tools/searxng" "trankilou.fr/lassistanoque/backend/internal/adapter/tools/searxng"
"trankilou.fr/lassistanoque/backend/internal/adapter/tools/weather" "trankilou.fr/lassistanoque/backend/internal/adapter/tools/weather"
"trankilou.fr/lassistanoque/backend/internal/domain" "trankilou.fr/lassistanoque/backend/internal/domain"
@@ -18,6 +19,7 @@ import (
"trankilou.fr/lassistanoque/backend/internal/service/chat" "trankilou.fr/lassistanoque/backend/internal/service/chat"
"trankilou.fr/lassistanoque/backend/internal/service/provider" "trankilou.fr/lassistanoque/backend/internal/service/provider"
"trankilou.fr/lassistanoque/backend/internal/service/storage" "trankilou.fr/lassistanoque/backend/internal/service/storage"
"trankilou.fr/lassistanoque/backend/internal/service/task"
"trankilou.fr/lassistanoque/backend/internal/service/tool" "trankilou.fr/lassistanoque/backend/internal/service/tool"
"trankilou.fr/lassistanoque/backend/internal/service/user" "trankilou.fr/lassistanoque/backend/internal/service/user"
) )
@@ -36,6 +38,7 @@ var providerService *provider.Service
var agentService *agent.Service var agentService *agent.Service
var toolService *tool.Service var toolService *tool.Service
var chatService *chat.Service var chatService *chat.Service
var taskService *task.Service
var tokenManager auth.TokenManager var tokenManager auth.TokenManager
func init() { func init() {
@@ -135,16 +138,26 @@ func GetChatService() *chat.Service {
GetLLMAdapter(), GetLLMAdapter(),
GetToolService(), GetToolService(),
) )
// l'exécution des tâches planifiées passe par le service de chat
GetTaskService().SetChatService(chatService)
} }
return chatService return chatService
} }
func GetTaskService() *task.Service {
if taskService == nil {
taskService = task.NewService(db.TaskRepository())
}
return taskService
}
func GetToolService() *tool.Service { func GetToolService() *tool.Service {
if toolService == nil { if toolService == nil {
toolService = tool.NewService(db.ToolRepository(), db.UserRepository()) toolService = tool.NewService(db.ToolRepository(), db.UserRepository())
toolService.RegisterToolImpl(&weather.WeatherTool{}) toolService.RegisterToolImpl(&weather.WeatherTool{})
toolService.RegisterToolImpl(&searxng.SearxngTool{}) toolService.RegisterToolImpl(&searxng.SearxngTool{})
toolService.RegisterToolImpl(&browser.BrowserTool{}) toolService.RegisterToolImpl(&browser.BrowserTool{})
toolService.RegisterToolImpl(scheduler.New(GetTaskService()))
} }
return toolService return toolService
} }
+5
View File
@@ -47,11 +47,16 @@ func runServe() {
AgentService: GetAgentService(), AgentService: GetAgentService(),
ChatService: GetChatService(), ChatService: GetChatService(),
ToolService: GetToolService(), ToolService: GetToolService(),
TaskService: GetTaskService(),
TokenManager: GetTokenManager(), TokenManager: GetTokenManager(),
}) })
gatewayRouter := gateway.NewRouter(gateway.Dependencies{}) gatewayRouter := gateway.NewRouter(gateway.Dependencies{})
// task scheduler : replanifie les tâches persistées
GetTaskService().Start()
defer GetTaskService().Stop()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop() defer stop()
@@ -17,6 +17,7 @@ type Database interface {
AgentRepository() domain.AgentRepository AgentRepository() domain.AgentRepository
ChatRepository() domain.ChatRepository ChatRepository() domain.ChatRepository
ToolRepository() domain.ToolRepository ToolRepository() domain.ToolRepository
TaskRepository() domain.TaskRepository
Migrate() error Migrate() error
Close() Close()
} }
@@ -2,6 +2,7 @@ package turso
import ( import (
"database/sql" "database/sql"
"fmt"
"log" "log"
"strings" "strings"
@@ -30,7 +31,7 @@ func NewTursoChatRepository(db *sql.DB) *TursoChatRepository {
} }
} }
func (r *TursoChatRepository) ListChats(userID string, teamID string, page int, query string) ([]*domain.Chat, error) { func (r *TursoChatRepository) ListChats(userID string, teamID string, page int, query string, taskID string) ([]*domain.Chat, error) {
where := "team_id=$1 and team_id in (select team_id from user_teams where user_id=$2)" where := "team_id=$1 and team_id in (select team_id from user_teams where user_id=$2)"
args := []any{teamID, userID} args := []any{teamID, userID}
if query != "" { if query != "" {
@@ -41,6 +42,10 @@ func (r *TursoChatRepository) ListChats(userID string, teamID string, page int,
where += " and title like $3 escape '\\'" where += " and title like $3 escape '\\'"
args = append(args, "%"+escaped+"%") args = append(args, "%"+escaped+"%")
} }
if taskID != "" {
where += fmt.Sprintf(" and task_id=$%d", len(args)+1)
args = append(args, taskID)
}
return r.chatTable.Select( return r.chatTable.Select(
orm.WithWhere(where, args...), orm.WithWhere(where, args...),
orm.WithOrder("_date_created desc"), orm.WithOrder("_date_created desc"),
@@ -87,3 +87,7 @@ func (db *TursoDB) ChatRepository() domain.ChatRepository {
func (db *TursoDB) ToolRepository() domain.ToolRepository { func (db *TursoDB) ToolRepository() domain.ToolRepository {
return NewTursoToolRepository(db.DB) return NewTursoToolRepository(db.DB)
} }
func (db *TursoDB) TaskRepository() domain.TaskRepository {
return NewTursoTaskRepository(db.DB)
}
@@ -25,7 +25,7 @@ func TestListChatsFilter(t *testing.T) {
create table user_teams (user_id text, team_id text); create table user_teams (user_id text, team_id text);
insert into chats (id, team_id, user_id, agent_id, task_id, title, fresh_title, _date_created, _version) insert into chats (id, team_id, user_id, agent_id, task_id, title, fresh_title, _date_created, _version)
values ('c1','t1','u1','','','Problème de timeout',0,'2026-01-01 10:00:00','v'), values ('c1','t1','u1','','','Problème de timeout',0,'2026-01-01 10:00:00','v'),
('c2','t1','u1','','','Discussion navigateur',0,'2026-01-02 10:00:00','v'), ('c2','t1','u1','','task-9','Discussion navigateur',0,'2026-01-02 10:00:00','v'),
('c3','t1','u1','','','Recette de cuisine 100%',0,'2026-01-03 10:00:00','v'); ('c3','t1','u1','','','Recette de cuisine 100%',0,'2026-01-03 10:00:00','v');
insert into user_teams (user_id, team_id) values ('u1','t1'); insert into user_teams (user_id, team_id) values ('u1','t1');
insert into chats (id, team_id, user_id, agent_id, task_id, title, fresh_title, _date_created, _version) insert into chats (id, team_id, user_id, agent_id, task_id, title, fresh_title, _date_created, _version)
@@ -40,14 +40,14 @@ func TestListChatsFilter(t *testing.T) {
repo := NewTursoChatRepository(db) repo := NewTursoChatRepository(db)
// sans filtre, page 0 : 20 conversations (28 en base) // sans filtre, page 0 : 20 conversations (28 en base)
p0, err := repo.ListChats("u1", "t1", 0, "") p0, err := repo.ListChats("u1", "t1", 0, "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(p0) != 20 { if len(p0) != 20 {
t.Fatalf("page 0: expected 20, got %d", len(p0)) t.Fatalf("page 0: expected 20, got %d", len(p0))
} }
p1, err := repo.ListChats("u1", "t1", 1, "") p1, err := repo.ListChats("u1", "t1", 1, "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -61,7 +61,7 @@ func TestListChatsFilter(t *testing.T) {
} }
seen[c.ID] = true seen[c.ID] = true
} }
p2, err := repo.ListChats("u1", "t1", 2, "") p2, err := repo.ListChats("u1", "t1", 2, "", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -70,7 +70,7 @@ func TestListChatsFilter(t *testing.T) {
} }
// filtre simple // filtre simple
res, err := repo.ListChats("u1", "t1", 0, "timeout") res, err := repo.ListChats("u1", "t1", 0, "timeout", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -79,7 +79,7 @@ func TestListChatsFilter(t *testing.T) {
} }
// jokers LIKE neutralisés : '100%' ne doit rien matcher de spécial // jokers LIKE neutralisés : '100%' ne doit rien matcher de spécial
res, err = repo.ListChats("u1", "t1", 0, "100%") res, err = repo.ListChats("u1", "t1", 0, "100%", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -88,7 +88,7 @@ func TestListChatsFilter(t *testing.T) {
} }
// pas de résultat // pas de résultat
res, err = repo.ListChats("u1", "t1", 0, "inexistant") res, err = repo.ListChats("u1", "t1", 0, "inexistant", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -96,5 +96,14 @@ func TestListChatsFilter(t *testing.T) {
t.Fatalf("expected 0, got %d", len(res)) t.Fatalf("expected 0, got %d", len(res))
} }
// filtre par tâche
taskRes, err := repo.ListChats("u1", "t1", 0, "", "task-9")
if err != nil {
t.Fatal(err)
}
if len(taskRes) != 1 || taskRes[0].ID != "c2" {
t.Fatalf("filter task-9: expected [c2], got %v", taskRes)
}
_ = domain.Chat{} _ = domain.Chat{}
} }
@@ -0,0 +1 @@
alter table tasks drop column repeat;
@@ -0,0 +1 @@
alter table tasks add column repeat integer not null default 1;
@@ -0,0 +1 @@
alter table tasks drop column last_datetime;
@@ -0,0 +1 @@
alter table tasks add column last_datetime numeric;
@@ -0,0 +1,85 @@
package turso
import (
"database/sql"
"log"
"trankilou.fr/lassistanoque/backend/internal/adapter/database/orm"
"trankilou.fr/lassistanoque/backend/internal/domain"
)
type TursoTaskRepository struct {
db *sql.DB
taskTable orm.Table[domain.Task]
}
func NewTursoTaskRepository(db *sql.DB) *TursoTaskRepository {
dialect := orm.NewSqliteDialect()
taskTable, err := orm.NewTable[domain.Task](db, dialect, "tasks")
if err != nil {
log.Fatalf("error creating task table")
}
return &TursoTaskRepository{
db: db,
taskTable: taskTable,
}
}
func (r *TursoTaskRepository) ListTasks(userID string, teamID string) ([]*domain.Task, error) {
return r.taskTable.Select(
orm.WithWhere(
"team_id=$1 and team_id in (select team_id from user_teams where user_id=$2)",
teamID,
userID,
),
orm.WithOrder("_date_created desc"),
)
}
func (r *TursoTaskRepository) ListActiveTasks() ([]*domain.Task, error) {
return r.taskTable.Select(
orm.WithWhere("status=$1", domain.TaskStatusActive),
)
}
func (r *TursoTaskRepository) GetTaskByID(userID string, teamID string, id string) (*domain.Task, error) {
return r.taskTable.SelectOne(
"id=$1 and team_id=$2 and team_id in (select team_id from user_teams where user_id=$3)",
id,
teamID,
userID,
)
}
func (r *TursoTaskRepository) CreateTask(task *domain.Task) (*domain.Task, error) {
return r.taskTable.Insert(task)
}
func (r *TursoTaskRepository) UpdateTask(task *domain.Task) (*domain.Task, error) {
return r.taskTable.Update(task)
}
func (r *TursoTaskRepository) DeleteTask(userID string, teamID string, id string) error {
return r.taskTable.DeleteWhere(
"id=$1 and team_id=$2 and team_id in (select team_id from user_teams where user_id=$3)",
id,
teamID,
userID,
)
}
// FirstUserOfTeam retourne le premier utilisateur d'une équipe. Les tâches
// planifiées ne portent pas d'utilisateur : c'est lui qui porte la conversation
// générée lors de l'exécution.
func (r *TursoTaskRepository) FirstUserOfTeam(teamID string) (string, error) {
var userID string
err := r.db.QueryRow(
"select user_id from user_teams where team_id=$1 order by _date_created asc limit 1",
teamID,
).Scan(&userID)
if err != nil {
return "", err
}
return userID, nil
}
+16 -12
View File
@@ -168,13 +168,15 @@ func (e *AnyLLMEngine) Stream(
Extra: extra, Extra: extra,
}) })
params.OnChunk(&domain.Chunk{ if params.OnChunk != nil {
Done: false, params.OnChunk(&domain.Chunk{
ToolName: tc.Function.Name, Done: false,
Role: anyllm.RoleAssistant, ToolName: tc.Function.Name,
Content: tc.Function.Arguments, Role: anyllm.RoleAssistant,
Reasoning: false, Content: tc.Function.Arguments,
}) Reasoning: false,
})
}
} }
@@ -182,11 +184,13 @@ func (e *AnyLLMEngine) Stream(
} }
if !toolCalling { if !toolCalling {
params.OnChunk(&domain.Chunk{ if params.OnChunk != nil {
Done: true, params.OnChunk(&domain.Chunk{
Role: anyllm.RoleAssistant, Done: true,
Content: "", Role: anyllm.RoleAssistant,
}) Content: "",
})
}
} }
if err := <-errChan; err != nil { if err := <-errChan; err != nil {
@@ -0,0 +1,186 @@
package scheduler
import (
"context"
"encoding/json"
"fmt"
"trankilou.fr/lassistanoque/backend/internal/domain"
"trankilou.fr/lassistanoque/backend/internal/service/task"
)
// SchedulerTool permet à l'agent de planifier des tâches pour l'utilisateur :
// exécution d'un prompt selon une spécification cron, avec ou sans répétition.
type SchedulerTool struct {
taskService *task.Service
}
func New(taskService *task.Service) *SchedulerTool {
return &SchedulerTool{taskService: taskService}
}
func (t *SchedulerTool) Name() string {
return "scheduler"
}
func (t *SchedulerTool) Description() string {
return "Schedule tasks that run automatically at specified times, with or without repetition. " +
"Use this tool whenever the user asks to do something later or on a recurring basis " +
"(e.g. 'every day at 8am', 'every Monday at 9am', 'tomorrow at 6pm', 'every hour'). " +
"Actions: 'create' (schedule a new task), 'list' (list scheduled tasks), " +
"'update' (modify a task's title, prompt, cron or repetition), " +
"'delete' (delete a task by its id)."
}
func (t *SchedulerTool) Params() []domain.ToolParam {
return []domain.ToolParam{}
}
func (t *SchedulerTool) Definition(ctx context.Context) *domain.ToolDefinition {
return &domain.ToolDefinition{
Type: "function",
Function: &domain.ToolFunction{
Name: t.Name(),
Description: t.Description(),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"action": map[string]any{
"type": "string",
"enum": []string{"create", "list", "update", "delete"},
"description": "The scheduling action to perform.",
},
"title": map[string]any{
"type": "string",
"description": "Short task title, e.g. 'Météo du matin'. Required for 'create'.",
},
"prompt": map[string]any{
"type": "string",
"description": "Self-contained prompt to execute at the scheduled time. " +
"It will run in a fresh conversation with no memory of this one: " +
"include all needed context. Required for 'create'.",
},
"cron": map[string]any{
"type": "string",
"description": "Cron spec, 5 fields 'minute hour day-of-month month day-of-week' " +
"(e.g. '0 8 * * *' every day at 08:00, '0 9 * * 1' every Monday at 09:00, " +
"'30 18 1 * *' on the 1st at 18:30) or a descriptor like '@daily', '@hourly', '@weekly'. " +
"Required for 'create'.",
},
"repeat": map[string]any{
"type": "boolean",
"description": "true: the task repeats on schedule. " +
"false: it runs only once, at the first time matching the cron spec, then is marked done. " +
"Default true. Use false for one-shot requests like 'tomorrow at 8am'.",
},
"id": map[string]any{
"type": "string",
"description": "Task id, as returned by 'list'. Required for 'update' and 'delete'.",
},
},
"required": []string{"action"},
},
},
}
}
func (t *SchedulerTool) Execute(ctx context.Context, input []byte, configuration string) ([]byte, error) {
var params struct {
Action string `json:"action"`
Title string `json:"title"`
Prompt string `json:"prompt"`
Cron string `json:"cron"`
Repeat *bool `json:"repeat"`
ID string `json:"id"`
}
if err := json.Unmarshal(input, &params); err != nil {
return nil, fmt.Errorf("invalid parameters: %w", err)
}
userID, ok := domain.UserIDFromContext(ctx)
if !ok {
return nil, fmt.Errorf("scheduler tool: missing user context")
}
teamID, ok := domain.TeamIDFromContext(ctx)
if !ok {
return nil, fmt.Errorf("scheduler tool: missing team context")
}
modelID, _ := domain.ModelIDFromContext(ctx)
switch params.Action {
case "create":
repeat := true
if params.Repeat != nil {
repeat = *params.Repeat
}
taskModel, err := t.taskService.CreateTask(userID, teamID, &domain.Task{
ModelID: modelID,
Label: params.Title,
Prompt: params.Prompt,
Cron: params.Cron,
Repeat: repeat,
})
if err != nil {
return nil, err
}
result, err := json.Marshal(taskModel)
if err != nil {
return nil, err
}
return result, nil
case "list":
tasks, err := t.taskService.ListTasks(userID, teamID)
if err != nil {
return nil, err
}
result, err := json.Marshal(tasks)
if err != nil {
return nil, err
}
return result, nil
case "update":
if params.ID == "" {
return nil, fmt.Errorf("'id' is required for action 'update'")
}
current, err := t.taskService.GetTask(userID, teamID, params.ID)
if err != nil {
return nil, err
}
// mise à jour partielle : seuls les champs fournis changent
if params.Title != "" {
current.Label = params.Title
}
if params.Prompt != "" {
current.Prompt = params.Prompt
}
if params.Cron != "" {
current.Cron = params.Cron
}
if params.Repeat != nil {
current.Repeat = *params.Repeat
}
updated, err := t.taskService.UpdateTask(userID, teamID, current)
if err != nil {
return nil, err
}
result, err := json.Marshal(updated)
if err != nil {
return nil, err
}
return result, nil
case "delete":
if params.ID == "" {
return nil, fmt.Errorf("'id' is required for action 'delete'")
}
if err := t.taskService.DeleteTask(userID, teamID, params.ID); err != nil {
return nil, err
}
return []byte("task deleted"), nil
default:
return nil, fmt.Errorf("unknown action %q", params.Action)
}
}
+1 -1
View File
@@ -151,7 +151,7 @@ type LLMEngine interface {
} }
type ChatRepository interface { type ChatRepository interface {
ListChats(userID string, teamID string, page int, query string) ([]*Chat, error) ListChats(userID string, teamID string, page int, query string, taskID string) ([]*Chat, error)
ListChatsWithUnfreshTitles(teamID string) ([]*Chat, error) ListChatsWithUnfreshTitles(teamID string) ([]*Chat, error)
GetChat(userID string, teamID string, id string) (*Chat, error) GetChat(userID string, teamID string, id string) (*Chat, error)
CreateChat(userID string, chat *Chat) (*Chat, error) CreateChat(userID string, chat *Chat) (*Chat, error)
+35
View File
@@ -0,0 +1,35 @@
package domain
import "time"
const (
// statuts d'une tâche planifiée
TaskStatusActive = "active"
TaskStatusDone = "done"
)
type Task struct {
ID string `db:"id" json:"id"`
TeamID string `db:"team_id" json:"teamId"`
ModelID string `db:"model_id" json:"modelId"`
Label string `db:"label" json:"label"`
Prompt string `db:"prompt" json:"prompt"`
Cron string `db:"cron" json:"cron"`
Repeat bool `db:"repeat" json:"repeat"`
Status string `db:"status" json:"status"`
NextDatetime *time.Time `db:"next_datetime" json:"nextDatetime"`
LastDatetime *time.Time `db:"last_datetime" json:"lastDatetime"`
DateCreated time.Time `db:"_date_created" json:"_date_created"`
DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"`
VersionId string `db:"_version" json:"_version"`
}
type TaskRepository interface {
ListTasks(userID string, teamID string) ([]*Task, error)
ListActiveTasks() ([]*Task, error)
GetTaskByID(userID string, teamID string, id string) (*Task, error)
CreateTask(task *Task) (*Task, error)
UpdateTask(task *Task) (*Task, error)
DeleteTask(userID string, teamID string, id string) error
FirstUserOfTeam(teamID string) (string, error)
}
+36 -1
View File
@@ -1,6 +1,41 @@
package domain package domain
import "time" import (
"context"
"time"
)
// Clés de contexte passées aux outils lors de l'exécution : identité de
// l'appelant et modèle en cours, pour les outils qui en dépendent
// (ex. scheduler crée une tâche pour l'équipe courante).
type contextKey int
const (
contextKeyUserID contextKey = iota
contextKeyTeamID
contextKeyModelID
)
func WithToolContext(ctx context.Context, userID string, teamID string, modelID string) context.Context {
ctx = context.WithValue(ctx, contextKeyUserID, userID)
ctx = context.WithValue(ctx, contextKeyTeamID, teamID)
return context.WithValue(ctx, contextKeyModelID, modelID)
}
func UserIDFromContext(ctx context.Context) (string, bool) {
v, ok := ctx.Value(contextKeyUserID).(string)
return v, ok
}
func TeamIDFromContext(ctx context.Context) (string, bool) {
v, ok := ctx.Value(contextKeyTeamID).(string)
return v, ok
}
func ModelIDFromContext(ctx context.Context) (string, bool) {
v, ok := ctx.Value(contextKeyModelID).(string)
return v, ok
}
type Tool struct { type Tool struct {
ID string `db:"id" json:"id"` ID string `db:"id" json:"id"`
+7 -1
View File
@@ -52,6 +52,7 @@ func (h *ChatHandler) NewChat(c *echo.Context) error {
userID, userID,
teamID, teamID,
request.AgentID, request.AgentID,
"",
) )
if err != nil { if err != nil {
c.Logger().Error("error creating chat", "error", err.Error()) c.Logger().Error("error creating chat", "error", err.Error())
@@ -120,11 +121,16 @@ func (h *ChatHandler) List(c *echo.Context) error {
page := c.Param("page") page := c.Param("page")
pageInt, _ := strconv.Atoi(page) pageInt, _ := strconv.Atoi(page)
query := c.QueryParam("q") query := c.QueryParam("q")
chats, err := h.chatService.ListChats(userID, teamID, pageInt, query) taskID := c.QueryParam("task")
chats, err := h.chatService.ListChats(userID, teamID, pageInt, query, taskID)
if err != nil { if err != nil {
c.Logger().Error("error listing chats", "error", err) c.Logger().Error("error listing chats", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing chats") return echo.NewHTTPError(http.StatusBadRequest, "error listing chats")
} }
// évite "null" dans la réponse quand il n'y a pas de conversation
if chats == nil {
chats = []*domain.Chat{}
}
return c.JSON(http.StatusOK, chats) return c.JSON(http.StatusOK, chats)
} }
+70
View File
@@ -0,0 +1,70 @@
package handlers
import (
"net/http"
"github.com/labstack/echo/v5"
"trankilou.fr/lassistanoque/backend/internal/domain"
"trankilou.fr/lassistanoque/backend/internal/service/auth"
"trankilou.fr/lassistanoque/backend/internal/service/task"
)
type TaskHandler struct {
taskService *task.Service
}
func NewTaskGroup(prefix string, e *echo.Group, service *task.Service, middlewares ...echo.MiddlewareFunc) *echo.Group {
taskHandler := &TaskHandler{taskService: service}
auth := e.Group(prefix, middlewares...)
auth.GET("/:space", taskHandler.List)
auth.PUT("/:space/:id", taskHandler.Update)
auth.DELETE("/:space/:id", taskHandler.Delete)
return auth
}
func (h *TaskHandler) List(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
tasks, err := h.taskService.ListTasks(userID, teamID)
if err != nil {
c.Logger().Error("error listing tasks", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error listing tasks")
}
// évite "null" dans la réponse quand il n'y a pas de tâche
if tasks == nil {
tasks = []*domain.Task{}
}
return c.JSON(http.StatusOK, tasks)
}
func (h *TaskHandler) Update(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
taskID := c.Param("id")
var taskModel domain.Task
if err := c.Bind(&taskModel); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "error binding request")
}
taskModel.ID = taskID
updated, err := h.taskService.UpdateTask(userID, teamID, &taskModel)
if err != nil {
c.Logger().Error("error updating task", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error updating task")
}
return c.JSON(http.StatusOK, updated)
}
func (h *TaskHandler) Delete(c *echo.Context) error {
userID := c.Get(auth.ContextUserIDKey).(string)
teamID := c.Param("space")
taskID := c.Param("id")
if err := h.taskService.DeleteTask(userID, teamID, taskID); err != nil {
c.Logger().Error("error deleting task", "error", err)
return echo.NewHTTPError(http.StatusBadRequest, "error deleting task")
}
return c.JSON(http.StatusOK, "task deleted")
}
+3
View File
@@ -16,6 +16,7 @@ import (
"trankilou.fr/lassistanoque/backend/internal/service/chat" "trankilou.fr/lassistanoque/backend/internal/service/chat"
"trankilou.fr/lassistanoque/backend/internal/service/provider" "trankilou.fr/lassistanoque/backend/internal/service/provider"
"trankilou.fr/lassistanoque/backend/internal/service/storage" "trankilou.fr/lassistanoque/backend/internal/service/storage"
"trankilou.fr/lassistanoque/backend/internal/service/task"
"trankilou.fr/lassistanoque/backend/internal/service/tool" "trankilou.fr/lassistanoque/backend/internal/service/tool"
"trankilou.fr/lassistanoque/backend/internal/service/user" "trankilou.fr/lassistanoque/backend/internal/service/user"
) )
@@ -44,6 +45,7 @@ type Dependencies struct {
AgentService *agent.Service AgentService *agent.Service
ChatService *chat.Service ChatService *chat.Service
ToolService *tool.Service ToolService *tool.Service
TaskService *task.Service
TokenManager auth.TokenManager TokenManager auth.TokenManager
} }
@@ -87,6 +89,7 @@ func NewRouter(deps Dependencies) *Router {
_ = handlers.NewToolGroup("/tool", api, deps.ToolService, deps.UserService, deps.TokenManager.TokenMiddleware) _ = handlers.NewToolGroup("/tool", api, deps.ToolService, deps.UserService, deps.TokenManager.TokenMiddleware)
_ = handlers.NewTeamGroup("/team", api, deps.UserService, deps.TokenManager.TokenMiddleware) _ = handlers.NewTeamGroup("/team", api, deps.UserService, deps.TokenManager.TokenMiddleware)
_ = handlers.NewChatGroup("/chat", api, deps.ChatService, deps.TokenManager.TokenMiddleware) _ = handlers.NewChatGroup("/chat", api, deps.ChatService, deps.TokenManager.TokenMiddleware)
_ = handlers.NewTaskGroup("/task", api, deps.TaskService, deps.TokenManager.TokenMiddleware)
server := http.Server{ server := http.Server{
Addr: fmt.Sprintf(":%d", cfg.HttpPort), Addr: fmt.Sprintf(":%d", cfg.HttpPort),
@@ -1,2 +0,0 @@
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial;--tw-leading:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-green-300:oklch(87.1% .15 154.449);--color-green-500:oklch(72.3% .219 149.579);--color-green-700:oklch(52.7% .154 150.069);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-700:oklch(50% .134 242.749);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-stone-50:oklch(98.5% .001 106.423);--color-stone-100:oklch(97% .001 106.424);--color-stone-200:oklch(92.3% .003 48.717);--color-stone-300:oklch(86.9% .005 56.366);--color-stone-400:oklch(70.9% .01 56.259);--color-stone-500:oklch(55.3% .013 58.071);--color-stone-600:oklch(44.4% .011 73.639);--color-stone-700:oklch(37.4% .01 67.558);--color-stone-800:oklch(26.8% .007 34.298);--color-stone-900:oklch(21.6% .006 56.043);--color-stone-950:oklch(14.7% .004 49.25);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-bold:700;--radius-sm:.25rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-heightLine truncated
@@ -0,0 +1,2 @@
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial;--tw-leading:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-green-300:oklch(87.1% .15 154.449);--color-green-500:oklch(72.3% .219 149.579);--color-green-700:oklch(52.7% .154 150.069);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-700:oklch(50% .134 242.749);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-stone-50:oklch(98.5% .001 106.423);--color-stone-100:oklch(97% .001 106.424);--color-stone-200:oklch(92.3% .003 48.717);--color-stone-300:oklch(86.9% .005 56.366);--color-stone-400:oklch(70.9% .01 56.259);--color-stone-500:oklch(55.3% .013 58.071);--color-stone-600:oklch(44.4% .011 73.639);--color-stone-700:oklch(37.4% .01 67.558);--color-stone-800:oklch(26.8% .007 34.298);--color-stone-900:oklch(21.6% .006 56.043);--color-stone-950:oklch(14.7% .004 49.25);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-bold:700;--radius-sm:.25rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-heightLine truncated
@@ -0,0 +1 @@
import{t as e}from"./DtfiK5fE.js";var t={createChat:(t,n)=>e.post(`/chat/${t}`,n),createChatMessage:(t,n,r)=>e.postStream(`/chat/${t}/${n}`,r),allChats:(t,n,r,i)=>e.get(`/chat/${t}/all/${n}${r||i?`?${[r&&`q=${encodeURIComponent(r)}`,i&&`task=${i}`].filter(Boolean).join(`&`)}`:``}`),getChat:(t,n)=>e.get(`/chat/${t}/${n}`),subscribe:(t,n)=>e.get(`/chat/${t}/${n}/subscribe`),deleteChat:(t,n)=>e.delete(`/chat/${t}/${n}`)};export{t};
@@ -1 +1 @@
import{B as e,H as t,V as n,ct as r,it as i,nt as a,r as o,t as s}from"./DGrvnoUE.js";var c=class{constructor(e,t){this.status=e,this.body=typeof t==`string`?{message:t}:t||{message:`Error: ${e}`}}toString(){return JSON.stringify(this.body)}},l=class{constructor(e,t){try{new Headers({location:t})}catch{throw Error(`Invalid redirect location ${JSON.stringify(t)}: this string contains characters that cannot be used in HTTP headers`)}this.status=e,this.location=t}},u=class extends Error{constructor(e,t,n){super(n),this.status=e,this.text=t}};new URL(`sveltekit-internal://`);function d(e,t){return e===`/`||t===`ignore`?e:t===`never`?e.endsWith(`/`)?e.slice(0,-1):e:t===`always`&&!e.endsWith(`/`)?e+`/`:e}function f(e){return e.split(`%25`).map(decodeURI).join(`%25`)}function p(e){for(let t in e)e[t]=decodeURIComponent(e[t]);return e}function m({href:e}){return e.split(`#`)[0]}function h(e,t,n,r=!1){let i=new URL(e);Object.defineProperty(i,"searchParams",{value:new Proxy(i.searchParams,{get(e,r){if(r===`get`||r===`getAll`||r===`has`)return(t,...i)=>(n(t),e[r](t,...i));t();let i=Reflect.get(e,r);return typeof i==`function`?i.bind(e):i}}),enumerable:!0,configurable:!0});let a=[`href`,`pathname`,`search`,`toString`,`toJSON`];r&&a.push(`hash`);for(let n of a)Object.defineProperty(i,n,{get(){return t(),e[n]},enumerable:!0,configurable:!0});return i}function g(){}function _(...e){let t=5381;for(let n of e)if(typeof n==`string`){let e=n.length;for(;e;)t=t*33^n.charCodeAt(--e)}else if(ArrayBuffer.isView(n)){let e=new Uint8Array(n.buffer,n.byteOffset,n.byteLength),r=e.length;for(;r;)t=t*33^e[--r]}else throw TypeError(`value must be a string or TypedArray`);return(t>>>0).toString(36)}new TextEncoder;function v(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var ee=window.fetch;window.fetch=(e,t)=>((e instanceof Request?e.method:t?.method||`GET`)!==`GET`&&y.delete(x(e)),ee(e,t));var y=new Map;function b(e,t){let n=x(e,t),r=document.querySelector(n);if(r?.textContent){r.remove();let{body:e,...t}=JSON.parse(r.textContent);r.getAttribute(`data-b64`)!==null&&(e=v(e));let i=r.getAttribute(`data-ttl`);return i&&y.set(n,{body:e,init:t,ttl:1e3*Number(i)}),Promise.resolve(new Response(e,t))}return window.fetch(e,t)}function te(e,t,n){if(y.size>0){let t=x(e,n),r=y.get(t);if(r){if(performance.now()<r.ttl&&[`default`,`force-cache`,`only-if-cached`,void 0].includes(n?.cache))return new Response(r.body,r.init);y.delete(t)}}return window.fetch(t,n)}function x(e,t){let n=`script[data-sveltekit-fetched][data-url=${JSON.stringify(e instanceof Request?e.url:e)}]`;if(t?.headers||t?.body){let e=[];t.headers&&e.push([...new Headers(t.headers)].join(`,`)),t.body&&(typeof t.body==`string`||ArrayBuffer.isView(t.body))&&e.push(t.body),n+=`[data-hash="${_(...e)}"]`}return n}var ne=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/,re=/^\/\((?:[^)]+)\)$/;function ie(e){let t=[];return{pattern:e===`/`||re.test(e)?/^\/$/:RegExp(`^${oe(e).map(e=>{let n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(e);if(n)return t.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),`(?:/([^]*))?`;let r=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(e);if(r)return t.push({name:r[1],matcher:r[2],optional:!0,rest:!1,chained:!0}),`(?:/([^/]+))?`;if(!e)return;let i=e.split(/\[(.+?)\](?!\])/);return`/`+i.map((e,n)=>{if(n%2){if(e.startsWith(`x+`))return ce(String.fromCharCode(parseInt(e.slice(2),16)));if(e.startsWith(`u+`))return ce(String.fromCharCode(...e.slice(2).split(`-`).map(e=>parseInt(e,16))));let[,r,a,o,s]=ne.exec(e);return t.push({name:o,matcher:s,optional:!!r,rest:!!a,chained:a?n===1&&i[0]===``:!1}),a?`([^]*?)`:r?`([^/]*)?`:`([^/]+?)`}return ce(e)}).join(``)}).join(``)}/?$`),params:t}}function ae(e){return e!==``&&!/^\([^)]+\)$/.test(e)}function oe(e){return e.slice(1).split(`/`).filter(ae)}function se(e,t,n){let r={},i=e.slice(1),a=i.filter(e=>e!==void 0),o=0;for(let e=0;e<t.length;e+=1){let s=t[e],c=i[e-o];if(s.chained&&s.rest&&o&&(c=i.slice(e-o,e+1).filter(e=>e).join(`/`),o=0),c===void 0)if(s.rest)c=``;else continue;if(!s.matcher||n[s.matcher](c)){r[s.name]=c;let n=t[e+1],l=i[e+1];n&&!n.rest&&n.optional&&l&&s.chained&&(o=0),!n&&!l&&Object.keys(r).length===a.length&&(o=0);continue}if(s.optional&&s.chained){o++;continue}return}if(!o)return r}function ce(e){return e.normalize().replace(/[[\]]/g,`\\$&`).replace(/%/g,`%25`).replace(/\//g,`%2[Ff]`).replace(/\?/g,`%3[Ff]`).replace(/#/g,`%23`).replace(/[.*+?^${}()|\\]/g,`\\$&`)}function le({nodes:e,server_loads:t,dictionary:n,matchers:r}){let i=new Set(t);return Object.entries(n).map(([t,[n,i,s]])=>{let{pattern:c,params:l}=ie(t),u={id:t,exec:e=>{let t=c.exec(e);if(t)return se(t,l,r)},errors:[1,...s||[]].map(t=>e[t]),layouts:[0,...i||[]].map(o),leaf:a(n)};return u.errors.length=u.layouts.length=Math.max(u.errors.length,u.layouts.length),u});function a(t){let n=t<0;return n&&(t=~t),[n,e[t]]}function o(t){return t===void 0?t:[i.has(t),e[t]]}}function ue(e,t=JSON.parse){try{return t(sessionStorage Line truncated import{B as e,H as t,V as n,ct as r,it as i,nt as a,r as o,t as s}from"./DGrvnoUE.js";var c=class{constructor(e,t){this.status=e,this.body=typeof t==`string`?{message:t}:t||{message:`Error: ${e}`}}toString(){return JSON.stringify(this.body)}},l=class{constructor(e,t){try{new Headers({location:t})}catch{throw Error(`Invalid redirect location ${JSON.stringify(t)}: this string contains characters that cannot be used in HTTP headers`)}this.status=e,this.location=t}},u=class extends Error{constructor(e,t,n){super(n),this.status=e,this.text=t}};new URL(`sveltekit-internal://`);function d(e,t){return e===`/`||t===`ignore`?e:t===`never`?e.endsWith(`/`)?e.slice(0,-1):e:t===`always`&&!e.endsWith(`/`)?e+`/`:e}function f(e){return e.split(`%25`).map(decodeURI).join(`%25`)}function p(e){for(let t in e)e[t]=decodeURIComponent(e[t]);return e}function m({href:e}){return e.split(`#`)[0]}function h(e,t,n,r=!1){let i=new URL(e);Object.defineProperty(i,"searchParams",{value:new Proxy(i.searchParams,{get(e,r){if(r===`get`||r===`getAll`||r===`has`)return(t,...i)=>(n(t),e[r](t,...i));t();let i=Reflect.get(e,r);return typeof i==`function`?i.bind(e):i}}),enumerable:!0,configurable:!0});let a=[`href`,`pathname`,`search`,`toString`,`toJSON`];r&&a.push(`hash`);for(let n of a)Object.defineProperty(i,n,{get(){return t(),e[n]},enumerable:!0,configurable:!0});return i}function g(){}function _(...e){let t=5381;for(let n of e)if(typeof n==`string`){let e=n.length;for(;e;)t=t*33^n.charCodeAt(--e)}else if(ArrayBuffer.isView(n)){let e=new Uint8Array(n.buffer,n.byteOffset,n.byteLength),r=e.length;for(;r;)t=t*33^e[--r]}else throw TypeError(`value must be a string or TypedArray`);return(t>>>0).toString(36)}new TextEncoder;function v(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}var ee=window.fetch;window.fetch=(e,t)=>((e instanceof Request?e.method:t?.method||`GET`)!==`GET`&&y.delete(x(e)),ee(e,t));var y=new Map;function b(e,t){let n=x(e,t),r=document.querySelector(n);if(r?.textContent){r.remove();let{body:e,...t}=JSON.parse(r.textContent);r.getAttribute(`data-b64`)!==null&&(e=v(e));let i=r.getAttribute(`data-ttl`);return i&&y.set(n,{body:e,init:t,ttl:1e3*Number(i)}),Promise.resolve(new Response(e,t))}return window.fetch(e,t)}function te(e,t,n){if(y.size>0){let t=x(e,n),r=y.get(t);if(r){if(performance.now()<r.ttl&&[`default`,`force-cache`,`only-if-cached`,void 0].includes(n?.cache))return new Response(r.body,r.init);y.delete(t)}}return window.fetch(t,n)}function x(e,t){let n=`script[data-sveltekit-fetched][data-url=${JSON.stringify(e instanceof Request?e.url:e)}]`;if(t?.headers||t?.body){let e=[];t.headers&&e.push([...new Headers(t.headers)].join(`,`)),t.body&&(typeof t.body==`string`||ArrayBuffer.isView(t.body))&&e.push(t.body),n+=`[data-hash="${_(...e)}"]`}return n}var ne=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/,re=/^\/\((?:[^)]+)\)$/;function ie(e){let t=[];return{pattern:e===`/`||re.test(e)?/^\/$/:RegExp(`^${oe(e).map(e=>{let n=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(e);if(n)return t.push({name:n[1],matcher:n[2],optional:!1,rest:!0,chained:!0}),`(?:/([^]*))?`;let r=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(e);if(r)return t.push({name:r[1],matcher:r[2],optional:!0,rest:!1,chained:!0}),`(?:/([^/]+))?`;if(!e)return;let i=e.split(/\[(.+?)\](?!\])/);return`/`+i.map((e,n)=>{if(n%2){if(e.startsWith(`x+`))return ce(String.fromCharCode(parseInt(e.slice(2),16)));if(e.startsWith(`u+`))return ce(String.fromCharCode(...e.slice(2).split(`-`).map(e=>parseInt(e,16))));let[,r,a,o,s]=ne.exec(e);return t.push({name:o,matcher:s,optional:!!r,rest:!!a,chained:a?n===1&&i[0]===``:!1}),a?`([^]*?)`:r?`([^/]*)?`:`([^/]+?)`}return ce(e)}).join(``)}).join(``)}/?$`),params:t}}function ae(e){return e!==``&&!/^\([^)]+\)$/.test(e)}function oe(e){return e.slice(1).split(`/`).filter(ae)}function se(e,t,n){let r={},i=e.slice(1),a=i.filter(e=>e!==void 0),o=0;for(let e=0;e<t.length;e+=1){let s=t[e],c=i[e-o];if(s.chained&&s.rest&&o&&(c=i.slice(e-o,e+1).filter(e=>e).join(`/`),o=0),c===void 0)if(s.rest)c=``;else continue;if(!s.matcher||n[s.matcher](c)){r[s.name]=c;let n=t[e+1],l=i[e+1];n&&!n.rest&&n.optional&&l&&s.chained&&(o=0),!n&&!l&&Object.keys(r).length===a.length&&(o=0);continue}if(s.optional&&s.chained){o++;continue}return}if(!o)return r}function ce(e){return e.normalize().replace(/[[\]]/g,`\\$&`).replace(/%/g,`%25`).replace(/\//g,`%2[Ff]`).replace(/\?/g,`%3[Ff]`).replace(/#/g,`%23`).replace(/[.*+?^${}()|\\]/g,`\\$&`)}function le({nodes:e,server_loads:t,dictionary:n,matchers:r}){let i=new Set(t);return Object.entries(n).map(([t,[n,i,s]])=>{let{pattern:c,params:l}=ie(t),u={id:t,exec:e=>{let t=c.exec(e);if(t)return se(t,l,r)},errors:[1,...s||[]].map(t=>e[t]),layouts:[0,...i||[]].map(o),leaf:a(n)};return u.errors.length=u.layouts.length=Math.max(u.errors.length,u.layouts.length),u});function a(t){let n=t<0;return n&&(t=~t),[n,e[t]]}function o(t){return t===void 0?t:[i.has(t),e[t]]}}function ue(e,t=JSON.parse){try{return t(sessionStorage Line truncated
@@ -1 +1 @@
import{t as e}from"./DqlBPR2w.js";var t={providerTypes:()=>e.get(`/provider/providerTypes`),getProviders:t=>e.get(`/provider/${t}`),getProvider:(t,n)=>e.get(`/provider/${t}/${n}`),createProvider:(t,n)=>e.post(`/provider/${t}`,n),updateProvider:(t,n)=>e.put(`/provider/${t}`,n),deleteProvider:(t,n)=>e.delete(`/provider/${t}/${n}`),getAvailableModels:(t,n)=>e.post(`/provider/${t}/avalable-models`,n),getProvidersModels:t=>e.get(`/provider/${t}/models`)};export{t}; import{t as e}from"./DtfiK5fE.js";var t={providerTypes:()=>e.get(`/provider/providerTypes`),getProviders:t=>e.get(`/provider/${t}`),getProvider:(t,n)=>e.get(`/provider/${t}/${n}`),createProvider:(t,n)=>e.post(`/provider/${t}`,n),updateProvider:(t,n)=>e.put(`/provider/${t}`,n),deleteProvider:(t,n)=>e.delete(`/provider/${t}/${n}`),getAvailableModels:(t,n)=>e.post(`/provider/${t}/avalable-models`,n),getProvidersModels:t=>e.get(`/provider/${t}/models`)};export{t};
@@ -0,0 +1 @@
import{t as e}from"./DtfiK5fE.js";var t={register:t=>e.post(`/auth/register`,t),status:()=>e.get(`/auth/status`),login:t=>e.post(`/auth/login`,t),oidcProviders:()=>e.get(`/auth/oidc/providers`,{auth:!1}),oidcLoginUrl:e=>`/api/auth/oidc/login?provider=${encodeURIComponent(e)}`};export{t};
@@ -0,0 +1,4 @@
import{$ as e,A as t,C as n,I as r,K as i,L as a,M as o,N as s,Q as c,R as l,X as u,Z as d,a as f,dt as p,et as m,ft as h,j as g,k as _,vt as v}from"./DGrvnoUE.js";import"./xihTtKlq.js";import{t as y}from"./DtfiK5fE.js";var b={listTasks:e=>y.get(`/task/${e}`),updateTask:(e,t,n)=>y.put(`/task/${e}/${t}`,n),deleteTask:(e,t)=>y.delete(`/task/${e}/${t}`)},x=0,S=m([]),C=(e,t)=>{S.push({id:x++,type:e,text:t,status:`appearing`})},w=e=>e;function T(e){let t=e-1;return t*t*t+1}function E(e,{delay:t=0,duration:n=400,easing:r=w}={}){let i=+getComputedStyle(e).opacity;return{delay:t,duration:n,easing:r,css:e=>`opacity: ${e*i}`}}function D(e,{delay:t=0,duration:n=400,easing:r=T,start:i=0,opacity:a=0}={}){let o=getComputedStyle(e),s=+o.opacity,c=o.transform===`none`?``:o.transform,l=1-i,u=s*(1-a);return{delay:t,duration:n,easing:r,css:(e,t)=>`
transform: ${c} scale(${1-l*t});
opacity: ${s-u*t}
`}}var O=s(`<div class="fixed inset-0 z-50 flex items-center justify-center p-4"><button type="button" class="absolute inset-0 cursor-default bg-black/50" aria-label="Fermer"></button> <div class="relative w-full max-w-sm rounded-lg bg-stone-50 p-4 shadow-xl dark:bg-stone-900" role="dialog" aria-modal="true" aria-labelledby="confirm-dialog-title"><div class="flex items-center gap-3"><div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-600 dark:bg-red-950 dark:text-red-400"><i class="icon-trash-empty"></i></div> <h2 id="confirm-dialog-title" class="text-base font-bold"> </h2></div> <p class="mt-3 text-sm text-stone-600 dark:text-stone-400"> </p> <div class="mt-4 flex justify-end gap-2"><button type="button" class="bt small"> </button> <button type="button" class="bt small danger"> </button></div></div></div>`);function k(r,s){h(s,!0);let m=f(s,`open`,3,!1),y=f(s,`title`,3,``),b=f(s,`message`,3,``),x=f(s,`confirmLabel`,3,`Confirmer`),S=f(s,`cancelLabel`,3,`Annuler`),C=()=>s.onCancel?.(),w=e=>{m()&&e.key===`Escape`&&C()};var T=o();l(`keydown`,u,w);var k=c(T),A=r=>{var o=O(),c=d(o),l=e(c,2),u=d(l),f=e(d(u),2),p=d(f,!0);v(f),v(u);var m=e(u,2),h=d(m,!0);v(m);var _=e(m,2),w=d(_),T=d(w,!0);v(w);var k=e(w,2),A=d(k,!0);v(k),v(_),v(l),v(o),i(()=>{t(p,y()),t(h,b()),t(T,S()),t(A,x())}),a(`click`,c,C),n(3,c,()=>E,()=>({duration:150})),a(`click`,w,C),a(`click`,k,function(...e){s.onConfirm?.apply(this,e)}),n(3,l,()=>D,()=>({duration:150,start:.95})),g(r,o)};_(k,e=>{m()&&e(A)}),g(r,T),p()}r([`click`]);export{C as n,b as r,k as t};
@@ -0,0 +1 @@
import"./BZuNOv8h.js";
@@ -1 +0,0 @@
import{t as e}from"./DqlBPR2w.js";var t={register:t=>e.post(`/auth/register`,t),status:()=>e.get(`/auth/status`),login:t=>e.post(`/auth/login`,t)};export{t};
@@ -1,4 +1,4 @@
import{$ as e,A as t,B as n,D as r,E as i,F as a,H as o,I as s,K as c,L as l,M as u,N as d,P as f,Q as p,R as m,T as h,U as g,X as _,Z as v,_ as y,a as b,at as x,b as ee,c as te,dt as ne,et as S,f as re,ft as ie,h as ae,it as oe,j as C,k as w,m as se,n as ce,nt as T,p as le,q as E,r as ue,u as de,v as fe,vt as D}from"./DGrvnoUE.js";import"./Soo4K-rz.js";import"./xihTtKlq.js";import"./B6JECYQD.js";var pe=Math.min,O=Math.max,me=Math.round,he=Math.floor,k=e=>({x:e,y:e}),A={left:`right`,right:`left`,bottom:`top`,top:`bottom`};function j(e,t,n){return O(e,pe(t,n))}function ge(e,t){return typeof e==`function`?e(t):e}function M(e){return e.split(`-`)[0]}function N(e){return e.split(`-`)[1]}function P(e){return e===`x`?`y`:`x`}function F(e){return e===`y`?`height`:`width`}function I(e){let t=e[0];return t===`t`||t===`b`?`y`:`x`}function _e(e){return P(I(e))}function ve(e,t,n){n===void 0&&(n=!1);let r=N(e),i=_e(e),a=F(i),o=i===`x`?r===(n?`end`:`start`)?`right`:`left`:r===`start`?`bottom`:`top`;return t.reference[a]>t.floating[a]&&(o=Ee(o)),[o,Ee(o)]}function ye(e){let t=Ee(e);return[be(e),t,be(t)]}function be(e){return e.includes(`start`)?e.replace(`start`,`end`):e.replace(`end`,`start`)}var xe=[`left`,`right`],Se=[`right`,`left`],Ce=[`top`,`bottom`],L=[`bottom`,`top`];function we(e,t,n){switch(e){case`top`:case`bottom`:return n?t?Se:xe:t?xe:Se;case`left`:case`right`:return t?Ce:L;default:return[]}}function Te(e,t,n,r){let i=N(e),a=we(M(e),n===`start`,r);return i&&(a=a.map(e=>e+`-`+i),t&&(a=a.concat(a.map(be)))),a}function Ee(e){let t=M(e);return A[t]+e.slice(t.length)}function De(e){return{top:e.top??0,right:e.right??0,bottom:e.bottom??0,left:e.left??0}}function Oe(e){return typeof e==`number`?{top:e,right:e,bottom:e,left:e}:De(e)}function ke(e){let{x:t,y:n,width:r,height:i}=e;return{width:r,height:i,top:n,left:t,right:t+r,bottom:n+i,x:t,y:n}}function Ae(e,t,n){let{reference:r,floating:i}=e,a=I(t),o=_e(t),s=F(o),c=M(t),l=a===`y`,u=r.x+r.width/2-i.width/2,d=r.y+r.height/2-i.height/2,f=r[s]/2-i[s]/2,p;switch(c){case`top`:p={x:u,y:r.y-i.height};break;case`bottom`:p={x:u,y:r.y+r.height};break;case`right`:p={x:r.x+r.width,y:d};break;case`left`:p={x:r.x-i.width,y:d};break;default:p={x:r.x,y:r.y}}let m=N(t);return m&&(p[o]+=f*(m===`end`?1:-1)*(n&&l?-1:1)),p}async function je(e,t){t===void 0&&(t={});let{x:n,y:r,platform:i,rects:a,elements:o,strategy:s}=e,{boundary:c=`clippingAncestors`,rootBoundary:l=`viewport`,elementContext:u=`floating`,altBoundary:d=!1,padding:f=0}=ge(t,e),p=Oe(f),m=o[d?u===`floating`?`reference`:`floating`:u],h=ke(await i.getClippingRect({element:await(i.isElement==null?void 0:i.isElement(m))??!0?m:m.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(o.floating)),boundary:c,rootBoundary:l,strategy:s})),g=u===`floating`?{x:n,y:r,width:a.floating.width,height:a.floating.height}:a.reference,_=await(i.getOffsetParent==null?void 0:i.getOffsetParent(o.floating)),v=await(i.isElement==null?void 0:i.isElement(_))&&await(i.getScale==null?void 0:i.getScale(_))||{x:1,y:1},y=ke(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:o,rect:g,offsetParent:_,strategy:s}):g);return{top:(h.top-y.top+p.top)/v.y,bottom:(y.bottom-h.bottom+p.bottom)/v.y,left:(h.left-y.left+p.left)/v.x,right:(y.right-h.right+p.right)/v.x}}var Me=50,Ne=async(e,t,n)=>{let{placement:r=`bottom`,strategy:i=`absolute`,middleware:a=[],platform:o}=n,s=o.detectOverflow?o:{...o,detectOverflow:je},c=await(o.isRTL==null?void 0:o.isRTL(t)),l=await o.getElementRects({reference:e,floating:t,strategy:i}),{x:u,y:d}=Ae(l,r,c),f=r,p=0,m={};for(let n=0;n<a.length;n++){let h=a[n];if(!h)continue;let{name:g,fn:_}=h,{x:v,y,data:b,reset:x}=await _({x:u,y:d,initialPlacement:r,placement:f,strategy:i,middlewareData:m,rects:l,platform:s,elements:{reference:e,floating:t}});u=v??u,d=y??d,m[g]={...m[g],...b},x&&p<Me&&(p++,typeof x==`object`&&(x.placement&&(f=x.placement),x.rects&&(l=x.rects===!0?await o.getElementRects({reference:e,floating:t,strategy:i}):x.rects),{x:u,y:d}=Ae(l,f,c)),n=-1)}return{x:u,y:d,placement:f,strategy:i,middlewareData:m}},Pe=function(e){return e===void 0&&(e={}),{name:`flip`,options:e,async fn(t){var n;let{placement:r,middlewareData:i,rects:a,initialPlacement:o,platform:s,elements:c}=t,{mainAxis:l=!0,crossAxis:u=!0,fallbackPlacements:d,fallbackStrategy:f=`bestFit`,fallbackAxisSideDirection:p=`none`,flipAlignment:m=!0,...h}=ge(e,t);if((n=i.arrow)!=null&&n.alignmentOffset)return{};let g=M(r),_=I(o),v=M(o)===o,y=await(s.isRTL==null?void 0:s.isRTL(c.floating)),b=d||(v||!m?[Ee(o)]:ye(o)),x=p!==`none`;!d&&x&&b.push(...Te(o,m,p,y));let ee=[o,...b],te=await s.detectOverflow(t,h),ne=[],S=i.flip?.overflows||[];if(l&&ne.push(te[g]),u){let e=ve(r,a,y);ne.push(te[e[0]],te[e[1]])}if(S=[...S,{placement:r,overflows:ne}],!ne.every(e=>e<=0)){let e=(i.flip?.index||0)+1,t=ee[e];if(t&&(u!==`alignment`||_===I(t)||S.every(e=>I(e.placement)!==_||e.overflows[0]>0)))return{daLine truncated import{$ as e,A as t,B as n,D as r,E as i,F as a,H as o,I as s,K as c,L as l,M as u,N as d,P as f,Q as p,R as m,T as h,U as g,X as _,Z as v,_ as y,a as b,at as x,b as ee,c as te,dt as ne,et as S,f as re,ft as ie,h as ae,it as oe,j as C,k as w,m as se,n as ce,nt as T,p as le,q as E,r as ue,u as de,v as fe,vt as D}from"./DGrvnoUE.js";import"./BZuNOv8h.js";import"./xihTtKlq.js";import"./B6JECYQD.js";var pe=Math.min,O=Math.max,me=Math.round,he=Math.floor,k=e=>({x:e,y:e}),A={left:`right`,right:`left`,bottom:`top`,top:`bottom`};function j(e,t,n){return O(e,pe(t,n))}function ge(e,t){return typeof e==`function`?e(t):e}function M(e){return e.split(`-`)[0]}function N(e){return e.split(`-`)[1]}function P(e){return e===`x`?`y`:`x`}function F(e){return e===`y`?`height`:`width`}function I(e){let t=e[0];return t===`t`||t===`b`?`y`:`x`}function _e(e){return P(I(e))}function ve(e,t,n){n===void 0&&(n=!1);let r=N(e),i=_e(e),a=F(i),o=i===`x`?r===(n?`end`:`start`)?`right`:`left`:r===`start`?`bottom`:`top`;return t.reference[a]>t.floating[a]&&(o=Ee(o)),[o,Ee(o)]}function ye(e){let t=Ee(e);return[be(e),t,be(t)]}function be(e){return e.includes(`start`)?e.replace(`start`,`end`):e.replace(`end`,`start`)}var xe=[`left`,`right`],Se=[`right`,`left`],Ce=[`top`,`bottom`],L=[`bottom`,`top`];function we(e,t,n){switch(e){case`top`:case`bottom`:return n?t?Se:xe:t?xe:Se;case`left`:case`right`:return t?Ce:L;default:return[]}}function Te(e,t,n,r){let i=N(e),a=we(M(e),n===`start`,r);return i&&(a=a.map(e=>e+`-`+i),t&&(a=a.concat(a.map(be)))),a}function Ee(e){let t=M(e);return A[t]+e.slice(t.length)}function De(e){return{top:e.top??0,right:e.right??0,bottom:e.bottom??0,left:e.left??0}}function Oe(e){return typeof e==`number`?{top:e,right:e,bottom:e,left:e}:De(e)}function ke(e){let{x:t,y:n,width:r,height:i}=e;return{width:r,height:i,top:n,left:t,right:t+r,bottom:n+i,x:t,y:n}}function Ae(e,t,n){let{reference:r,floating:i}=e,a=I(t),o=_e(t),s=F(o),c=M(t),l=a===`y`,u=r.x+r.width/2-i.width/2,d=r.y+r.height/2-i.height/2,f=r[s]/2-i[s]/2,p;switch(c){case`top`:p={x:u,y:r.y-i.height};break;case`bottom`:p={x:u,y:r.y+r.height};break;case`right`:p={x:r.x+r.width,y:d};break;case`left`:p={x:r.x-i.width,y:d};break;default:p={x:r.x,y:r.y}}let m=N(t);return m&&(p[o]+=f*(m===`end`?1:-1)*(n&&l?-1:1)),p}async function je(e,t){t===void 0&&(t={});let{x:n,y:r,platform:i,rects:a,elements:o,strategy:s}=e,{boundary:c=`clippingAncestors`,rootBoundary:l=`viewport`,elementContext:u=`floating`,altBoundary:d=!1,padding:f=0}=ge(t,e),p=Oe(f),m=o[d?u===`floating`?`reference`:`floating`:u],h=ke(await i.getClippingRect({element:await(i.isElement==null?void 0:i.isElement(m))??!0?m:m.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(o.floating)),boundary:c,rootBoundary:l,strategy:s})),g=u===`floating`?{x:n,y:r,width:a.floating.width,height:a.floating.height}:a.reference,_=await(i.getOffsetParent==null?void 0:i.getOffsetParent(o.floating)),v=await(i.isElement==null?void 0:i.isElement(_))&&await(i.getScale==null?void 0:i.getScale(_))||{x:1,y:1},y=ke(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:o,rect:g,offsetParent:_,strategy:s}):g);return{top:(h.top-y.top+p.top)/v.y,bottom:(y.bottom-h.bottom+p.bottom)/v.y,left:(h.left-y.left+p.left)/v.x,right:(y.right-h.right+p.right)/v.x}}var Me=50,Ne=async(e,t,n)=>{let{placement:r=`bottom`,strategy:i=`absolute`,middleware:a=[],platform:o}=n,s=o.detectOverflow?o:{...o,detectOverflow:je},c=await(o.isRTL==null?void 0:o.isRTL(t)),l=await o.getElementRects({reference:e,floating:t,strategy:i}),{x:u,y:d}=Ae(l,r,c),f=r,p=0,m={};for(let n=0;n<a.length;n++){let h=a[n];if(!h)continue;let{name:g,fn:_}=h,{x:v,y,data:b,reset:x}=await _({x:u,y:d,initialPlacement:r,placement:f,strategy:i,middlewareData:m,rects:l,platform:s,elements:{reference:e,floating:t}});u=v??u,d=y??d,m[g]={...m[g],...b},x&&p<Me&&(p++,typeof x==`object`&&(x.placement&&(f=x.placement),x.rects&&(l=x.rects===!0?await o.getElementRects({reference:e,floating:t,strategy:i}):x.rects),{x:u,y:d}=Ae(l,f,c)),n=-1)}return{x:u,y:d,placement:f,strategy:i,middlewareData:m}},Pe=function(e){return e===void 0&&(e={}),{name:`flip`,options:e,async fn(t){var n;let{placement:r,middlewareData:i,rects:a,initialPlacement:o,platform:s,elements:c}=t,{mainAxis:l=!0,crossAxis:u=!0,fallbackPlacements:d,fallbackStrategy:f=`bestFit`,fallbackAxisSideDirection:p=`none`,flipAlignment:m=!0,...h}=ge(e,t);if((n=i.arrow)!=null&&n.alignmentOffset)return{};let g=M(r),_=I(o),v=M(o)===o,y=await(s.isRTL==null?void 0:s.isRTL(c.floating)),b=d||(v||!m?[Ee(o)]:ye(o)),x=p!==`none`;!d&&x&&b.push(...Te(o,m,p,y));let ee=[o,...b],te=await s.detectOverflow(t,h),ne=[],S=i.flip?.overflows||[];if(l&&ne.push(te[g]),u){let e=ve(r,a,y);ne.push(te[e[0]],te[e[1]])}if(S=[...S,{placement:r,overflows:ne}],!ne.every(e=>e<=0)){let e=(i.flip?.index||0)+1,t=ee[e];if(t&&(u!==`alignment`||_===I(t)||S.every(e=>I(e.placement)!==_||e.overflows[0]>0)))return{daLine truncated
3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0
1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502
0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0
@@ -1,2 +1,2 @@
import{et as e}from"./DGrvnoUE.js";import{t}from"./Soo4K-rz.js";import"./QHwlfjO8.js";var n=e({user:null,status:`loading`}),r=()=>{localStorage.removeItem(`accessToken`),n.status=`unauthenticated`},i=()=>localStorage.getItem(`accessToken`),a=e=>{localStorage.setItem(`accessToken`,e)},o=`/api`,s=class extends Error{status;body;constructor(e,t){super(`API Error ${e}`),this.status=e,this.body=t}};async function c(e,n={}){let{auth:a=!0,headers:c,...l}=n,d={"Content-Type":`application/json`,...c},f=new Headers(d);if(a){let e=i();e&&f.append(`Authorization`,`Bearer ${e}`)}let p=await fetch(`${o}${e}`,{...l,headers:f});if(p.status===401&&(r(),t(`/login`)),!p.ok)throw new s(p.status,await u(p));if(p.status!==204)return p.json()}async function*l(e,n={}){let{auth:a=!0,headers:s,...c}=n,l={"Content-Type":`application/json`,...s},u=new Headers(l);if(a){let e=i();e&&u.append(`Authorization`,`Bearer ${e}`)}let d=await fetch(`${o}${e}`,{...c,headers:u});if(d.status===401&&(r(),t(`/login`)),!d.ok||!d.body)throw Error(`HTTP ${d.status}`);let f=d.body.pipeThrough(new TextDecoderStream).getReader(),p=``;try{for(;;){let{value:e,done:t}=await f.read();if(t)break;p+=e;let n=p.split(` import{et as e}from"./DGrvnoUE.js";import{t}from"./BZuNOv8h.js";import"./CY9OlB4q.js";var n=e({user:null,status:`loading`}),r=()=>{localStorage.removeItem(`accessToken`),n.status=`unauthenticated`},i=()=>localStorage.getItem(`accessToken`),a=e=>{localStorage.setItem(`accessToken`,e)},o=`/api`,s=class extends Error{status;body;constructor(e,t){super(`API Error ${e}`),this.status=e,this.body=t}};async function c(e,n={}){let{auth:a=!0,headers:c,...l}=n,d={"Content-Type":`application/json`,...c},f=new Headers(d);if(a){let e=i();e&&f.append(`Authorization`,`Bearer ${e}`)}let p=await fetch(`${o}${e}`,{...l,headers:f});if(p.status===401&&(r(),t(`/login`)),!p.ok)throw new s(p.status,await u(p));if(p.status!==204)return p.json()}async function*l(e,n={}){let{auth:a=!0,headers:s,...c}=n,l={"Content-Type":`application/json`,...s},u=new Headers(l);if(a){let e=i();e&&u.append(`Authorization`,`Bearer ${e}`)}let d=await fetch(`${o}${e}`,{...c,headers:u});if(d.status===401&&(r(),t(`/login`)),!d.ok||!d.body)throw Error(`HTTP ${d.status}`);let f=d.body.pipeThrough(new TextDecoderStream).getReader(),p=``;try{for(;;){let{value:e,done:t}=await f.read();if(t)break;p+=e;let n=p.split(`
`);p=n.pop()??``;for(let e of n)e.trim()&&(yield JSON.parse(e))}p.trim()&&(yield JSON.parse(p))}finally{f.releaseLock()}}async function u(e){try{return await e.json()}catch{return null}}var d={get:(e,t)=>c(e,{...t,method:`GET`}),post:(e,t,n)=>c(e,{...n,method:`POST`,body:JSON.stringify(t)}),postStream:(e,t,n)=>l(e,{...n,method:`POST`,body:JSON.stringify(t)}),put:(e,t,n)=>c(e,{...n,method:`PUT`,body:JSON.stringify(t)}),delete:(e,t)=>c(e,{...t,method:`DELETE`})};export{a as i,n,r,d as t}; `);p=n.pop()??``;for(let e of n)e.trim()&&(yield JSON.parse(e))}p.trim()&&(yield JSON.parse(p))}finally{f.releaseLock()}}async function u(e){try{return await e.json()}catch{return null}}var d={get:(e,t)=>c(e,{...t,method:`GET`}),post:(e,t,n)=>c(e,{...n,method:`POST`,body:JSON.stringify(t)}),postStream:(e,t,n)=>l(e,{...n,method:`POST`,body:JSON.stringify(t)}),put:(e,t,n)=>c(e,{...n,method:`PUT`,body:JSON.stringify(t)}),delete:(e,t)=>c(e,{...t,method:`DELETE`})};export{a as i,n,r,d as t};
@@ -1 +0,0 @@
import"./Soo4K-rz.js";
@@ -1 +1 @@
import"./DGrvnoUE.js";import{i as e,o as t}from"./Soo4K-rz.js";var n={get data(){return t.data},get error(){return t.error},get form(){return t.form},get params(){return t.params},get route(){return t.route},get state(){return t.state},get status(){return t.status},get url(){return t.url}};e.updated.check;var r=n;export{r as t}; import"./DGrvnoUE.js";import{i as e,o as t}from"./BZuNOv8h.js";var n={get data(){return t.data},get error(){return t.error},get form(){return t.form},get params(){return t.params},get route(){return t.route},get state(){return t.state},get status(){return t.status},get url(){return t.url}};e.updated.check;var r=n;export{r as t};
@@ -1 +0,0 @@
import{t as e}from"./DqlBPR2w.js";var t={createChat:(t,n)=>e.post(`/chat/${t}`,n),createChatMessage:(t,n,r)=>e.postStream(`/chat/${t}/${n}`,r),allChats:(t,n,r)=>e.get(`/chat/${t}/all/${n}${r?`?q=${encodeURIComponent(r)}`:``}`),getChat:(t,n)=>e.get(`/chat/${t}/${n}`),subscribe:(t,n)=>e.get(`/chat/${t}/${n}/subscribe`),deleteChat:(t,n)=>e.delete(`/chat/${t}/${n}`)};export{t};
@@ -1 +1 @@
import{t as e}from"./DqlBPR2w.js";var t={me:()=>e.get(`/user/me`),update:(t,n)=>e.put(`/user/${t}`,n),listAddresses:t=>e.get(`/user/${t}/address`),createAddress:(t,n)=>e.post(`/user/${t}/address`,n),updateAddress:(t,n)=>e.put(`/user/${t}/address`,n),deleteAddress:(t,n)=>e.delete(`/user/${t}/address/${n}`)};export{t}; import{t as e}from"./DtfiK5fE.js";var t={me:()=>e.get(`/user/me`),update:(t,n)=>e.put(`/user/${t}`,n),listAddresses:t=>e.get(`/user/${t}/address`),createAddress:(t,n)=>e.post(`/user/${t}/address`,n),updateAddress:(t,n)=>e.put(`/user/${t}/address`,n),deleteAddress:(t,n)=>e.delete(`/user/${t}/address/${n}`)};export{t};
@@ -0,0 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.BLV5Ey1y.js","../chunks/DGrvnoUE.js","../chunks/xihTtKlq.js","../chunks/DTCALkcP.js","../assets/0.C0TpjoIE.css","../nodes/1.COgG0Fy8.js","../chunks/ffLBjIeN.js","../chunks/BZuNOv8h.js","../nodes/2.wASuVt48.js","../chunks/CY9OlB4q.js","../chunks/DtfiK5fE.js","../chunks/zsRwiIdn.js","../chunks/Cyrg28w2.js","../chunks/BRXBpvt8.js","../nodes/3.CHETzYMH.js","../nodes/4.DkQEi_Qd.js","../chunks/BYWIgY43.js","../chunks/BYYkuYgk.js","../nodes/5.BgmoPtaF.js","../chunks/B6JECYQD.js","../assets/5.nNRn7XR0.css","../nodes/6.B8E4TBNF.js","../chunks/Bht2nTIZ.js","../nodes/7.CJI6is1J.js","../nodes/8.Ds1ONmZq.js","../nodes/9.CYl-UmMc.js","../chunks/BeIYuf23.js","../chunks/6mSXxE57.js","../chunks/DdGy_ePN.js","../nodes/10.D6tOeXzG.js","../nodes/11.DtFjRc5K.js","../nodes/12.D1XIMXHX.js","../nodes/13.C-WGkE4P.js","../chunks/D3MDK1zR.js","../nodes/14.Zp7NcB4T.js","../nodes/15.DBuFCR43.js","../nodes/16.Bwbj6qfw.js","../nodes/17.BV0v_EXc.js","../nodes/18.e37B7XcZ.js","../nodes/19.CdvrW-UN.js","../chunks/BedKI9iq.js","../nodes/20.CPbrVrB7.js"])))=>i.map(i=>d[i]);
import{$ as e,A as t,B as n,F as r,H as i,J as a,K as o,M as s,N as c,Q as l,Z as u,a as d,at as f,c as p,dt as m,ft as h,i as g,it as _,j as v,k as y,nt as b,q as x,r as S,vt as C,w}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";var T=`modulepreload`,E=function(e,t){return new URL(e,t).href},D={},O=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=E(t,n),t=s(t),t in D)return;D[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:T,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},k={},A=c(`<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px"><!></div>`),j=c(`<!> <!>`,1);function M(c,g){h(g,!0);let T=d(g,`components`,23,()=>[]),E=d(g,`data_0`,3,null),D=d(g,`data_1`,3,null),O=d(g,`data_2`,3,null);a(()=>g.stores.page.set(g.page)),x(()=>{g.stores,g.page,g.constructors,T(),g.form,E(),D(),O(),g.stores.page.notify()});let k=_(!1),M=_(!1),N=_(null);S(()=>{let e=g.stores.page.subscribe(()=>{n(k)&&(b(M,!0),i().then(()=>{b(N,document.title||`untitled page`,!0)}))});return b(k,!0),e});let P=f(()=>g.constructors[2]);var F=j(),I=l(F),L=e=>{let t=f(()=>g.constructors[0]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return E()},get form(){return g.form},get params(){return g.page.params},children:(e,t)=>{var r=s(),i=l(r),a=e=>{let t=f(()=>g.constructors[1]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return D()},get form(){return g.form},get params(){return g.page.params},children:(e,t)=>{var r=s(),i=l(r);w(i,()=>n(P),(e,t)=>{p(t(e,{get data(){return O()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[2]=e,()=>T()?.[2])}),v(e,r)},$$slots:{default:!0}}),e=>T()[1]=e,()=>T()?.[1])}),v(e,r)},o=e=>{let t=f(()=>g.constructors[1]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return D()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[1]=e,()=>T()?.[1])}),v(e,r)};y(i,e=>{g.constructors[2]?e(a):e(o,-1)}),v(e,r)},$$slots:{default:!0}}),e=>T()[0]=e,()=>T()?.[0])}),v(e,r)},R=e=>{let t=f(()=>g.constructors[0]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return E()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[0]=e,()=>T()?.[0])}),v(e,r)};y(I,e=>{g.constructors[1]?e(L):e(R,-1)});var z=e(I,2),B=e=>{var i=A(),a=u(i),s=e=>{var i=r();o(()=>t(i,n(N))),v(e,i)};y(a,e=>{n(M)&&e(s)}),C(i),v(e,i)};y(z,e=>{n(k)&&e(B)}),v(c,F),m()}var N=g(M),P=[()=>O(()=>import(`../nodes/0.BLV5Ey1y.js`),__vite__mapDeps([0,1,2,3,4]),import.meta.url),()=>O(()=>import(`../nodes/1.COgG0Fy8.js`),__vite__mapDeps([5,1,2,6,7]),import.meta.url),()=>O(()=>import(`../nodes/2.wASuVt48.js`),__vite__mapDeps([8,1,7,2,3,6,9,10,11,12,13]),import.meta.url),()=>O(()=>import(`../nodes/3.CHETzYMH.js`),__vite__mapDeps([14,1,7,2,9,12]),import.meta.url),()=>O(()=>import(`../nodes/4.DkQEi_Qd.js`),__vite__mapDeps([15,1,7,2,9,16,17,10]),import.meta.url),()=>O(()=>import(`../nodes/5.BgmoPtaF.js`),__vite__mapDeps([18,1,2,6,7,16,17,10,9,19,20]),import.meta.url),()=>O(()=>import(`../nodes/6.B8E4TBNF.js`),__vite__mapDeps([21,1,7,2,9,17,10,22]),import.meta.url),()=>O(()=>import(`../nodes/7.CJI6is1J.js`),__vite__mapDeps([23,1,2]),import.meta.url),()=>O(()=>import(`../nodes/8.Ds1ONmZq.js`),__vite__mapDeps([24,1,2]),import.meta.url),()=>O(()=>import(`../nodes/9.CYl-UmMc.js`),__vite__mapDeps([25,1,2,10,7,9,12,26,27,28,19]),import.meta.url),()=>O(()=>import(`../nodes/10.D6tOeXzG.js`),__vite__mapDeps([29,1,2]),import.meta.url),()=>O(()=>import(`../nodes/11.DtFjRc5K.js`),__vite__mapDeps([30,1,2]),import.meta.url),()=>O(()=>import(`../nodes/12.D1XIMXHX.js`),__vite__mapDeps([31,1,2]),import.meta.url),()=>O(()=>import(`../nodes/13.C-WGkE4P.js`),__vite__mapDeps([32,1,2,26,10,7,9,27,28,19,33]),import.meta.url),()=>O(()=>import(`../nodes/14.Zp7NcB4T.js`),__vite__mapDeps([34,1,2]),import.meta.url),()=>O(()=>import(`../nodes/15.DBuFCR43.js`),__vite__mapDeps([35,1,2,10,7,9,27]),import.meta.url),()Line truncated
@@ -1,2 +0,0 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.C86e0tcA.js","../chunks/DGrvnoUE.js","../chunks/xihTtKlq.js","../chunks/DTCALkcP.js","../assets/0.BKrS386W.css","../nodes/1.B34i4hHQ.js","../chunks/5WAfNqs_.js","../chunks/Soo4K-rz.js","../nodes/2.BGKAfrIz.js","../chunks/QHwlfjO8.js","../chunks/DqlBPR2w.js","../chunks/DyF3myvh.js","../chunks/Cyrg28w2.js","../chunks/BRXBpvt8.js","../nodes/3.7A57L7YY.js","../nodes/4.Dd2s_2MN.js","../chunks/BYWIgY43.js","../chunks/guSkOB4x.js","../nodes/5.At5j5jjs.js","../chunks/B6JECYQD.js","../assets/5.nNRn7XR0.css","../nodes/6.BBY8N1lq.js","../nodes/7.CJI6is1J.js","../nodes/8.Ds1ONmZq.js","../nodes/9.Bt_qXBPf.js","../chunks/BI_fD_HY.js","../chunks/6mSXxE57.js","../chunks/CUminYLk.js","../nodes/10.D6tOeXzG.js","../nodes/11.DtFjRc5K.js","../nodes/12.D1XIMXHX.js","../nodes/13.Dxxi1Ijq.js","../chunks/D3MDK1zR.js","../nodes/14.Zp7NcB4T.js","../nodes/15.CqwsYGvL.js","../nodes/16.Bwbj6qfw.js","../nodes/17.CRbsg29O.js","../nodes/18.DRjMAC4S.js","../nodes/19.Bxx8Nj5U.js","../chunks/CvbyM2Rc.js","../nodes/20.BwhsqgTX.js"])))=>i.map(i=>d[i]);
import{$ as e,A as t,B as n,F as r,H as i,J as a,K as o,M as s,N as c,Q as l,Z as u,a as d,at as f,c as p,dt as m,ft as h,i as g,it as _,j as v,k as y,nt as b,q as x,r as S,vt as C,w}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";var T=`modulepreload`,E=function(e,t){return new URL(e,t).href},D={},O=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=E(t,n),t=s(t),t in D)return;D[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:T,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},k={},A=c(`<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px"><!></div>`),j=c(`<!> <!>`,1);function M(c,g){h(g,!0);let T=d(g,`components`,23,()=>[]),E=d(g,`data_0`,3,null),D=d(g,`data_1`,3,null),O=d(g,`data_2`,3,null);a(()=>g.stores.page.set(g.page)),x(()=>{g.stores,g.page,g.constructors,T(),g.form,E(),D(),O(),g.stores.page.notify()});let k=_(!1),M=_(!1),N=_(null);S(()=>{let e=g.stores.page.subscribe(()=>{n(k)&&(b(M,!0),i().then(()=>{b(N,document.title||`untitled page`,!0)}))});return b(k,!0),e});let P=f(()=>g.constructors[2]);var F=j(),I=l(F),L=e=>{let t=f(()=>g.constructors[0]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return E()},get form(){return g.form},get params(){return g.page.params},children:(e,t)=>{var r=s(),i=l(r),a=e=>{let t=f(()=>g.constructors[1]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return D()},get form(){return g.form},get params(){return g.page.params},children:(e,t)=>{var r=s(),i=l(r);w(i,()=>n(P),(e,t)=>{p(t(e,{get data(){return O()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[2]=e,()=>T()?.[2])}),v(e,r)},$$slots:{default:!0}}),e=>T()[1]=e,()=>T()?.[1])}),v(e,r)},o=e=>{let t=f(()=>g.constructors[1]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return D()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[1]=e,()=>T()?.[1])}),v(e,r)};y(i,e=>{g.constructors[2]?e(a):e(o,-1)}),v(e,r)},$$slots:{default:!0}}),e=>T()[0]=e,()=>T()?.[0])}),v(e,r)},R=e=>{let t=f(()=>g.constructors[0]);var r=s(),i=l(r);w(i,()=>n(t),(e,t)=>{p(t(e,{get data(){return E()},get form(){return g.form},get params(){return g.page.params}}),e=>T()[0]=e,()=>T()?.[0])}),v(e,r)};y(I,e=>{g.constructors[1]?e(L):e(R,-1)});var z=e(I,2),B=e=>{var i=A(),a=u(i),s=e=>{var i=r();o(()=>t(i,n(N))),v(e,i)};y(a,e=>{n(M)&&e(s)}),C(i),v(e,i)};y(z,e=>{n(k)&&e(B)}),v(c,F),m()}var N=g(M),P=[()=>O(()=>import(`../nodes/0.C86e0tcA.js`),__vite__mapDeps([0,1,2,3,4]),import.meta.url),()=>O(()=>import(`../nodes/1.B34i4hHQ.js`),__vite__mapDeps([5,1,2,6,7]),import.meta.url),()=>O(()=>import(`../nodes/2.BGKAfrIz.js`),__vite__mapDeps([8,1,7,2,3,6,9,10,11,12,13]),import.meta.url),()=>O(()=>import(`../nodes/3.7A57L7YY.js`),__vite__mapDeps([14,1,7,2,9,12]),import.meta.url),()=>O(()=>import(`../nodes/4.Dd2s_2MN.js`),__vite__mapDeps([15,1,7,2,9,16,17,10]),import.meta.url),()=>O(()=>import(`../nodes/5.At5j5jjs.js`),__vite__mapDeps([18,1,2,6,7,16,17,10,9,19,20]),import.meta.url),()=>O(()=>import(`../nodes/6.BBY8N1lq.js`),__vite__mapDeps([21,1,7,2,9,17,10]),import.meta.url),()=>O(()=>import(`../nodes/7.CJI6is1J.js`),__vite__mapDeps([22,1,2]),import.meta.url),()=>O(()=>import(`../nodes/8.Ds1ONmZq.js`),__vite__mapDeps([23,1,2]),import.meta.url),()=>O(()=>import(`../nodes/9.Bt_qXBPf.js`),__vite__mapDeps([24,1,2,10,7,9,12,25,26,27,19]),import.meta.url),()=>O(()=>import(`../nodes/10.D6tOeXzG.js`),__vite__mapDeps([28,1,2]),import.meta.url),()=>O(()=>import(`../nodes/11.DtFjRc5K.js`),__vite__mapDeps([29,1,2]),import.meta.url),()=>O(()=>import(`../nodes/12.D1XIMXHX.js`),__vite__mapDeps([30,1,2]),import.meta.url),()=>O(()=>import(`../nodes/13.Dxxi1Ijq.js`),__vite__mapDeps([31,1,2,25,10,7,9,26,27,19,32]),import.meta.url),()=>O(()=>import(`../nodes/14.Zp7NcB4T.js`),__vite__mapDeps([33,1,2]),import.meta.url),()=>O(()=>import(`../nodes/15.CqwsYGvL.js`),__vite__mapDeps([34,1,2,10,7,9,26]),import.meta.url),()=>OLine truncated
@@ -0,0 +1 @@
import{c as e,r as t}from"../chunks/BZuNOv8h.js";export{e as load_css,t as start};
@@ -1 +0,0 @@
import{c as e,r as t}from"../chunks/Soo4K-rz.js";export{e as load_css,t as start};
@@ -1 +1 @@
import{$ as e,A as t,K as n,N as r,Q as i,Z as a,dt as o,ft as s,j as c,vt as l}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as u}from"../chunks/5WAfNqs_.js";var d=r(`<h1> </h1> <p> </p>`,1);function f(r,f){s(f,!0);var p=d(),m=i(p),h=a(m,!0);l(m);var g=e(m,2),_=a(g,!0);l(g),n(()=>{t(h,u.status),t(_,u.error?.message)}),c(r,p),o()}export{f as component}; import{$ as e,A as t,K as n,N as r,Q as i,Z as a,dt as o,ft as s,j as c,vt as l}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as u}from"../chunks/ffLBjIeN.js";var d=r(`<h1> </h1> <p> </p>`,1);function f(r,f){s(f,!0);var p=d(),m=i(p),h=a(m,!0);l(m);var g=e(m,2),_=a(g,!0);l(g),n(()=>{t(h,u.status),t(_,u.error?.message)}),c(r,p),o()}export{f as component};
@@ -1 +1 @@
import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,l as E,nt as D,p as O,u as k,vt as A}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as j}from"../chunks/BI_fD_HY.js";import{n as M,t as N}from"../chunks/6mSXxE57.js";import{t as P}from"../chunks/CUminYLk.js";import{n as F}from"../chunks/D3MDK1zR.js";var I=y({load:()=>L}),L=async({params:e})=>({title:`Paramétrage : Modèles`,back:`../settings`,space:e.space,providerTypes:await j.providerTypes(),providers:await j.getProviders(e.space)}),R=l(`<li><label><input type="checkbox"/> </label></li>`),z=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché"/> <!></div> <div class="formelement"><label for="type" class="block my-1 flex-1">Type</label> <!> <!></div> <div class="formelement"><label for="baseUrl">URL</label> <input id="baseUrl" type="text" class="textinput" placeholder="http://127.0.0.1:8080/v1" autocomplete="off"/> <!></div> <div class="formelement"><label for="apiKey">Clé API</label> <input id="apiKey" type="password" class="textinput" placeholder="clé API (optionnel)" autocomplete="new-password"/> <!></div> <div class="formelement"><label for="models">Models</label> <button class="bt small">Afficher les modèles disponibles</button> <ol class="ml-2"></ol> <div><!></div></div> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function B(a,l){S(l,!0);let u=_(l,`item`,7),p=C(x(u().models.split(`|`))),m=C(x(u().models.split(`|`).map(e=>({value:e,selected:!0})))),y=new M,F=e=>{e.focus()},I=e=>{e.preventDefault(),u().models=n(p).join(`|`),l.onSave(u())},L=e=>{e.preventDefault(),l.onCancel()},B=e=>{e.preventDefault(),y.clear(),j.getAvailableModels(u().teamId,u()).then(e=>{D(m,e.map(e=>({value:e,selected:n(p).includes(e)})),!0)}).catch(e=>{y.set(`models`,e)})},V=()=>{D(p,n(m).filter(e=>e.selected).map(e=>e.value),!0)};var H=z(),U=h(H),W=h(U),G=h(W),K=e(h(G),2);O(K),i(()=>k(K,()=>u().name,e=>u().name=e)),v(K,e=>F?.(e));var ee=e(K,2);N(ee,{key:`name`,get errors(){return l.errors}}),A(G);var q=e(G,2),te=e(h(q),2);P(te,{get items(){return l.providerTypes},valueMode:`id`,get value(){return u().type},set value(e){u().type=e}});var ne=e(te,2);N(ne,{key:`type`,get errors(){return l.errors}}),A(q);var J=e(q,2),Y=e(h(J),2);O(Y);var re=e(Y,2);N(re,{key:`baseUrl`,get errors(){return l.errors}}),A(J);var X=e(J,2),Z=e(h(X),2);O(Z);var ie=e(Z,2);N(ie,{key:`apiKey`,get errors(){return l.errors}}),A(X);var Q=e(X,2),ae=e(h(Q),2),$=e(ae,2);r($,21,()=>n(m),e=>e.value,(r,i,a)=>{var l=c(),u=d(l),f=r=>{var a=R(),c=h(a),l=h(c);O(l);var u=e(l);A(c),A(a),o(()=>t(u,` ${n(i).value??``}`)),s(`change`,l,V),E(l,()=>n(i).selected,e=>n(i).selected=e),w(r,a)};T(u,e=>{n(i).value&&e(f)}),w(r,l)}),A($);var oe=e($,2),se=h(oe);N(se,{key:`models`,get errors(){return y}}),A(oe),A(Q);var ce=e(Q,2),le=h(ce);g(2),A(ce),A(W),A(U),A(H),f(`submit`,W,I),s(`change`,W,()=>{l.errors.clear()}),k(Y,()=>u().baseUrl,e=>u().baseUrl=e),k(Z,()=>u().apiKey,e=>u().apiKey=e),s(`click`,ae,B),s(`click`,le,L),w(a,H),b()}a([`change`,`click`]);var V=l(`<button class="rounded w-full border border-dashed p-2 border-stone-500 cursor-pointer" tabindex="0"><i class="icon-plus"></i> Ajouter un fournisseur</button>`),H=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span> <span class="text-stone-500"> </span></div> <button class="bt small mx-1" aria-label="Modifier"><i class="icon-edit"></i></button> <button class="bt small mx-1" aria-label="Supprimer"><i class="icon-trash-empty"></i></button></div>`),U=l(`<div class="container"><!> <!></div>`);function W(i,a){S(a,!0);let l=C(x(p(()=>a.data.providers))),g=C(!1),_=C(null),v=C(x({})),y=new M,E=()=>{n(_)||(y.clear(),D(v,{},!0),n(v).models=``,D(g,!0))},O=()=>{D(g,!1)},k=e=>{e.name||y.set(`name`,`Le nom est obligatoire !`),e.type||y.set(`type`,`Le type est obligatoire !`),e.baseUrl&&!F(e.baseUrl)&&y.set(`baseUrl`,`Mauvaise URL !`),y.size===0&&j.createProvider(a.data.space,e).then(e=>{n(l).push(e),D(g,!1),D(v,{},!0)}).catch(e=>{console.log(e)})},N=()=>{D(_,null),D(v,{},!0)},P=e=>{e.name||y.set(`name`,`Le nom est obligatoire !`),e.type||y.set(`type`,`Le type est obligatoire !`),e.baseUrl&&!F(e.baseUrl)&&y.set(`baseUrl`,`Mauvaise URL !`),y.size===0&&j.updateProvider(a.data.space,e).then(e=>{D(l,n(l).map(t=>e.id===t.id?e:t),!0),D(_,null),D(v,{},!0)}).catch(e=>{console.log(e)})},I=async e=>{y.clear(),!n(g)&&j.getProvider(a.data.space,e).then(t=>{D(l,n(l).map(n=>n.id===e?t:n),!0),D(_,e,!0)})},L=e=>{j.deleteProvider(a.data.space,e).then(()=>{D(l,n(l).filter(t=>t.id!==e),!0)}).catch(e=>{console.log(e)})},R=e=>{e.key===`Escape`&&N()};var z=U();f(`keydown Line truncated import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,l as E,nt as D,p as O,u as k,vt as A}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as j}from"../chunks/BeIYuf23.js";import{n as M,t as N}from"../chunks/6mSXxE57.js";import{t as P}from"../chunks/DdGy_ePN.js";import{n as F}from"../chunks/D3MDK1zR.js";var I=y({load:()=>L}),L=async({params:e})=>({title:`Paramétrage : Modèles`,back:`../settings`,space:e.space,providerTypes:await j.providerTypes(),providers:await j.getProviders(e.space)}),R=l(`<li><label><input type="checkbox"/> </label></li>`),z=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché"/> <!></div> <div class="formelement"><label for="type" class="block my-1 flex-1">Type</label> <!> <!></div> <div class="formelement"><label for="baseUrl">URL</label> <input id="baseUrl" type="text" class="textinput" placeholder="http://127.0.0.1:8080/v1" autocomplete="off"/> <!></div> <div class="formelement"><label for="apiKey">Clé API</label> <input id="apiKey" type="password" class="textinput" placeholder="clé API (optionnel)" autocomplete="new-password"/> <!></div> <div class="formelement"><label for="models">Models</label> <button class="bt small">Afficher les modèles disponibles</button> <ol class="ml-2"></ol> <div><!></div></div> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function B(a,l){S(l,!0);let u=_(l,`item`,7),p=C(x(u().models.split(`|`))),m=C(x(u().models.split(`|`).map(e=>({value:e,selected:!0})))),y=new M,F=e=>{e.focus()},I=e=>{e.preventDefault(),u().models=n(p).join(`|`),l.onSave(u())},L=e=>{e.preventDefault(),l.onCancel()},B=e=>{e.preventDefault(),y.clear(),j.getAvailableModels(u().teamId,u()).then(e=>{D(m,e.map(e=>({value:e,selected:n(p).includes(e)})),!0)}).catch(e=>{y.set(`models`,e)})},V=()=>{D(p,n(m).filter(e=>e.selected).map(e=>e.value),!0)};var H=z(),U=h(H),W=h(U),G=h(W),K=e(h(G),2);O(K),i(()=>k(K,()=>u().name,e=>u().name=e)),v(K,e=>F?.(e));var ee=e(K,2);N(ee,{key:`name`,get errors(){return l.errors}}),A(G);var q=e(G,2),te=e(h(q),2);P(te,{get items(){return l.providerTypes},valueMode:`id`,get value(){return u().type},set value(e){u().type=e}});var ne=e(te,2);N(ne,{key:`type`,get errors(){return l.errors}}),A(q);var J=e(q,2),Y=e(h(J),2);O(Y);var re=e(Y,2);N(re,{key:`baseUrl`,get errors(){return l.errors}}),A(J);var X=e(J,2),Z=e(h(X),2);O(Z);var ie=e(Z,2);N(ie,{key:`apiKey`,get errors(){return l.errors}}),A(X);var Q=e(X,2),ae=e(h(Q),2),$=e(ae,2);r($,21,()=>n(m),e=>e.value,(r,i,a)=>{var l=c(),u=d(l),f=r=>{var a=R(),c=h(a),l=h(c);O(l);var u=e(l);A(c),A(a),o(()=>t(u,` ${n(i).value??``}`)),s(`change`,l,V),E(l,()=>n(i).selected,e=>n(i).selected=e),w(r,a)};T(u,e=>{n(i).value&&e(f)}),w(r,l)}),A($);var oe=e($,2),se=h(oe);N(se,{key:`models`,get errors(){return y}}),A(oe),A(Q);var ce=e(Q,2),le=h(ce);g(2),A(ce),A(W),A(U),A(H),f(`submit`,W,I),s(`change`,W,()=>{l.errors.clear()}),k(Y,()=>u().baseUrl,e=>u().baseUrl=e),k(Z,()=>u().apiKey,e=>u().apiKey=e),s(`click`,ae,B),s(`click`,le,L),w(a,H),b()}a([`change`,`click`]);var V=l(`<button class="rounded w-full border border-dashed p-2 border-stone-500 cursor-pointer" tabindex="0"><i class="icon-plus"></i> Ajouter un fournisseur</button>`),H=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span> <span class="text-stone-500"> </span></div> <button class="bt small mx-1" aria-label="Modifier"><i class="icon-edit"></i></button> <button class="bt small mx-1" aria-label="Supprimer"><i class="icon-trash-empty"></i></button></div>`),U=l(`<div class="container"><!> <!></div>`);function W(i,a){S(a,!0);let l=C(x(p(()=>a.data.providers))),g=C(!1),_=C(null),v=C(x({})),y=new M,E=()=>{n(_)||(y.clear(),D(v,{},!0),n(v).models=``,D(g,!0))},O=()=>{D(g,!1)},k=e=>{e.name||y.set(`name`,`Le nom est obligatoire !`),e.type||y.set(`type`,`Le type est obligatoire !`),e.baseUrl&&!F(e.baseUrl)&&y.set(`baseUrl`,`Mauvaise URL !`),y.size===0&&j.createProvider(a.data.space,e).then(e=>{n(l).push(e),D(g,!1),D(v,{},!0)}).catch(e=>{console.log(e)})},N=()=>{D(_,null),D(v,{},!0)},P=e=>{e.name||y.set(`name`,`Le nom est obligatoire !`),e.type||y.set(`type`,`Le type est obligatoire !`),e.baseUrl&&!F(e.baseUrl)&&y.set(`baseUrl`,`Mauvaise URL !`),y.size===0&&j.updateProvider(a.data.space,e).then(e=>{D(l,n(l).map(t=>e.id===t.id?e:t),!0),D(_,null),D(v,{},!0)}).catch(e=>{console.log(e)})},I=async e=>{y.clear(),!n(g)&&j.getProvider(a.data.space,e).then(t=>{D(l,n(l).map(n=>n.id===e?t:n),!0),D(_,e,!0)})},L=e=>{j.deleteProvider(a.data.space,e).then(()=>{D(l,n(l).filter(t=>t.id!==e),!0)}).catch(e=>{console.log(e)})},R=e=>{e.key===`Escape`&&N()};var z=U();f(`keydown Line truncated
@@ -1 +1 @@
import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,l as E,m as D,nt as O,p as k,r as A,u as j,vt as M}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as N}from"../chunks/DqlBPR2w.js";import{n as P,t as F}from"../chunks/6mSXxE57.js";var I={getTools:e=>N.get(`/tool/${e}`),getTool:(e,t)=>N.get(`/tool/${e}/${t}`),getToolParams:(e,t)=>N.get(`/tool/${e}/${t}/params`),createTool:(e,t)=>N.post(`/tool/${e}`,t),updateTool:(e,t)=>N.put(`/tool/${e}`,t)},L=y({load:()=>R}),R=async({params:e})=>({title:`Paramétrage : Outils`,back:`../settings`,space:e.space,tools:await I.getTools(e.space)}),z=l(`<input id="enabled" type="checkbox" class="checkboxinput"/>`),B=l(`<input type="number" class="textinput"/>`),V=l(`<input class="textinput"/>`),H=l(`<div class="formelement"><label> </label> <!> <!></div>`),U=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché" disabled=""/> <!></div> <div class="formelement"><label for="enabled">Actif</label> <input id="enabled" type="checkbox" class="checkboxinput"/> <!></div> <!> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function W(a,c){S(c,!0);let l=_(c,`item`,7),u=x(p(()=>l())),d=C(x([])),m=new P;A(async()=>{O(d,await I.getToolParams(l().teamId,l().id),!0),m=new P(Object.entries(JSON.parse(l().configuration)))});let y=e=>{e.focus()},N=e=>{e.preventDefault(),l().configuration=JSON.stringify(Object.fromEntries(m)),c.onSave(l())},L=e=>{e.preventDefault(),c.onCancel()};var R=U(),W=h(R),G=h(W),K=h(G),q=e(h(K),2);k(q),i(()=>j(q,()=>u.name,e=>u.name=e)),v(q,e=>y?.(e));var J=e(q,2);F(J,{key:`name`,get errors(){return c.errors}}),M(K);var Y=e(K,2),X=e(h(Y),2);k(X);var Z=e(X,2);F(Z,{key:`baseUrl`,get errors(){return c.errors}}),M(Y);var Q=e(Y,2);r(Q,17,()=>n(d),e=>e.name,(r,i)=>{var a=H(),s=h(a),l=h(s,!0);M(s);var u=e(s,2),d=e=>{var t=z();k(t),E(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)},f=e=>{var t=B();k(t),o(()=>{D(t,`id`,n(i).name),D(t,`placeholder`,n(i).description)}),j(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)},p=e=>{var t=V();k(t),o(()=>{D(t,`id`,n(i).name),D(t,`placeholder`,n(i).description)}),j(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)};T(u,e=>{n(i).type==`bool`?e(d):n(i).type==`int`?e(f,1):e(p,-1)});var g=e(u,2);F(g,{key:`baseUrl`,get errors(){return c.errors}}),M(a),o(()=>{D(s,`for`,n(i).name),t(l,n(i).name)}),w(r,a)});var $=e(Q,2),ee=h($);g(2),M($),M(G),M(W),M(R),f(`submit`,G,N),s(`change`,G,()=>{c.errors.clear()}),E(X,()=>u.enabled,e=>u.enabled=e),s(`click`,ee,L),w(a,R),b()}a([`change`,`click`]);var G=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span> <span class="text-stone-500"> </span></div> <button class="bt small mx-1" aria-label="Modifier"><i class="icon-edit"></i></button></div>`),K=l(`<div class="container"></div>`);function q(i,a){S(a,!0);let l=C(x(p(()=>a.data.tools))),g=C(null),_=new P,v=()=>{O(g,null)},y=e=>{_.size===0&&I.updateTool(a.data.space,e).then(e=>{O(l,n(l).map(t=>e.id===t.id?e:t),!0),O(g,null)}).catch(e=>{console.log(e)})},E=async e=>{_.clear(),I.getTool(a.data.space,e).then(t=>{O(l,n(l).map(n=>n.id===e?t:n),!0),O(g,e,!0)})},D=e=>{e.key===`Escape`&&v()};var k=K();f(`keydown`,m,D),r(k,21,()=>n(l),e=>e.id,(r,i)=>{var a=c(),l=d(a),f=e=>{var t=c(),r=d(t);u(r,()=>n(i).id,e=>{W(e,{get item(){return n(i)},get errors(){return _},onSave:y,onCancel:v})}),w(e,t)},p=r=>{var a=G(),c=h(a),l=h(c),u=h(l,!0);M(l);var d=e(l,2),f=h(d);M(d),M(c);var p=e(c,2);M(a),o(()=>{t(u,n(i).name),t(f,`(${n(i).enabled??``})`)}),s(`click`,p,()=>E(n(i).id)),w(r,a)};T(l,e=>{n(g)===n(i).id?e(f):e(p,-1)}),w(r,a)}),M(k),w(i,k),b()}a([`click`]);export{q as component,L as universal}; import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,l as E,m as D,nt as O,p as k,r as A,u as j,vt as M}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as N}from"../chunks/DtfiK5fE.js";import{n as P,t as F}from"../chunks/6mSXxE57.js";var I={getTools:e=>N.get(`/tool/${e}`),getTool:(e,t)=>N.get(`/tool/${e}/${t}`),getToolParams:(e,t)=>N.get(`/tool/${e}/${t}/params`),createTool:(e,t)=>N.post(`/tool/${e}`,t),updateTool:(e,t)=>N.put(`/tool/${e}`,t)},L=y({load:()=>R}),R=async({params:e})=>({title:`Paramétrage : Outils`,back:`../settings`,space:e.space,tools:await I.getTools(e.space)}),z=l(`<input id="enabled" type="checkbox" class="checkboxinput"/>`),B=l(`<input type="number" class="textinput"/>`),V=l(`<input class="textinput"/>`),H=l(`<div class="formelement"><label> </label> <!> <!></div>`),U=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché" disabled=""/> <!></div> <div class="formelement"><label for="enabled">Actif</label> <input id="enabled" type="checkbox" class="checkboxinput"/> <!></div> <!> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function W(a,c){S(c,!0);let l=_(c,`item`,7),u=x(p(()=>l())),d=C(x([])),m=new P;A(async()=>{O(d,await I.getToolParams(l().teamId,l().id),!0),m=new P(Object.entries(JSON.parse(l().configuration)))});let y=e=>{e.focus()},N=e=>{e.preventDefault(),l().configuration=JSON.stringify(Object.fromEntries(m)),c.onSave(l())},L=e=>{e.preventDefault(),c.onCancel()};var R=U(),W=h(R),G=h(W),K=h(G),q=e(h(K),2);k(q),i(()=>j(q,()=>u.name,e=>u.name=e)),v(q,e=>y?.(e));var J=e(q,2);F(J,{key:`name`,get errors(){return c.errors}}),M(K);var Y=e(K,2),X=e(h(Y),2);k(X);var Z=e(X,2);F(Z,{key:`baseUrl`,get errors(){return c.errors}}),M(Y);var Q=e(Y,2);r(Q,17,()=>n(d),e=>e.name,(r,i)=>{var a=H(),s=h(a),l=h(s,!0);M(s);var u=e(s,2),d=e=>{var t=z();k(t),E(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)},f=e=>{var t=B();k(t),o(()=>{D(t,`id`,n(i).name),D(t,`placeholder`,n(i).description)}),j(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)},p=e=>{var t=V();k(t),o(()=>{D(t,`id`,n(i).name),D(t,`placeholder`,n(i).description)}),j(t,()=>m.get(n(i).name)??``,e=>m.set(n(i).name,e)),w(e,t)};T(u,e=>{n(i).type==`bool`?e(d):n(i).type==`int`?e(f,1):e(p,-1)});var g=e(u,2);F(g,{key:`baseUrl`,get errors(){return c.errors}}),M(a),o(()=>{D(s,`for`,n(i).name),t(l,n(i).name)}),w(r,a)});var $=e(Q,2),ee=h($);g(2),M($),M(G),M(W),M(R),f(`submit`,G,N),s(`change`,G,()=>{c.errors.clear()}),E(X,()=>u.enabled,e=>u.enabled=e),s(`click`,ee,L),w(a,R),b()}a([`change`,`click`]);var G=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span> <span class="text-stone-500"> </span></div> <button class="bt small mx-1" aria-label="Modifier"><i class="icon-edit"></i></button></div>`),K=l(`<div class="container"></div>`);function q(i,a){S(a,!0);let l=C(x(p(()=>a.data.tools))),g=C(null),_=new P,v=()=>{O(g,null)},y=e=>{_.size===0&&I.updateTool(a.data.space,e).then(e=>{O(l,n(l).map(t=>e.id===t.id?e:t),!0),O(g,null)}).catch(e=>{console.log(e)})},E=async e=>{_.clear(),I.getTool(a.data.space,e).then(t=>{O(l,n(l).map(n=>n.id===e?t:n),!0),O(g,e,!0)})},D=e=>{e.key===`Escape`&&v()};var k=K();f(`keydown`,m,D),r(k,21,()=>n(l),e=>e.id,(r,i)=>{var a=c(),l=d(a),f=e=>{var t=c(),r=d(t);u(r,()=>n(i).id,e=>{W(e,{get item(){return n(i)},get errors(){return _},onSave:y,onCancel:v})}),w(e,t)},p=r=>{var a=G(),c=h(a),l=h(c),u=h(l,!0);M(l);var d=e(l,2),f=h(d);M(d),M(c);var p=e(c,2);M(a),o(()=>{t(u,n(i).name),t(f,`(${n(i).enabled??``})`)}),s(`click`,p,()=>E(n(i).id)),w(r,a)};T(l,e=>{n(g)===n(i).id?e(f):e(p,-1)}),w(r,a)}),M(k),w(i,k),b()}a([`click`]);export{q as component,L as universal};
@@ -0,0 +1,4 @@
import{$ as e,A as t,B as n,E as r,I as i,K as a,L as o,M as s,N as c,Q as l,R as u,Z as d,at as f,bt as p,dt as m,et as h,ft as g,it as _,j as v,k as y,l as b,m as x,nt as S,p as C,q as w,st as T,u as E,v as D,vt as O}from"../chunks/DGrvnoUE.js";import{n as k}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import{t as A}from"../chunks/ffLBjIeN.js";import"../chunks/CY9OlB4q.js";import{t as j}from"../chunks/BYYkuYgk.js";import{n as M,r as N,t as P}from"../chunks/Bht2nTIZ.js";var F=p({load:()=>I}),I=async({params:e})=>({title:`Tâches`,tasks:await N.listTasks(e.space),space:e.space}),ee=c(`<p class="my-4 text-center text-sm text-stone-500">Aucune tâche planifiée. Demandez-en une dans le chat
(« résume-moi l'actualité tous les jours à 8h »).</p>`),L=c(`<div class="dark:bg-stone-800 rounded p-3 my-2"><form><div class="formgroup my-2"><div class="formelement"><label>Titre</label> <input class="textinput" type="text"/></div> <div class="formelement"><label>Planification (cron)</label> <input class="textinput" type="text"/></div> <div class="formelement"><label>Répétition</label> <input type="checkbox"/></div></div> <div class="formelement"><label>Prompt</label> <textarea class="textinput w-full" rows="4"></textarea></div> <div class="mt-2 flex gap-2"><button class="bt small" type="submit"> </button> <button class="bt small" type="button">Annuler</button></div></form></div>`),R=c(`<p class="text-sm text-stone-500">Chargement...</p>`),z=c(`<p class="text-sm text-stone-500">Aucune conversation pour cette tâche.</p>`),B=c(`<li class="my-1 text-sm"><a class="text-sky-700 dark:text-sky-300"> </a> <span class="ml-2 text-xs text-stone-500"> </span></li>`),V=c(`<ul class="mt-1"></ul>`),H=c(`<div class="mt-2 border-t border-stone-600 pt-2"><div class="text-xs font-medium uppercase text-stone-500">Conversations liées</div> <!></div>`),U=c(`<div><div class="flex flex-row items-center"><div class="flex-1"><div class="font-bold text-base"> </div> <div class="text-xs text-stone-500"> </div></div> <button class="bt small" title="Conversations liées"><i class="icon-chat"></i></button> <button class="bt small" title="Modifier la tâche"><i class="icon-edit"></i></button> <button class="bt small" title="Supprimer la tâche"><i class="icon-trash-empty"></i></button></div> <p class="mt-1 text-sm text-stone-600 dark:text-stone-400"> </p> <span class="text-xs"> </span> <!></div>`),te=c(`<div class="container"><!> <!></div> <!>`,1);function W(i,c){g(c,!0);let p=f(()=>c.data.tasks??[]),F=_(null),I=_(null),W=_(!1),G=_(h(A.url.searchParams.get(`task`))),K=_(h({})),q=_(!1),J=async e=>{S(q,!0);try{let t=await j.allChats(c.data.space,0,void 0,e);S(K,{...n(K),[e]:t??[]},!0)}catch{M(`failure`,`Erreur lors du chargement des conversations`)}finally{S(q,!1)}},ne=async e=>{if(n(G)===e.id){S(G,null);return}S(G,e.id,!0),n(K)[e.id]||await J(e.id)},Y=!1;w(()=>{!Y&&n(G)&&(Y=!0,J(n(G))),Y=!0});let X=e=>{if(!e)return`—`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString(`fr-FR`,{day:`numeric`,month:`long`,year:`numeric`,hour:`2-digit`,minute:`2-digit`})},re=e=>{S(F,{...e},!0)},ie=async e=>{if(e.preventDefault(),n(F)){if(!n(F).label.trim()||!n(F).prompt.trim()||!n(F).cron.trim()){M(`failure`,`Titre, prompt et planification sont obligatoires`);return}S(W,!0);try{await N.updateTask(c.data.space,n(F).id,{label:n(F).label,prompt:n(F).prompt,cron:n(F).cron,repeat:n(F).repeat}),M(`success`,`Tâche mise à jour`),S(F,null),await k()}catch{M(`failure`,`Erreur lors de la mise à jour de la tâche`)}finally{S(W,!1)}}},ae=async()=>{if(n(I))try{await N.deleteTask(c.data.space,n(I).id),M(`success`,`Tâche supprimée`),await k()}catch{M(`failure`,`Erreur lors de la suppression de la tâche`)}finally{S(I,null)}};var Z=te(),Q=l(Z),$=d(Q),oe=e=>{var t=ee();v(e,t)};y($,e=>{n(p).length===0&&e(oe)});var se=e($,2);r(se,17,()=>n(p),e=>e.id,(i,f)=>{var p=s(),m=l(p),h=r=>{var i=L(),s=d(i),c=d(s),l=d(c),p=d(l),m=e(p,2);C(m),O(l);var h=e(l,2),g=d(h),_=e(g,2);C(_),O(h);var y=e(h,2),w=d(y),D=e(w,2);C(D),O(y),O(c);var k=e(c,2),A=d(k),j=e(A,2);T(j),O(k);var M=e(k,2),N=d(M),P=d(N,!0);O(N);var I=e(N,2);O(M),O(s),O(i),a(()=>{x(p,`for`,`label-${n(f).id}`),x(m,`id`,`label-${n(f).id}`),x(g,`for`,`cron-${n(f).id}`),x(_,`id`,`cron-${n(f).id}`),x(w,`for`,`repeat-${n(f).id}`),x(D,`id`,`repeat-${n(f).id}`),x(A,`for`,`prompt-${n(f).id}`),x(j,`id`,`prompt-${n(f).id}`),N.disabled=n(W),t(P,n(W)?`Enregistrement...`:`Enregistrer`)}),u(`submit`,s,ie),E(m,()=>n(F).label,e=>n(F).label=e),E(_,()=>n(F).cron,e=>n(F).cron=e),b(D,()=>n(F).repeat,e=>n(F).repeat=e),E(j,()=>n(F).prompt,e=>n(F).prompt=e),o(`click`,I,()=>S(F,null)),v(r,i)},g=i=>{var s=U();let l;var u=d(s),p=d(u),m=d(p),h=d(m,!0);O(m);var g=e(m,2),_=d(g);O(g),O(p);var b=e(p,2),C=e(b,2),w=e(C,2);O(u);var T=e(u,2),E=d(T,!0);O(T);var k=e(T,2),A=d(k);O(k);var j=e(k,2),M=i=>{var o=H(),s=e(d(o),2),l=e=>{var t=R();v(e,t)},u=e=>{var t=z();v(e,t)},p=i=>{var o=V();r(o,21,()=>n(K)[n(f).id],e=>e.id,(r,i)=>{var o=B(),s=d(o),l=d(s,!0);O(s);var u=e(s,2),f=d(u,!0);O(u),O(o),a(e=>{x(s,`href`,`/${c.data.space}/${n(i).id}`),t(l,n(i).title),t(f,e)},[()=>X(n(i)._date_created)]),v(r,o)}),O(o),v(i,o)};y(s,e=>{n(q)&&!n(K)[n(f).id]?e(l):(n(K)[n(f).id]??[]).length===0?e(u,1):e(p,-1)}),O(o),v(i,o)};y(j,e=>{n(G)===n(f).id&&e(M)}),O(s),a(e=>{l=D(s,1,`dark:bg-stone-800 rounded p-2 my-2`,null,l,{"ring-2":n(G)===n(f).id,"ring-sky-500":n(G)===n(f).id}),t(h,n(f).label),t(_,`${n(f).cron??``}
${n(f).repeat?`· répétée`:`· ponctuelle`}
${n(f).status===`done`?`· terminée`:``}`),t(E,n(f).prompt),t(A,`Prochaine exécution : ${e??``}`)},[()=>X(n(f).nextDatetime)]),o(`click`,b,()=>ne(n(f))),o(`click`,C,()=>re(n(f))),o(`click`,w,()=>S(I,n(f),!0)),v(i,s)};y(m,e=>{n(F)&&n(F).id===n(f).id?e(h):e(g,-1)}),v(i,p)}),O(Q);var ce=e(Q,2);{let e=f(()=>n(I)!==null),t=f(()=>`Voulez-vous vraiment supprimer « ${n(I)?.label} » ? Cette action est irréversible.`);P(ce,{get open(){return n(e)},title:`Supprimer la tâche`,get message(){return n(t)},confirmLabel:`Supprimer`,onConfirm:ae,onCancel:()=>S(I,null)})}v(i,Z),m()}i([`click`]);export{W as component,F as universal};
@@ -1 +0,0 @@
import{N as e,bt as t,j as n}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";var r=t({load:()=>i});function i(){return{title:`Tâches`}}var a=e(`<div>Tâches</div>`);function o(e){var t=a();n(e,t)}export{o as component,r as universal};
@@ -1 +1 @@
import{$ as e,A as t,B as n,E as r,F as i,G as a,I as o,K as s,L as c,N as l,Q as u,R as d,U as f,Z as p,_t as m,a as h,at as ee,b as te,bt as g,dt as ne,et as _,ft as re,g as v,it as y,j as b,k as x,nt as S,p as C,q as ie,r as ae,u as w,v as T,vt as E}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{n as oe,t as se}from"../chunks/DTCALkcP.js";import{t as D}from"../chunks/DqlBPR2w.js";import{t as O}from"../chunks/DyF3myvh.js";import{n as ce,t as k}from"../chunks/6mSXxE57.js";import{t as le}from"../chunks/CUminYLk.js";import{t as ue}from"../chunks/D3MDK1zR.js";var de=g({load:()=>fe}),fe=async()=>({title:`Profil`,me:await O.me()}),A=function(e){return e[e.None=0]=`None`,e[e.Changed=1]=`Changed`,e[e.Saving=2]=`Saving`,e[e.Saved=3]=`Saved`,e[e.Error=4]=`Error`,e}({}),pe={listTimezones:()=>D.get(`/misc/timezones`)},me=l(`<i class="incon-spin1 anomate-spin"></i> Enregistrement en cours`,1),he=l(`<i class="incon-ok anomate-spin"></i> Enregistrement réussi`,1),ge=l(`<button><!></button>`);function _e(e,n){re(n,!0);let r=h(n,`state`,7),a=h(n,`disabled`,3,!1);ie(()=>{(r()===A.Saved||r()===A.Error)&&setTimeout(()=>{r(A.None)},2e3)});let o=()=>{n.handleClick&&(r()===A.Changed||r()===A.None)&&n.handleClick()};var l=ge();let u;var d=p(l),f=e=>{var r=i();s(()=>t(r,n.label)),b(e,r)},ee=e=>{var t=me();m(),b(e,t)},te=e=>{var t=he();m(),b(e,t)},g=e=>{var t=i(`Echec`);b(e,t)};x(d,e=>{r()==A.None||r()==A.Changed?e(f):r()==A.Saving?e(ee,1):r()==A.Saved?e(te,2):r()==A.Error&&e(g,3)}),E(l),s(()=>{l.disabled=a(),u=T(l,1,`bt`,null,u,{disabled:a(),changed:r()===A.Changed,saving:r()===A.Saving,saved:r()===A.Saved,error:r()===A.Error})}),c(`click`,l,o),b(e,l),ne()}o([`click`]);var ve=l(`<div class="m-2"><div class="dark:bg-stone-700 bg-stone-300 rounded inline px-2 py-1 text-sm"><span class="inline-block w-20"> </span> <span> </span> <button class="ml-4 pointer" title="Annuler"><i class="icon-cancel"></i></button></div></div>`),ye=l(`<div class="mb-4 formgroup container"><h2>Mon compte</h2> <form><div class="formelement"><label for="email" class="my-1 flex-1">Email</label> <input id="email" type="text" class="textinput"/> <!></div> <div class="grid grid-cols-1 gap-x-4 md:grid-cols-2"><div class="formelement"><label for="firstname" class=" my-1 flex-1">Prénom</label> <input id="firstname" type="text" class="textinput"/> <!></div> <div class="formelement"><label for="lastname" class="my-1 flex-1">Nom</label> <input id="lastname" type="text" class="textinput"/> <!></div></div> <div class="grid grid-cols-1 gap-x-4 md:grid-cols-2"><div class="formelement"><label for="lang" class="block my-1 flex-1">Langue</label> <select class="textinput"><option>English</option><option>Français</option></select> <!></div> <div class="formelement"><label for="timezone" class="block my-1 flex-1">Timezone</label> <!> <!></div></div> <div class="formelement"><label for="theme" class="block my-1 flex-1">Thème</label> <select class="textinput"><option>Automatique</option><option>Sombre</option><option>Clair</option></select> <!></div> <!></form></div> <div class="mb-4 formgroup container"><h2>Canaux de communication</h2> <!> <div class="flex gap-2 mt-6"><div><select class="textinput"><option></option><option>Email</option><option>Signal</option><option>Telegram</option><option>Whatsapp</option></select></div> <div class="flex-1"><input type="text" class="textinput"/></div> <div><!></div></div></div>`,1);function j(i,o){re(o,!0);let l=_(f(()=>o.data.me.user)),m=y(_([])),h=y(_({type:``,address:``})),g=y(_([])),x=new ce,T=y(_(A.None)),D=y(_(A.None));ae(async()=>{S(m,await O.listAddresses(l.id),!0),S(g,(await pe.listTimezones()).map(e=>({value:e,label:e})),!0)}),ie(()=>{oe(l.theme),se()});let de=e=>{e.preventDefault(),S(T,A.Saving,!0),ue(l.email)||x.set(`email`,`Adresse email invalide !`),l.firstname||x.set(`firstname`,`Le prénom est obligatoire !`),l.lastname||x.set(`lastname`,`Le nom est obligatoire !`),x.size==0&&O.update(l.id,l).then(()=>{S(T,A.Saved,!0)}).catch(e=>{S(T,A.Saving,!0),console.error(e)})},fe=()=>{S(D,A.Saving,!0),O.createAddress(l.id,n(h)).then(e=>{n(m).push(e),S(h,{type:``,address:``},!0),S(D,A.Saved,!0)}).catch(e=>{console.log(e)})},me=e=>{O.deleteAddress(l.id,e).then(()=>{S(m,n(m).filter(t=>t.id!=e),!0)}).catch(e=>{console.log(e)})},he=()=>{x.clear(),S(T,A.Changed,!0)},ge=e=>{e.focus()};var j=ye(),M=u(j),N=e(p(M),2),P=p(N),F=e(p(P),2);C(F),a(()=>w(F,()=>l.email,e=>l.email=e)),te(F,e=>ge?.(e));var be=e(F,2);k(be,{key:`email`,get errors(){return x}}),E(P);var I=e(P,2),L=p(I),R=e(p(L),2);C(R);var xe=e(R,2);k(xe,{key:`firstname`,get errors(){return x}}),E(L);var Se=e(L,2),z=e(p(Se),2);C(z);var Ce=e(z,2);k(Ce,{key:`lastname`,get errors(){return x}}),E(Se),E(I);var B=e(I,2),V=p(B),H=e(p(V),2),U=p(H);U.value=U.__value=`en`;var we=e(U);we.value=we.__value=`fr`,E(H);var Te=e(H,2);k(Te,{key:`lang`,get errors(){return x}}),E(V);var Ee=e(V,2),De=e(p(Ee),2);le(De,{get items(){return n(g)},valueMode:`id`,get value(){return l.timezone},seLine truncated import{$ as e,A as t,B as n,E as r,F as i,G as a,I as o,K as s,L as c,N as l,Q as u,R as d,U as f,Z as p,_t as m,a as h,at as ee,b as te,bt as g,dt as ne,et as _,ft as re,g as v,it as y,j as b,k as x,nt as S,p as C,q as ie,r as ae,u as w,v as T,vt as E}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{n as oe,t as se}from"../chunks/DTCALkcP.js";import{t as D}from"../chunks/DtfiK5fE.js";import{t as O}from"../chunks/zsRwiIdn.js";import{n as ce,t as k}from"../chunks/6mSXxE57.js";import{t as le}from"../chunks/DdGy_ePN.js";import{t as ue}from"../chunks/D3MDK1zR.js";var de=g({load:()=>fe}),fe=async()=>({title:`Profil`,me:await O.me()}),A=function(e){return e[e.None=0]=`None`,e[e.Changed=1]=`Changed`,e[e.Saving=2]=`Saving`,e[e.Saved=3]=`Saved`,e[e.Error=4]=`Error`,e}({}),pe={listTimezones:()=>D.get(`/misc/timezones`)},me=l(`<i class="incon-spin1 anomate-spin"></i> Enregistrement en cours`,1),he=l(`<i class="incon-ok anomate-spin"></i> Enregistrement réussi`,1),ge=l(`<button><!></button>`);function _e(e,n){re(n,!0);let r=h(n,`state`,7),a=h(n,`disabled`,3,!1);ie(()=>{(r()===A.Saved||r()===A.Error)&&setTimeout(()=>{r(A.None)},2e3)});let o=()=>{n.handleClick&&(r()===A.Changed||r()===A.None)&&n.handleClick()};var l=ge();let u;var d=p(l),f=e=>{var r=i();s(()=>t(r,n.label)),b(e,r)},ee=e=>{var t=me();m(),b(e,t)},te=e=>{var t=he();m(),b(e,t)},g=e=>{var t=i(`Echec`);b(e,t)};x(d,e=>{r()==A.None||r()==A.Changed?e(f):r()==A.Saving?e(ee,1):r()==A.Saved?e(te,2):r()==A.Error&&e(g,3)}),E(l),s(()=>{l.disabled=a(),u=T(l,1,`bt`,null,u,{disabled:a(),changed:r()===A.Changed,saving:r()===A.Saving,saved:r()===A.Saved,error:r()===A.Error})}),c(`click`,l,o),b(e,l),ne()}o([`click`]);var ve=l(`<div class="m-2"><div class="dark:bg-stone-700 bg-stone-300 rounded inline px-2 py-1 text-sm"><span class="inline-block w-20"> </span> <span> </span> <button class="ml-4 pointer" title="Annuler"><i class="icon-cancel"></i></button></div></div>`),ye=l(`<div class="mb-4 formgroup container"><h2>Mon compte</h2> <form><div class="formelement"><label for="email" class="my-1 flex-1">Email</label> <input id="email" type="text" class="textinput"/> <!></div> <div class="grid grid-cols-1 gap-x-4 md:grid-cols-2"><div class="formelement"><label for="firstname" class=" my-1 flex-1">Prénom</label> <input id="firstname" type="text" class="textinput"/> <!></div> <div class="formelement"><label for="lastname" class="my-1 flex-1">Nom</label> <input id="lastname" type="text" class="textinput"/> <!></div></div> <div class="grid grid-cols-1 gap-x-4 md:grid-cols-2"><div class="formelement"><label for="lang" class="block my-1 flex-1">Langue</label> <select class="textinput"><option>English</option><option>Français</option></select> <!></div> <div class="formelement"><label for="timezone" class="block my-1 flex-1">Timezone</label> <!> <!></div></div> <div class="formelement"><label for="theme" class="block my-1 flex-1">Thème</label> <select class="textinput"><option>Automatique</option><option>Sombre</option><option>Clair</option></select> <!></div> <!></form></div> <div class="mb-4 formgroup container"><h2>Canaux de communication</h2> <!> <div class="flex gap-2 mt-6"><div><select class="textinput"><option></option><option>Email</option><option>Signal</option><option>Telegram</option><option>Whatsapp</option></select></div> <div class="flex-1"><input type="text" class="textinput"/></div> <div><!></div></div></div>`,1);function j(i,o){re(o,!0);let l=_(f(()=>o.data.me.user)),m=y(_([])),h=y(_({type:``,address:``})),g=y(_([])),x=new ce,T=y(_(A.None)),D=y(_(A.None));ae(async()=>{S(m,await O.listAddresses(l.id),!0),S(g,(await pe.listTimezones()).map(e=>({value:e,label:e})),!0)}),ie(()=>{oe(l.theme),se()});let de=e=>{e.preventDefault(),S(T,A.Saving,!0),ue(l.email)||x.set(`email`,`Adresse email invalide !`),l.firstname||x.set(`firstname`,`Le prénom est obligatoire !`),l.lastname||x.set(`lastname`,`Le nom est obligatoire !`),x.size==0&&O.update(l.id,l).then(()=>{S(T,A.Saved,!0)}).catch(e=>{S(T,A.Saving,!0),console.error(e)})},fe=()=>{S(D,A.Saving,!0),O.createAddress(l.id,n(h)).then(e=>{n(m).push(e),S(h,{type:``,address:``},!0),S(D,A.Saved,!0)}).catch(e=>{console.log(e)})},me=e=>{O.deleteAddress(l.id,e).then(()=>{S(m,n(m).filter(t=>t.id!=e),!0)}).catch(e=>{console.log(e)})},he=()=>{x.clear(),S(T,A.Changed,!0)},ge=e=>{e.focus()};var j=ye(),M=u(j),N=e(p(M),2),P=p(N),F=e(p(P),2);C(F),a(()=>w(F,()=>l.email,e=>l.email=e)),te(F,e=>ge?.(e));var be=e(F,2);k(be,{key:`email`,get errors(){return x}}),E(P);var I=e(P,2),L=p(I),R=e(p(L),2);C(R);var xe=e(R,2);k(xe,{key:`firstname`,get errors(){return x}}),E(L);var Se=e(L,2),z=e(p(Se),2);C(z);var Ce=e(z,2);k(Ce,{key:`lastname`,get errors(){return x}}),E(Se),E(I);var B=e(I,2),V=p(B),H=e(p(V),2),U=p(H);U.value=U.__value=`en`;var we=e(U);we.value=we.__value=`fr`,E(H);var Te=e(H,2);k(Te,{key:`lang`,get errors(){return x}}),E(V);var Ee=e(V,2),De=e(p(Ee),2);le(De,{get items(){return n(g)},valueMode:`id`,get value(){return l.timezone},seLine truncated
@@ -1 +0,0 @@
import{$ as e,I as t,K as n,L as r,N as i,Q as a,R as o,Z as s,_t as c,dt as l,et as u,ft as d,j as f,k as p,m,ot as h,p as g,u as _,vt as v}from"../chunks/DGrvnoUE.js";import{t as y}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import"../chunks/QHwlfjO8.js";import{i as b,n as x}from"../chunks/DqlBPR2w.js";import{t as S}from"../chunks/BRXBpvt8.js";import{t as C}from"../chunks/D3MDK1zR.js";import{t as w}from"../chunks/CvbyM2Rc.js";var T=i(`<form><div class="flex"><label for="email" class="block mb-2 flex-1">Email</label> <a href="/recover-password" class="text-xs ">Mot de passe oublié ?</a></div> <div class="flex flex-row"><input type="text" class="textinput mr-1 flex-1"/> <button class="bt small" title="page suivante"><i class="icon-right-big"></i></button></div></form> <div class="my-4 text-xs"><a href="/register">Pas encore de compte ? Incrivez-vous.</a></div>`,1),E=i(`<form><div class="flex"><label for="email" class="block mb-2 flex-1">Mot de passe</label></div> <div class="flex flex-row"><input type="password" class="textinput mr-1 flex-1"/> <button class="bt small">Entrer</button></div> <a href="/login" class="text-xs">← Retour</a></form>`),D=i(`<div class="h-full w-full flex items-center public"><div class="m-auto w-96 max-w-full p-4"><img class="h-10 mb-4" alt="logo"/> <h1>Identifiez-vous ...</h1> <!> <hr class="my-4"/> <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-4"><button class="bt p-5 text-center" title="Connexion avec Google"><i class="icon-google"></i></button> <button class="bt p-5 text-center" title="Connexion avec Facebook"><i class="icon-facebook"></i></button> <button class="bt p-5 text-center" title="Connexion avec Github"><i class="icon-github"></i></button> <button class="bt p-5 text-center" title="Connexion avec Apple"><i class="icon-apple"></i></button></div></div></div>`);function O(t,i){d(i,!0);let O=u({email:``,password:``,validemail:!1}),k=()=>{O.validemail=C(O.email)},A=e=>{e.preventDefault(),w.login(O).then(e=>{x.user=e.user,b(e.accessToken),y(`/`)}).catch(e=>{console.log(e)})};var j=D(),M=s(j),N=s(M),P=e(N,4),F=t=>{var n=T(),r=a(n),i=e(s(r),2),l=s(i);g(l),h(l,!0),c(2),v(i),v(r),c(2),o(`submit`,r,k),_(l,()=>O.email,e=>O.email=e),f(t,n)},I=t=>{var n=E(),i=e(s(n),2),a=s(i);g(a),h(a,!0),c(2),v(i);var l=e(i,2);v(n),o(`submit`,n,A),_(a,()=>O.password,e=>O.password=e),r(`click`,l,()=>{O.validemail=!1}),f(t,n)};p(P,e=>{O.validemail?e(I,-1):e(F)}),c(4),v(M),v(j),n(()=>m(N,`src`,S)),f(t,j),l()}t([`click`]);export{O as component};
@@ -0,0 +1 @@
import{$ as e,A as t,B as n,E as r,I as i,K as a,L as o,N as s,Q as c,R as l,Z as u,_t as d,dt as f,et as p,ft as m,it as h,j as g,k as _,m as v,nt as y,ot as b,p as x,r as S,u as C,vt as w}from"../chunks/DGrvnoUE.js";import{t as T}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import"../chunks/CY9OlB4q.js";import{i as E,n as D}from"../chunks/DtfiK5fE.js";import{t as O}from"../chunks/BRXBpvt8.js";import{t as k}from"../chunks/D3MDK1zR.js";import{t as A}from"../chunks/BedKI9iq.js";var j=s(`<form><div class="flex"><label for="email" class="block mb-2 flex-1">Email</label> <a href="/recover-password" class="text-xs ">Mot de passe oublié ?</a></div> <div class="flex flex-row"><input type="text" class="textinput mr-1 flex-1"/> <button class="bt small" title="page suivante"><i class="icon-right-big"></i></button></div></form> <div class="my-4 text-xs"><a href="/register">Pas encore de compte ? Incrivez-vous.</a></div>`,1),M=s(`<form><div class="flex"><label for="email" class="block mb-2 flex-1">Mot de passe</label></div> <div class="flex flex-row"><input type="password" class="textinput mr-1 flex-1"/> <button class="bt small">Entrer</button></div> <a href="/login" class="text-xs">← Retour</a></form>`),N=s(`<button class="bt p-5 text-center"> </button>`),P=s(`<hr class="my-4"/> <div class="grid grid-cols-[repeat(auto-fit,minmax(150px,1fr))] gap-4"></div>`,1),F=s(`<div class="h-full w-full flex items-center public"><div class="m-auto w-96 max-w-full p-4"><img class="h-10 mb-4" alt="logo"/> <h1>Identifiez-vous ...</h1> <!> <!></div></div>`);function I(i,s){m(s,!0);let I=p({email:``,password:``,validemail:!1}),L=h(p([]));S(()=>{A.oidcProviders().then(e=>{y(L,e??[],!0)}).catch(()=>{y(L,[],!0)})});let R=e=>{window.location.href=A.oidcLoginUrl(e)},z=()=>{I.validemail=k(I.email)},B=e=>{e.preventDefault(),A.login(I).then(e=>{D.user=e.user,E(e.accessToken),T(`/`)}).catch(e=>{console.log(e)})};var V=F(),H=u(V),U=u(H),W=e(U,4),G=t=>{var n=j(),r=c(n),i=e(u(r),2),a=u(i);x(a),b(a,!0),d(2),w(i),w(r),d(2),l(`submit`,r,z),C(a,()=>I.email,e=>I.email=e),g(t,n)},K=t=>{var n=M(),r=e(u(n),2),i=u(r);x(i),b(i,!0),d(2),w(r);var a=e(r,2);w(n),l(`submit`,n,B),C(i,()=>I.password,e=>I.password=e),o(`click`,a,()=>{I.validemail=!1}),g(t,n)};_(W,e=>{I.validemail?e(K,-1):e(G)});var q=e(W,2),J=i=>{var s=P(),l=e(c(s),2);r(l,21,()=>n(L),e=>e.id,(e,r)=>{var i=N(),s=u(i,!0);w(i),a(()=>{v(i,`title`,`Connexion avec ${n(r).label??``}`),t(s,n(r).label)}),o(`click`,i,()=>R(n(r).id)),g(e,i)}),w(l),g(i,s)};_(q,e=>{n(L).length>0&&e(J)}),w(H),w(V),a(()=>v(U,`src`,O)),g(i,V),f()}i([`click`]);export{I as component};
@@ -1 +1 @@
import{$ as e,A as t,B as n,E as r,I as i,K as a,L as o,N as s,Q as c,R as l,T as u,X as d,Z as f,a as p,at as m,bt as h,dt as g,et as _,ft as v,j as y,k as b,m as x,q as S,r as C,v as w,vt as T,y as E}from"../chunks/DGrvnoUE.js";import{t as D}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import{n as O,t as k}from"../chunks/DTCALkcP.js";import{t as A}from"../chunks/5WAfNqs_.js";import"../chunks/QHwlfjO8.js";import{n as j,r as M}from"../chunks/DqlBPR2w.js";import{t as N}from"../chunks/DyF3myvh.js";import{t as P}from"../chunks/Cyrg28w2.js";import{t as F}from"../chunks/BRXBpvt8.js";var I=h({load:()=>L}),L=async()=>{let e=await N.me();return P.spaces=e.teams,P.current||(P.current=P.spaces[0].id),{spaceid:P.current,me:e}},R=_({sidebarDesktopOpen:!0,sidebarMobileOpen:!1,menuContentVisible:!0}),z=s(`<span class="ml-4"> </span>`),B=s(`<div class="my-2 block"><a class="p-2 w-full text-left menuitem block"><i></i> <!></a></div>`);function V(n,r){v(r,!0);let i=p(r,`label`,3,``),s=p(r,`icon`,3,``),c=p(r,`link`,3,``),l=e=>{e.preventDefault(),R.sidebarMobileOpen&&(R.sidebarMobileOpen=!1,R.menuContentVisible=!1),D(c())};var u=B(),d=f(u),m=f(d),h=e(m,2),_=e=>{var n=z(),r=f(n,!0);T(n),a(()=>t(r,i())),y(e,n)};b(h,e=>{R.menuContentVisible&&e(_)}),T(d),T(u),a(()=>{x(d,`href`,c()),w(m,1,E([s()]))}),o(`click`,d,l),y(n,u),g()}i([`click`]);var H=s(`<div class="flex-1 p-3 font openonly"><img class="h-5" alt="logo"/></div>`),U=s(`<option> </option>`),W=s(`<div class="m-2"><div class="formelement"><select class="textinput"></select></div></div>`),G=s(`<div class="flex flex-row gap-2 p-2 "><div class="py-1 flex-1 flex flex-row text-xs"><div class="w-6 h-6 rounded-full bg-cyan-600 text-white flex items-center justify-center font-medium">FM</div> <div class="flex-1 ml-2 inline-flex items-center">Fabien Masson</div></div> <a href="/profile" class="bt small inline-flex items-center justify-center" title="Edition profil"><i class="icon-edit"></i></a> <button class="bt small" title="Déconnecter"><i class="icon-logout"></i></button></div>`),K=s(`<div class="flex flex-row italic mb-2"><!> <button id="hamburgerDesktop" title="Open menu"><i class="icon-menu pointer block p-2"></i></button> <button id="hamburgerMobile" title="Open menu"><i class="icon-menu pointer block p-2"></i></button></div> <!> <div id="menu" class="flex-1 overflow-y-scroll"><!> <!> <!> <!> <!></div> <div id="profile" class="w-full items-center border-t border-stone-200 dark:border-stone-800"><!></div>`,1);function q(i,s){v(s,!0);let l=()=>{M()};var u=K(),d=c(u),p=f(d),h=e=>{var t=H(),n=f(t);T(t),a(()=>x(n,`src`,F)),y(e,t)};b(p,e=>{R.menuContentVisible&&e(h)});var _=e(p,2),S=e(_,2);T(d);var C=e(d,2),w=e=>{var i=W(),o=f(i),c=f(o);r(c,21,()=>s.spaces,e=>e.id,(e,r)=>{var i=U(),o=f(i,!0);T(i);var s={};a(()=>{t(o,n(r).label),s!==(s=n(r).id)&&(i.value=(i.__value=n(r).id)??``)}),y(e,i)}),T(c),T(o),T(i),y(e,i)};b(C,e=>{R.menuContentVisible&&e(w)});var E=e(C,2),D=f(E);{let e=m(()=>`/${s.spaceid}`);V(D,{label:`Nouveau chat`,icon:`icon-plus`,get link(){return n(e)}})}var O=e(D,2);{let e=m(()=>`/${s.spaceid}/history`);V(O,{label:`Conversations`,icon:`icon-chat`,get link(){return n(e)}})}var k=e(O,2);{let e=m(()=>`/${s.spaceid}/tasks`);V(k,{label:`Planification`,icon:`icon-tasks`,get link(){return n(e)}})}var A=e(k,2);{let e=m(()=>`/${s.spaceid}/kb`);V(A,{label:`Connaissances`,icon:`icon-graduation-cap`,get link(){return n(e)}})}var j=e(A,2);{let e=m(()=>`/${s.spaceid}/settings`);V(j,{label:`Réglages`,icon:`icon-cog`,get link(){return n(e)}})}T(E);var N=e(E,2),P=f(N),I=t=>{var n=G(),r=e(f(n),4);T(n),o(`click`,r,l),y(t,n)},L=e=>{V(e,{label:`User`,icon:`icon-user`,link:`/profile`})};b(P,e=>{R.menuContentVisible?e(I):e(L,-1)}),T(N),o(`click`,_,function(...e){s.handleMenuDesktop?.apply(this,e)}),o(`click`,S,function(...e){s.handleMenuMobile?.apply(this,e)}),y(i,u),g()}i([`click`]);var J=s(`<span><a title="retour"><i class="icon-left-big"></i></a></span>`),Y=s(`<div id="outer"><div id="sidebar" class="flex flex-col z-10"><!></div> <div id="main"><div class="flex flex-col h-screen "><div class="px-2"><div class="header container"><h1 class="flex mx-2"><span class="flex-1"> </span> <!></h1></div></div> <div class="overflow-scroll flex-1 p-2"><!></div></div></div></div>`);function X(n,r){v(r,!0);let i=()=>{R.sidebarDesktopOpen=!R.sidebarDesktopOpen,R.sidebarDesktopOpen?setTimeout(()=>{R.menuContentVisible=R.sidebarDesktopOpen},200):R.menuContentVisible=R.sidebarDesktopOpen},o=()=>{R.sidebarMobileOpen=!R.sidebarMobileOpen,R.sidebarMobileOpen?setTimeout(()=>{R.menuContentVisible=R.sidebarMobileOpen},200):R.menuContentVisible=R.sidebarMobileOpen},s=()=>{R.menuContentVisible=window.innerWidth<640?R.sidebarMobileOpen:R.sidebarDesktopOpen};C(async()=>{s(),r.data.me?(j.user=r.data.me.user,O(j.user.theme),k(),j.status=`authenticated`):j.status=`unauthenticated`}),S(()=>{j.status==`unauthenticated`&&D(`/login`)});var c=Y();l(`resize`,d,s);var p=f(c);q(f(p),{get spaces(){return P.spaces},geLine truncated import{$ as e,A as t,B as n,E as r,I as i,K as a,L as o,N as s,Q as c,R as l,T as u,X as d,Z as f,a as p,at as m,bt as h,dt as g,et as _,ft as v,j as y,k as b,m as x,q as S,r as C,v as w,vt as T,y as E}from"../chunks/DGrvnoUE.js";import{t as D}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import{n as O,t as k}from"../chunks/DTCALkcP.js";import{t as A}from"../chunks/ffLBjIeN.js";import"../chunks/CY9OlB4q.js";import{n as j,r as M}from"../chunks/DtfiK5fE.js";import{t as N}from"../chunks/zsRwiIdn.js";import{t as P}from"../chunks/Cyrg28w2.js";import{t as F}from"../chunks/BRXBpvt8.js";var I=h({load:()=>L}),L=async()=>{let e=await N.me();return P.spaces=e.teams,P.current||(P.current=P.spaces[0].id),{spaceid:P.current,me:e}},R=_({sidebarDesktopOpen:!0,sidebarMobileOpen:!1,menuContentVisible:!0}),z=s(`<span class="ml-4"> </span>`),B=s(`<div class="my-2 block"><a class="p-2 w-full text-left menuitem block"><i></i> <!></a></div>`);function V(n,r){v(r,!0);let i=p(r,`label`,3,``),s=p(r,`icon`,3,``),c=p(r,`link`,3,``),l=e=>{e.preventDefault(),R.sidebarMobileOpen&&(R.sidebarMobileOpen=!1,R.menuContentVisible=!1),D(c())};var u=B(),d=f(u),m=f(d),h=e(m,2),_=e=>{var n=z(),r=f(n,!0);T(n),a(()=>t(r,i())),y(e,n)};b(h,e=>{R.menuContentVisible&&e(_)}),T(d),T(u),a(()=>{x(d,`href`,c()),w(m,1,E([s()]))}),o(`click`,d,l),y(n,u),g()}i([`click`]);var H=s(`<div class="flex-1 p-3 font openonly"><img class="h-5" alt="logo"/></div>`),U=s(`<option> </option>`),W=s(`<div class="m-2"><div class="formelement"><select class="textinput"></select></div></div>`),G=s(`<div class="flex flex-row gap-2 p-2 "><div class="py-1 flex-1 flex flex-row text-xs"><div class="w-6 h-6 rounded-full bg-cyan-600 text-white flex items-center justify-center font-medium">FM</div> <div class="flex-1 ml-2 inline-flex items-center">Fabien Masson</div></div> <a href="/profile" class="bt small inline-flex items-center justify-center" title="Edition profil"><i class="icon-edit"></i></a> <button class="bt small" title="Déconnecter"><i class="icon-logout"></i></button></div>`),K=s(`<div class="flex flex-row italic mb-2"><!> <button id="hamburgerDesktop" title="Open menu"><i class="icon-menu pointer block p-2"></i></button> <button id="hamburgerMobile" title="Open menu"><i class="icon-menu pointer block p-2"></i></button></div> <!> <div id="menu" class="flex-1 overflow-y-scroll"><!> <!> <!> <!> <!></div> <div id="profile" class="w-full items-center border-t border-stone-200 dark:border-stone-800"><!></div>`,1);function q(i,s){v(s,!0);let l=()=>{M()};var u=K(),d=c(u),p=f(d),h=e=>{var t=H(),n=f(t);T(t),a(()=>x(n,`src`,F)),y(e,t)};b(p,e=>{R.menuContentVisible&&e(h)});var _=e(p,2),S=e(_,2);T(d);var C=e(d,2),w=e=>{var i=W(),o=f(i),c=f(o);r(c,21,()=>s.spaces,e=>e.id,(e,r)=>{var i=U(),o=f(i,!0);T(i);var s={};a(()=>{t(o,n(r).label),s!==(s=n(r).id)&&(i.value=(i.__value=n(r).id)??``)}),y(e,i)}),T(c),T(o),T(i),y(e,i)};b(C,e=>{R.menuContentVisible&&e(w)});var E=e(C,2),D=f(E);{let e=m(()=>`/${s.spaceid}`);V(D,{label:`Nouveau chat`,icon:`icon-plus`,get link(){return n(e)}})}var O=e(D,2);{let e=m(()=>`/${s.spaceid}/history`);V(O,{label:`Conversations`,icon:`icon-chat`,get link(){return n(e)}})}var k=e(O,2);{let e=m(()=>`/${s.spaceid}/tasks`);V(k,{label:`Planification`,icon:`icon-tasks`,get link(){return n(e)}})}var A=e(k,2);{let e=m(()=>`/${s.spaceid}/kb`);V(A,{label:`Connaissances`,icon:`icon-graduation-cap`,get link(){return n(e)}})}var j=e(A,2);{let e=m(()=>`/${s.spaceid}/settings`);V(j,{label:`Réglages`,icon:`icon-cog`,get link(){return n(e)}})}T(E);var N=e(E,2),P=f(N),I=t=>{var n=G(),r=e(f(n),4);T(n),o(`click`,r,l),y(t,n)},L=e=>{V(e,{label:`User`,icon:`icon-user`,link:`/profile`})};b(P,e=>{R.menuContentVisible?e(I):e(L,-1)}),T(N),o(`click`,_,function(...e){s.handleMenuDesktop?.apply(this,e)}),o(`click`,S,function(...e){s.handleMenuMobile?.apply(this,e)}),y(i,u),g()}i([`click`]);var J=s(`<span><a title="retour"><i class="icon-left-big"></i></a></span>`),Y=s(`<div id="outer"><div id="sidebar" class="flex flex-col z-10"><!></div> <div id="main"><div class="flex flex-col h-screen "><div class="px-2"><div class="header container"><h1 class="flex mx-2"><span class="flex-1"> </span> <!></h1></div></div> <div class="overflow-scroll flex-1 p-2"><!></div></div></div></div>`);function X(n,r){v(r,!0);let i=()=>{R.sidebarDesktopOpen=!R.sidebarDesktopOpen,R.sidebarDesktopOpen?setTimeout(()=>{R.menuContentVisible=R.sidebarDesktopOpen},200):R.menuContentVisible=R.sidebarDesktopOpen},o=()=>{R.sidebarMobileOpen=!R.sidebarMobileOpen,R.sidebarMobileOpen?setTimeout(()=>{R.menuContentVisible=R.sidebarMobileOpen},200):R.menuContentVisible=R.sidebarMobileOpen},s=()=>{R.menuContentVisible=window.innerWidth<640?R.sidebarMobileOpen:R.sidebarDesktopOpen};C(async()=>{s(),r.data.me?(j.user=r.data.me.user,O(j.user.theme),k(),j.status=`authenticated`):j.status=`unauthenticated`}),S(()=>{j.status==`unauthenticated`&&D(`/login`)});var c=Y();l(`resize`,d,s);var p=f(c);q(f(p),{get spaces(){return P.spaces},geLine truncated
@@ -1 +1 @@
import{$ as e,I as t,K as n,L as r,N as i,R as a,Z as o,dt as s,et as c,ft as l,j as u,m as d,ot as f,p,u as m,vt as h}from"../chunks/DGrvnoUE.js";import{t as g}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import"../chunks/QHwlfjO8.js";import{t as _}from"../chunks/BRXBpvt8.js";import{n as v,t as y}from"../chunks/6mSXxE57.js";import{t as b}from"../chunks/D3MDK1zR.js";import{t as x}from"../chunks/CvbyM2Rc.js";var S=i(`<div class="h-full w-full flex items-center public"><div class="m-auto w-96 max-w-full p-4"><img class="h-10 mb-4" alt="logo"/> <h1>Inscription</h1> <form><label for="email" class="block my-1 flex-1">Email</label> <input id="email" type="text" class="textinput"/> <!> <label for="firstname" class="block my-1 flex-1">Prénom</label> <input id="firstname" type="text" class="textinput"/> <!> <label for="lastname" class="block my-1 flex-1">Nom</label> <input id="lastname" type="text" class="textinput"/> <!> <label for="password" class="block my-1 flex-1">Mot de passe</label> <input id="password" type="password" class="textinput"/> <!> <label for="verifpassword" class="block my-1 flex-1">Vérification du mot de passe</label> <input id="verifpassword" type="password" class="textinput"/> <!> <button class="bt my-2 w-full ">Enregistrer</button> <!></form></div></div>`);function C(t,i){l(i,!0);let C=new v,w=c({email:``,firstname:``,lastname:``,password:``,verifPassword:``}),T=e=>{if(e.preventDefault(),C.clear(),b(w.email)||C.set(`email`,`Adresse email invalide !`),w.firstname||C.set(`firstname`,`Le prénom est obligatoire !`),w.lastname||C.set(`lastname`,`Le nom est obligatoire !`),w.password!==w.verifPassword&&C.set(`verifPassword`,`Les mots de pass ne correspondent pas.`),C.size==0){let e={method:`password`,email:w.email,firstname:w.firstname,lastname:w.lastname,password:w.password};x.register(e).then(()=>{g(`/`)}).catch(e=>{C.set(`submit`,`Erreur: `+e)})}};var E=S(),D=o(E),O=o(D),k=e(O,4),A=e(o(k),2);p(A),f(A,!0);var j=e(A,2);y(j,{key:`email`,get errors(){return C}});var M=e(j,4);p(M);var N=e(M,2);y(N,{key:`firstname`,get errors(){return C}});var P=e(N,4);p(P);var F=e(P,2);y(F,{key:`lastname`,get errors(){return C}});var I=e(F,4);p(I);var L=e(I,2);y(L,{key:`password`,get errors(){return C}});var R=e(L,4);p(R);var z=e(R,2);y(z,{key:`verifPassword`,get errors(){return C}});var B=e(z,4);y(B,{key:`submit`,get errors(){return C}}),h(k),h(D),h(E),n(()=>d(O,`src`,_)),a(`submit`,k,T),r(`change`,k,()=>{C.clear()}),m(A,()=>w.email,e=>w.email=e),m(M,()=>w.firstname,e=>w.firstname=e),m(P,()=>w.lastname,e=>w.lastname=e),m(I,()=>w.password,e=>w.password=e),m(R,()=>w.verifPassword,e=>w.verifPassword=e),u(t,E),s()}t([`change`]);export{C as component}; import{$ as e,I as t,K as n,L as r,N as i,R as a,Z as o,dt as s,et as c,ft as l,j as u,m as d,ot as f,p,u as m,vt as h}from"../chunks/DGrvnoUE.js";import{t as g}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import"../chunks/CY9OlB4q.js";import{t as _}from"../chunks/BRXBpvt8.js";import{n as v,t as y}from"../chunks/6mSXxE57.js";import{t as b}from"../chunks/D3MDK1zR.js";import{t as x}from"../chunks/BedKI9iq.js";var S=i(`<div class="h-full w-full flex items-center public"><div class="m-auto w-96 max-w-full p-4"><img class="h-10 mb-4" alt="logo"/> <h1>Inscription</h1> <form><label for="email" class="block my-1 flex-1">Email</label> <input id="email" type="text" class="textinput"/> <!> <label for="firstname" class="block my-1 flex-1">Prénom</label> <input id="firstname" type="text" class="textinput"/> <!> <label for="lastname" class="block my-1 flex-1">Nom</label> <input id="lastname" type="text" class="textinput"/> <!> <label for="password" class="block my-1 flex-1">Mot de passe</label> <input id="password" type="password" class="textinput"/> <!> <label for="verifpassword" class="block my-1 flex-1">Vérification du mot de passe</label> <input id="verifpassword" type="password" class="textinput"/> <!> <button class="bt my-2 w-full ">Enregistrer</button> <!></form></div></div>`);function C(t,i){l(i,!0);let C=new v,w=c({email:``,firstname:``,lastname:``,password:``,verifPassword:``}),T=e=>{if(e.preventDefault(),C.clear(),b(w.email)||C.set(`email`,`Adresse email invalide !`),w.firstname||C.set(`firstname`,`Le prénom est obligatoire !`),w.lastname||C.set(`lastname`,`Le nom est obligatoire !`),w.password!==w.verifPassword&&C.set(`verifPassword`,`Les mots de pass ne correspondent pas.`),C.size==0){let e={method:`password`,email:w.email,firstname:w.firstname,lastname:w.lastname,password:w.password};x.register(e).then(()=>{g(`/`)}).catch(e=>{C.set(`submit`,`Erreur: `+e)})}};var E=S(),D=o(E),O=o(D),k=e(O,4),A=e(o(k),2);p(A),f(A,!0);var j=e(A,2);y(j,{key:`email`,get errors(){return C}});var M=e(j,4);p(M);var N=e(M,2);y(N,{key:`firstname`,get errors(){return C}});var P=e(N,4);p(P);var F=e(P,2);y(F,{key:`lastname`,get errors(){return C}});var I=e(F,4);p(I);var L=e(I,2);y(L,{key:`password`,get errors(){return C}});var R=e(L,4);p(R);var z=e(R,2);y(z,{key:`verifPassword`,get errors(){return C}});var B=e(z,4);y(B,{key:`submit`,get errors(){return C}}),h(k),h(D),h(E),n(()=>d(O,`src`,_)),a(`submit`,k,T),r(`change`,k,()=>{C.clear()}),m(A,()=>w.email,e=>w.email=e),m(M,()=>w.firstname,e=>w.firstname=e),m(P,()=>w.lastname,e=>w.lastname=e),m(I,()=>w.password,e=>w.password=e),m(R,()=>w.verifPassword,e=>w.verifPassword=e),u(t,E),s()}t([`change`]);export{C as component};
@@ -1 +1 @@
import{bt as e,dt as t,ft as n}from"../chunks/DGrvnoUE.js";import{t as r}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import"../chunks/QHwlfjO8.js";import{t as i}from"../chunks/Cyrg28w2.js";var a=e({load:()=>o}),o=async({parent:e})=>{let{me:t}=await e();return{me:t}};function s(e,a){n(a,!0),r(`/${i.current}/`,{replaceState:!0}),t()}export{s as component,a as universal}; import{bt as e,dt as t,ft as n}from"../chunks/DGrvnoUE.js";import{t as r}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import"../chunks/CY9OlB4q.js";import{t as i}from"../chunks/Cyrg28w2.js";var a=e({load:()=>o}),o=async({parent:e})=>{let{me:t}=await e();return{me:t}};function s(e,a){n(a,!0),r(`/${i.current}/`,{replaceState:!0}),t()}export{s as component,a as universal};
@@ -1 +1 @@
import{B as e,G as t,N as n,R as r,Z as i,_t as a,b as o,bt as s,dt as c,et as l,ft as u,it as d,j as f,nt as p,p as m,u as h,vt as g}from"../chunks/DGrvnoUE.js";import{t as _}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import"../chunks/QHwlfjO8.js";import{t as v}from"../chunks/BYWIgY43.js";import{t as y}from"../chunks/guSkOB4x.js";var b=s({load:()=>x}),x=({params:e})=>({title:`Nouvelle conversation`,spaceId:e.space}),S=n(`<div class="h-full w-full flex items-center public"><div class="container"><form class="request flex w-full"><input class="chatinput w-full flex-1 focus:outline-hidden focus:shadow-none focus:ring-0" type="text" placeholder="Demande ce que tu veux"/> <button class="chatbutton">Go</button></form></div></div>`);function C(n,s){u(s,!0);let b=l({}),x=d(``),C=async()=>{y.createChat(s.data.spaceId,b).then(t=>{_(`/${s.data.spaceId}/${t.id}`,{state:{prompt:e(x)}})}).catch(e=>console.log(e))};var w=S(),T=i(w),E=i(T),D=i(E);m(D),t(()=>h(D,()=>e(x),e=>p(x,e))),o(D,e=>v?.(e)),a(2),g(E),g(T),g(w),r(`submit`,E,C),f(n,w),c()}export{C as component,b as universal}; import{B as e,G as t,N as n,R as r,Z as i,_t as a,b as o,bt as s,dt as c,et as l,ft as u,it as d,j as f,nt as p,p as m,u as h,vt as g}from"../chunks/DGrvnoUE.js";import{t as _}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import"../chunks/CY9OlB4q.js";import{t as v}from"../chunks/BYWIgY43.js";import{t as y}from"../chunks/BYYkuYgk.js";var b=s({load:()=>x}),x=({params:e})=>({title:`Nouvelle conversation`,spaceId:e.space}),S=n(`<div class="h-full w-full flex items-center public"><div class="container"><form class="request flex w-full"><input class="chatinput w-full flex-1 focus:outline-hidden focus:shadow-none focus:ring-0" type="text" placeholder="Demande ce que tu veux"/> <button class="chatbutton">Go</button></form></div></div>`);function C(n,s){u(s,!0);let b=l({}),x=d(``),C=async()=>{y.createChat(s.data.spaceId,b).then(t=>{_(`/${s.data.spaceId}/${t.id}`,{state:{prompt:e(x)}})}).catch(e=>console.log(e))};var w=S(),T=i(w),E=i(T),D=i(E);m(D),t(()=>h(D,()=>e(x),e=>p(x,e))),o(D,e=>v?.(e)),a(2),g(E),g(T),g(w),r(`submit`,E,C),f(n,w),c()}export{C as component,b as universal};
@@ -1,4 +1,4 @@
import{$ as e,A as t,B as n,E as r,F as i,G as a,H as o,K as s,M as c,N as l,O as u,Q as d,R as f,S as p,T as m,U as h,Z as g,_,_t as v,a as y,at as b,b as x,bt as S,c as C,d as w,dt as ee,et as te,f as T,ft as ne,it as E,j as D,k as O,lt as k,m as A,nt as j,o as re,p as ie,pt as ae,q as M,r as N,s as P,st as oe,u as se,ut as ce,v as le,vt as F,w as I,y as ue,yt as L,z as R}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as de}from"../chunks/5WAfNqs_.js";import{t as fe}from"../chunks/BYWIgY43.js";import{t as pe}from"../chunks/guSkOB4x.js";import"../chunks/B6JECYQD.js";var me=S({load:()=>he}),he=async({params:e})=>{let t=await pe.getChat(e.space,e.conversation);return{title:t.chat.title,spaceId:e.space,chatId:e.conversation,chatWithMessage:t}},ge=l(`<a><!></a>`);function _e(e,t){var n=ge();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ve=l(`<abbr><!></abbr>`);function ye(e,t){var n=ve();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var be=l(`<address><!></address>`);function xe(e,t){var n=be();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Se=l(`<article><!></article>`);function Ce(e,t){var n=Se();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var we=l(`<aside><!></aside>`);function Te(e,t){var n=we();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ee=l(`<audio><!></audio>`);function De(e,t){var n=Ee();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Oe=l(`<b><!></b>`);function ke(e,t){var n=Oe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ae=l(`<bdi><!></bdi>`);function je(e,t){var n=Ae();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Me=l(`<bdo><!></bdo>`);function Ne(e,t){var n=Me();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Pe=l(`<blockquote><!></blockquote>`);function Fe(e,t){var n=Pe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ie=l(`<br/>`);function Le(e,t){let n=y(t,`attributes`,19,()=>({}));var r=Ie();T(r,()=>({...n()})),D(e,r)}var Re=l(`<button><!></button>`);function ze(e,t){var n=Re();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Be=l(`<canvas><!></canvas>`);function Ve(e,t){var n=Be();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var He=l(`<cite><!></cite>`);function Ue(e,t){var n=He();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var We=l(`<code><!></code>`);function Ge(e,t){var n=We();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ke=l(`<datalist><!></datalist>`);function qe(e,t){var n=Ke();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Je=l(`<dd><!></dd>`);function Ye(e,t){var n=Je();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Xe=l(`<del><!></del>`);function Ze(e,t){var n=Xe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Qe=l(`<details><!></details>`);function $e(e,t){var n=Qe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var et=l(`<dfn><!></dfn>`);function tt(e,t){var n=et();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var nt=l(`<dialog><!></dialog>`);function rt(e,t){var n=nt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var it=l(`<div><!></div>`);function at(e,t){var n=it();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ot=l(`<dl><!></dl>`);function st(e,t){var n=ot();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ct=l(`<dt><!></dt>`);function lt(e,t){var n=ct();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ut=l(`<em><!></em>`);function dt(e,t){var n=ut();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ft=l(`<embed/>`);function pt(e,t){var n=ft();T(n,()=>({...t.attributes})),R(n),D(e,n)}var mt=l(`<fieldset><!></fieldset>`);function ht(e,t){var n=mt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var gt=l(`<footer><!></footer>`);function _t(e,t){var n=gt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var vt=l(`<form><!></form>`);function yt(e,t){var n=vt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var bt=l(`<h1><!></h1>`);function xt(e,t){var n=bt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var St=l(`<h2><!></h2>`);function Ct(e,t){var n=St();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var wt=l(`<h3><!></h3>`);function Tt(e,t){var n=wt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Et=l(`<h4><!></h4>`);function Dt(e,t){var n=Et();T(nLine truncated import{$ as e,A as t,B as n,E as r,F as i,G as a,H as o,K as s,M as c,N as l,O as u,Q as d,R as f,S as p,T as m,U as h,Z as g,_,_t as v,a as y,at as b,b as x,bt as S,c as C,d as w,dt as ee,et as te,f as T,ft as ne,it as E,j as D,k as O,lt as k,m as A,nt as j,o as re,p as ie,pt as ae,q as M,r as N,s as P,st as oe,u as se,ut as ce,v as le,vt as F,w as I,y as ue,yt as L,z as R}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as de}from"../chunks/ffLBjIeN.js";import{t as fe}from"../chunks/BYWIgY43.js";import{t as pe}from"../chunks/BYYkuYgk.js";import"../chunks/B6JECYQD.js";var me=S({load:()=>he}),he=async({params:e})=>{let t=await pe.getChat(e.space,e.conversation);return{title:t.chat.title,spaceId:e.space,chatId:e.conversation,chatWithMessage:t}},ge=l(`<a><!></a>`);function _e(e,t){var n=ge();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ve=l(`<abbr><!></abbr>`);function ye(e,t){var n=ve();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var be=l(`<address><!></address>`);function xe(e,t){var n=be();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Se=l(`<article><!></article>`);function Ce(e,t){var n=Se();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var we=l(`<aside><!></aside>`);function Te(e,t){var n=we();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ee=l(`<audio><!></audio>`);function De(e,t){var n=Ee();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Oe=l(`<b><!></b>`);function ke(e,t){var n=Oe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ae=l(`<bdi><!></bdi>`);function je(e,t){var n=Ae();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Me=l(`<bdo><!></bdo>`);function Ne(e,t){var n=Me();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Pe=l(`<blockquote><!></blockquote>`);function Fe(e,t){var n=Pe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ie=l(`<br/>`);function Le(e,t){let n=y(t,`attributes`,19,()=>({}));var r=Ie();T(r,()=>({...n()})),D(e,r)}var Re=l(`<button><!></button>`);function ze(e,t){var n=Re();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Be=l(`<canvas><!></canvas>`);function Ve(e,t){var n=Be();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var He=l(`<cite><!></cite>`);function Ue(e,t){var n=He();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var We=l(`<code><!></code>`);function Ge(e,t){var n=We();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Ke=l(`<datalist><!></datalist>`);function qe(e,t){var n=Ke();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Je=l(`<dd><!></dd>`);function Ye(e,t){var n=Je();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Xe=l(`<del><!></del>`);function Ze(e,t){var n=Xe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Qe=l(`<details><!></details>`);function $e(e,t){var n=Qe();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var et=l(`<dfn><!></dfn>`);function tt(e,t){var n=et();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var nt=l(`<dialog><!></dialog>`);function rt(e,t){var n=nt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var it=l(`<div><!></div>`);function at(e,t){var n=it();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ot=l(`<dl><!></dl>`);function st(e,t){var n=ot();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ct=l(`<dt><!></dt>`);function lt(e,t){var n=ct();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ut=l(`<em><!></em>`);function dt(e,t){var n=ut();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var ft=l(`<embed/>`);function pt(e,t){var n=ft();T(n,()=>({...t.attributes})),R(n),D(e,n)}var mt=l(`<fieldset><!></fieldset>`);function ht(e,t){var n=mt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var gt=l(`<footer><!></footer>`);function _t(e,t){var n=gt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var vt=l(`<form><!></form>`);function yt(e,t){var n=vt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var bt=l(`<h1><!></h1>`);function xt(e,t){var n=bt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var St=l(`<h2><!></h2>`);function Ct(e,t){var n=St();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var wt=l(`<h3><!></h3>`);function Tt(e,t){var n=wt();T(n,()=>({...t.attributes}));var r=g(n);m(r,()=>t.children??L),F(n),D(e,n)}var Et=l(`<h4><!></h4>`);function Dt(e,t){var n=Et();T(nLine truncated
]`).replace(`lheading`,Wr).replace(`|table`,``).replace(`blockquote`,` {0,3}>`).replace(`|fences`,``).replace(`|list`,``).replace(`|html`,``).replace(`|tag`,``).getRegex()},si=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,ci=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,li=/^( {2,}|\\)\n(?!\s*$)[ \t]*/,ui=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,di=/[\p{P}\p{S}]/u,fi=/[\s\p{P}\p{S}]/u,pi=/[^\s\p{P}\p{S}]/u,mi=z(/^((?![*_])punctSpace)/,`u`).replace(/punctSpace/g,fi).getRegex(),hi=/[\p{Pi}\p{Ps}"']/u,gi=/(?!~)[\p{P}\p{S}]/u,_i=/(?!~)[\s\p{P}\p{S}]/u,vi=/(?:[^\s\p{P}\p{S}]|~)/u,yi=z(/link|precode-code|html/,`g`).replace(`link`,/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace(`precode-`,Ir?"(?<!`)()":"(^^|[^`])").replace(`code`,/(?<b>`+)[^`]+\k<b>(?!`)/).replace(`html`,/<(?! )[^<>]*?>/).getRegex(),bi=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,xi=z(bi,`u`).replace(/punct/g,di).getRegex(),Si=z(bi,`u`).replace(/punct/g,gi).getRegex(),Ci=z(/^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/,`u`).replace(/openQuote/g,hi).replace(/punct/g,di).getRegex(),wi=`^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)`,Ti=z(wi,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Ei=z(wi,`gu`).replace(/notPunctSpace/g,vi).replace(/punctSpace/g,_i).replace(/punct/g,gi).getRegex(),Di=z(`^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Oi=z(`^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),ki=z(`^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Ai=z(/^~~?(?:((?!~)punct)|[^\s~])/,`u`).replace(/punct/g,di).getRegex(),ji=z(`^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Mi=z(/\\(punct)/,`gu`).replace(/punct/g,di).getRegex(),Ni=z(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace(`scheme`,/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace(`email`,/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Pi=z(Qr).replace(`(?:-->|$)`,`-->`).getRegex(),Fi=z(`^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>`).replace(`comment`,Pi).replace(`attribute`,/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),Ii=/\[(?:\\[\s\S]|[^\[\]\\])*\]/,Li=z(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace(`brackets`,Ii).getRegex(),Ri=z(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace(`label`,Li).replace(`href`,/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace(`title`,/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),zi=z(/^!?\[(label)\]\[(ref)\]/).replace(`label`,Li).replace(`ref`,Jr).getRegex(),Bi=z(/^!?\[(ref)\](?:\[\])?/).replace(`ref`,Jr).getRegex(),Vi=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/,Hi=z(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace(`brackets`,Ii).getRegex(),Ui=z(`reflink|nolink(?!\\()`,`g`).replace(`reflink`,z(/^!?\[(label)\]\[(ref)\]/).replace(`label`,Hi).replace(`ref`,Vi).getRegex()).replace(`nolink`,z(/^!?\[(ref)\](?:\[\])?/).replace(`ref`,Vi).getRegex()).getRegex(),Wi=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,Gi=z(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g,/[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(),Ki={_backpedal:Pr,anyPunctLine truncated ]`).replace(`lheading`,Wr).replace(`|table`,``).replace(`blockquote`,` {0,3}>`).replace(`|fences`,``).replace(`|list`,``).replace(`|html`,``).replace(`|tag`,``).getRegex()},si=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,ci=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,li=/^( {2,}|\\)\n(?!\s*$)[ \t]*/,ui=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,di=/[\p{P}\p{S}]/u,fi=/[\s\p{P}\p{S}]/u,pi=/[^\s\p{P}\p{S}]/u,mi=z(/^((?![*_])punctSpace)/,`u`).replace(/punctSpace/g,fi).getRegex(),hi=/[\p{Pi}\p{Ps}"']/u,gi=/(?!~)[\p{P}\p{S}]/u,_i=/(?!~)[\s\p{P}\p{S}]/u,vi=/(?:[^\s\p{P}\p{S}]|~)/u,yi=z(/link|precode-code|html/,`g`).replace(`link`,/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace(`precode-`,Ir?"(?<!`)()":"(^^|[^`])").replace(`code`,/(?<b>`+)[^`]+\k<b>(?!`)/).replace(`html`,/<(?! )[^<>]*?>/).getRegex(),bi=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,xi=z(bi,`u`).replace(/punct/g,di).getRegex(),Si=z(bi,`u`).replace(/punct/g,gi).getRegex(),Ci=z(/^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/,`u`).replace(/openQuote/g,hi).replace(/punct/g,di).getRegex(),wi=`^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)`,Ti=z(wi,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Ei=z(wi,`gu`).replace(/notPunctSpace/g,vi).replace(/punctSpace/g,_i).replace(/punct/g,gi).getRegex(),Di=z(`^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Oi=z(`^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),ki=z(`^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Ai=z(/^~~?(?:((?!~)punct)|[^\s~])/,`u`).replace(/punct/g,di).getRegex(),ji=z(`^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)`,`gu`).replace(/notPunctSpace/g,pi).replace(/punctSpace/g,fi).replace(/punct/g,di).getRegex(),Mi=z(/\\(punct)/,`gu`).replace(/punct/g,di).getRegex(),Ni=z(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace(`scheme`,/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace(`email`,/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Pi=z(Qr).replace(`(?:-->|$)`,`-->`).getRegex(),Fi=z(`^comment|^</[a-zA-Z][a-zA-Z0-9-]*\\s*>|^<[a-zA-Z][a-zA-Z0-9-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>`).replace(`comment`,Pi).replace(`attribute`,/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),Ii=/\[(?:\\[\s\S]|[^\[\]\\])*\]/,Li=z(/(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/).replace(`brackets`,Ii).getRegex(),Ri=z(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace(`label`,Li).replace(`href`,/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace(`title`,/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),zi=z(/^!?\[(label)\]\[(ref)\]/).replace(`label`,Li).replace(`ref`,Jr).getRegex(),Bi=z(/^!?\[(ref)\](?:\[\])?/).replace(`ref`,Jr).getRegex(),Vi=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\]){1,999}/,Hi=z(/(?:[^\[\]\\`]*(?:\[(?:brackets|\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\]))){0,999}?[^\[\]\\`]*?/).replace(`brackets`,Ii).getRegex(),Ui=z(`reflink|nolink(?!\\()`,`g`).replace(`reflink`,z(/^!?\[(label)\]\[(ref)\]/).replace(`label`,Hi).replace(`ref`,Vi).getRegex()).replace(`nolink`,z(/^!?\[(ref)\](?:\[\])?/).replace(`ref`,Vi).getRegex()).getRegex(),Wi=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,Gi=z(/(?:mailto:email|xmpp:email(?:\/[A-Za-z0-9@.]+)?)/).replace(/email/g,/[A-Za-z0-9._+-]+@[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![\w-])/).getRegex(),Ki={_backpedal:Pr,anyPunctLine truncated
`),n=t.length-1;for(;n>=0&&B.blankLine.test(t[n]);)n--;return t.length-n<=2?e:t.slice(0,n+1).join(` `),n=t.length-1;for(;n>=0&&B.blankLine.test(t[n]);)n--;return t.length-n<=2?e:t.slice(0,n+1).join(`
`)}function aa(e){return e.trim().toLowerCase().toUpperCase().toLowerCase()}function oa(e,t){if(e.indexOf(t[1])===-1)return-1;let n=0;for(let r=0;r<e.length;r++)if(e[r]===`\\`)r++;else if(e[r]===t[0])n++;else if(e[r]===t[1]&&(n--,n<0))return r;return n>0?-2:-1}function sa(e,t=0){let n=t,r=``;for(let t of e)if(t===` `){let e=4-n%4;r+=` `.repeat(e),n+=e}else r+=t,n++;return r}function ca(e,t,n,r,i){let a=t.href,o=t.title||null,s=e[1].replace(i.other.outputLinkReplace,`$1`),c=e[0].charAt(0)===`!`;r.state.inLink=!0;let l=r.state.linkEmitted,u=r.state.inRawBlock;r.state.linkEmitted=!1;let d=r.inlineTokens(s),f=r.state.linkEmitted;if(r.state.linkEmitted=l,r.state.inLink=!1,!c){if(f){r.state.inRawBlock=u;return}r.state.linkEmitted=!0}return{type:c?`image`:`link`,raw:n,href:a,title:o,text:s,tokens:d}}function la(e,t,n){let r=e.match(n.other.indentCodeCompensation);if(r===null)return t;let i=r[1];return t.split(` `)}function aa(e){return e.trim().toLowerCase().toUpperCase().toLowerCase()}function oa(e,t){if(e.indexOf(t[1])===-1)return-1;let n=0;for(let r=0;r<e.length;r++)if(e[r]===`\\`)r++;else if(e[r]===t[0])n++;else if(e[r]===t[1]&&(n--,n<0))return r;return n>0?-2:-1}function sa(e,t=0){let n=t,r=``;for(let t of e)if(t===` `){let e=4-n%4;r+=` `.repeat(e),n+=e}else r+=t,n++;return r}function ca(e,t,n,r,i){let a=t.href,o=t.title||null,s=e[1].replace(i.other.outputLinkReplace,`$1`),c=e[0].charAt(0)===`!`;r.state.inLink=!0;let l=r.state.linkEmitted,u=r.state.inRawBlock;r.state.linkEmitted=!1;let d=r.inlineTokens(s),f=r.state.linkEmitted;if(r.state.linkEmitted=l,r.state.inLink=!1,!c){if(f){r.state.inRawBlock=u;return}r.state.linkEmitted=!0}return{type:c?`image`:`link`,raw:n,href:a,title:o,text:s,tokens:d}}function la(e,t,n){let r=e.match(n.other.indentCodeCompensation);if(r===null)return t;let i=r[1];return t.split(`
@@ -69,4 +69,4 @@ Please report this to https://github.com/markedjs/marked.`,e){let e=`<p>An error
`))return!0;switch(e.type){case`heading`:case`hr`:return e.raw.endsWith(` `))return!0;switch(e.type){case`heading`:case`hr`:return e.raw.endsWith(`
`);default:return!1}};hasPotentialReferenceUse=e=>!e.includes(`[`)||!e.includes(`]`)?!1:pc.test(e)||mc.test(e);hasPotentialReferenceUseOutsideDefinitions=e=>{if(!e.includes(`[`)||!e.includes(`]`))return!1;for(let t of e.split(` `);default:return!1}};hasPotentialReferenceUse=e=>!e.includes(`[`)||!e.includes(`]`)?!1:pc.test(e)||mc.test(e);hasPotentialReferenceUseOutsideDefinitions=e=>{if(!e.includes(`[`)||!e.includes(`]`))return!1;for(let t of e.split(`
`))if(!hc.test(t)&&this.hasPotentialReferenceUse(t))return!0;return!1};hasReferenceDefinition=e=>!e.includes(`[`)||!e.includes(`]`)?!1:hc.test(e);appendIntroducesMatch=(e,t)=>{if(t(e.slice(this.prevSource.length)))return!0;let n=this.prevSource.lastIndexOf(` `))if(!hc.test(t)&&this.hasPotentialReferenceUse(t))return!0;return!1};hasReferenceDefinition=e=>!e.includes(`[`)||!e.includes(`]`)?!1:hc.test(e);appendIntroducesMatch=(e,t)=>{if(t(e.slice(this.prevSource.length)))return!0;let n=this.prevSource.lastIndexOf(`
`)+1;return!t(this.prevSource.slice(n))&&t(e.slice(n))};isAppendOnlyUpdate=e=>this.prevSource!==``&&e.startsWith(this.prevSource);hasNewReferenceDefinition=e=>e.startsWith(this.prevSource)?this.appendIntroducesMatch(e,this.hasReferenceDefinition):!1;appendedDefinitionInvalidatesTail=e=>this.prevHasPotentialReferenceUse&&this.hasNewReferenceDefinition(e);canUseTailWindow=(e,t,n=this.isAppendOnlyUpdate(e),r=this.appendedDefinitionInvalidatesTail(e))=>{if(this.tailWindowDisabled||this.prevSource===``||this.prevTokens.length===0||!n||t.reparseOffset<=0||r)return!1;if(this.prevHasReferenceDefinition){let n=e.slice(t.reparseOffset);if(this.hasPotentialReferenceUseOutsideDefinitions(n))return!1}return!0};parseSource=(e,t,n,r)=>{if(!this.canUseTailWindow(e,t,n,r))return{tokens:$s(e,this.options,!1),tailTokens:[],usedTailWindow:!1};let i=$s(e.slice(t.reparseOffset),this.options,!1);return{tokens:[...this.prevTokens.slice(0,t.prefixCount),...i],tailTokens:i,usedTailWindow:!0}};hasAnyHtmlSpanMismatch=e=>e.some(this.hasHtmlSpanMismatch);getNextTailWindowBoundary=(e,t,n)=>{if(e.length===0||n)return{prefixCount:0,reparseOffset:0};let r=e[e.length-1];return this.isStableAtSourceEnd(r)?{prefixCount:e.length,reparseOffset:t}:{prefixCount:e.length-1,reparseOffset:t-this.getTokenSourceLength(r)}};updateCachedState=(e,t,n,r)=>{let i=t.usedTailWindow?this.prevHasHtmlSpanMismatch||this.hasAnyHtmlSpanMismatch(t.tailTokens):this.hasAnyHtmlSpanMismatch(t.tokens);this.prevHasPotentialReferenceUse=n?this.prevHasPotentialReferenceUse||this.appendIntroducesMatch(e,this.hasPotentialReferenceUseOutsideDefinitions):this.hasPotentialReferenceUseOutsideDefinitions(e),this.prevHasReferenceDefinition=n?this.prevHasReferenceDefinition||r:this.hasReferenceDefinition(e),this.prevSource=e,this.prevTokens=t.tokens,this.prevHasHtmlSpanMismatch=i,this.prevTailWindowBoundary=this.getNextTailWindowBoundary(t.tokens,e.length,i)};isReferenceSensitiveUpdate=(e,t,n)=>t?n:(this.prevHasReferenceDefinition||this.hasReferenceDefinition(e))&&(this.hasPotentialReferenceUse(this.prevSource)||this.hasPotentialReferenceUse(e));update=e=>{let t=this.getTailWindowBoundary(),n=this.isAppendOnlyUpdate(e),r=n&&this.appendIntroducesMatch(e,this.hasReferenceDefinition),i=this.prevHasPotentialReferenceUse&&r,a=this.parseSource(e,t,n,i),o=a.tokens;if(typeof this.options.walkTokens==`function`)for(let e of o)this.options.walkTokens(e);let s=this.isReferenceSensitiveUpdate(e,n,i),c=n&&!s,l=0,u=a.usedTailWindow?t.reparseOffset:0;if(!s){let e=Math.min(this.prevTokens.length,o.length);for(;l<e;){let e=this.prevTokens[l],n=o[l];if(!oc(e,n))break;a.usedTailWindow?u!==void 0&&l>=t.prefixCount&&(u+=this.getTokenSourceLength(n)):u!==void 0&&(this.hasHtmlSpanMismatch(n)?u=void 0:u+=this.getTokenSourceLength(n)),l++}}return this.updateCachedState(e,a,n,r),{tokens:o,divergeAt:l,divergeOffset:u,canReuse:c,usedTailWindow:a.usedTailWindow}}},_c=e=>typeof e==`object`&&!!e,vc=e=>_c(e)&&typeof e.id==`string`&&typeof e.text==`string`,yc=e=>{let t=``;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n),i=e[n];t+=/[A-Za-z0-9_-]/.test(i)?i:`~${r.toString(16).padStart(4,`0`)}`}return t},bc=(e,t=1)=>{let n=`fnref-${yc(e)}`;return t===1?n:`${n}:ref:${t}`},xc=e=>{let t=new WeakMap,n=new WeakMap,r=new Map,i=new Map,a=new Set,o=[],s=e=>{if(Array.isArray(e))for(let t of e)Array.isArray(t)?s(t):_c(t)&&c(t)},c=e=>{if(e.type===`footnoteRef`&&typeof e.id==`string`){let n=(r.get(e.id)??0)+1,a=bc(e.id,n);r.set(e.id,n),t.set(e,Object.freeze({referenceId:a}));let o=i.get(e.id);o?o.push(a):i.set(e.id,[a])}else if(e.type===`footnoteSection`&&Array.isArray(e.footnotes)){let t=[];for(let n of e.footnotes)!vc(n)||a.has(n.id)||(a.add(n.id),t.push({id:n.id,text:n.text}));o.push({token:e,footnotes:t})}e.type!==`image`&&e.type!==`code`&&e.type!==`codespan`&&(s(e.tokens),s(e.items),s(e.header),s(e.rows))};s(e);for(let e of o){let t=e.footnotes.map(e=>Object.freeze({...e,backrefs:Object.freeze([...i.get(e.id)??[]])}));n.set(e.token,Object.freeze({footnotes:Object.freeze(t)}))}return Object.freeze({referenceProps:t,sectionProps:n})},Sc=1e6,Cc=e=>typeof e==`object`&&!!e&&`offset`in e,wc=(e,t,{currentBufferLength:n=0,maxOffsetGap:r=Sc}={})=>typeof e==`string`?t===`offset`?{kind:`drop`,message:`offset mode active, string chunk dropped. Call resetStream() before switching streaming input modes.`}:{kind:`append`,value:e,nextMode:`append`}:!Cc(e)||typeof e.value!=`string`?{kind:`drop`,message:`Invalid chunk object passed to writeChunk(); expected { value: string, offset: number }.`}:!Number.isSafeInteger(e.offset)||e.offset<0?{kind:`drop`,message:`Invalid offset chunk passed to writeChunk(); offset must be a non-negative safe integer.`}:t===`append`?{kind:`drop`,message:`append mode active, offset chunk dropped. Call resetStream() before switching streaming input modes.`}:e.offset-n>r?{kind:`drop`,message:`offset chunk skipped: offset ${e.offset} is more than ${r} chars beyond the current buffer length (${n}).`}:{kind:`offset`,ch Line truncated `)+1;return!t(this.prevSource.slice(n))&&t(e.slice(n))};isAppendOnlyUpdate=e=>this.prevSource!==``&&e.startsWith(this.prevSource);hasNewReferenceDefinition=e=>e.startsWith(this.prevSource)?this.appendIntroducesMatch(e,this.hasReferenceDefinition):!1;appendedDefinitionInvalidatesTail=e=>this.prevHasPotentialReferenceUse&&this.hasNewReferenceDefinition(e);canUseTailWindow=(e,t,n=this.isAppendOnlyUpdate(e),r=this.appendedDefinitionInvalidatesTail(e))=>{if(this.tailWindowDisabled||this.prevSource===``||this.prevTokens.length===0||!n||t.reparseOffset<=0||r)return!1;if(this.prevHasReferenceDefinition){let n=e.slice(t.reparseOffset);if(this.hasPotentialReferenceUseOutsideDefinitions(n))return!1}return!0};parseSource=(e,t,n,r)=>{if(!this.canUseTailWindow(e,t,n,r))return{tokens:$s(e,this.options,!1),tailTokens:[],usedTailWindow:!1};let i=$s(e.slice(t.reparseOffset),this.options,!1);return{tokens:[...this.prevTokens.slice(0,t.prefixCount),...i],tailTokens:i,usedTailWindow:!0}};hasAnyHtmlSpanMismatch=e=>e.some(this.hasHtmlSpanMismatch);getNextTailWindowBoundary=(e,t,n)=>{if(e.length===0||n)return{prefixCount:0,reparseOffset:0};let r=e[e.length-1];return this.isStableAtSourceEnd(r)?{prefixCount:e.length,reparseOffset:t}:{prefixCount:e.length-1,reparseOffset:t-this.getTokenSourceLength(r)}};updateCachedState=(e,t,n,r)=>{let i=t.usedTailWindow?this.prevHasHtmlSpanMismatch||this.hasAnyHtmlSpanMismatch(t.tailTokens):this.hasAnyHtmlSpanMismatch(t.tokens);this.prevHasPotentialReferenceUse=n?this.prevHasPotentialReferenceUse||this.appendIntroducesMatch(e,this.hasPotentialReferenceUseOutsideDefinitions):this.hasPotentialReferenceUseOutsideDefinitions(e),this.prevHasReferenceDefinition=n?this.prevHasReferenceDefinition||r:this.hasReferenceDefinition(e),this.prevSource=e,this.prevTokens=t.tokens,this.prevHasHtmlSpanMismatch=i,this.prevTailWindowBoundary=this.getNextTailWindowBoundary(t.tokens,e.length,i)};isReferenceSensitiveUpdate=(e,t,n)=>t?n:(this.prevHasReferenceDefinition||this.hasReferenceDefinition(e))&&(this.hasPotentialReferenceUse(this.prevSource)||this.hasPotentialReferenceUse(e));update=e=>{let t=this.getTailWindowBoundary(),n=this.isAppendOnlyUpdate(e),r=n&&this.appendIntroducesMatch(e,this.hasReferenceDefinition),i=this.prevHasPotentialReferenceUse&&r,a=this.parseSource(e,t,n,i),o=a.tokens;if(typeof this.options.walkTokens==`function`)for(let e of o)this.options.walkTokens(e);let s=this.isReferenceSensitiveUpdate(e,n,i),c=n&&!s,l=0,u=a.usedTailWindow?t.reparseOffset:0;if(!s){let e=Math.min(this.prevTokens.length,o.length);for(;l<e;){let e=this.prevTokens[l],n=o[l];if(!oc(e,n))break;a.usedTailWindow?u!==void 0&&l>=t.prefixCount&&(u+=this.getTokenSourceLength(n)):u!==void 0&&(this.hasHtmlSpanMismatch(n)?u=void 0:u+=this.getTokenSourceLength(n)),l++}}return this.updateCachedState(e,a,n,r),{tokens:o,divergeAt:l,divergeOffset:u,canReuse:c,usedTailWindow:a.usedTailWindow}}},_c=e=>typeof e==`object`&&!!e,vc=e=>_c(e)&&typeof e.id==`string`&&typeof e.text==`string`,yc=e=>{let t=``;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n),i=e[n];t+=/[A-Za-z0-9_-]/.test(i)?i:`~${r.toString(16).padStart(4,`0`)}`}return t},bc=(e,t=1)=>{let n=`fnref-${yc(e)}`;return t===1?n:`${n}:ref:${t}`},xc=e=>{let t=new WeakMap,n=new WeakMap,r=new Map,i=new Map,a=new Set,o=[],s=e=>{if(Array.isArray(e))for(let t of e)Array.isArray(t)?s(t):_c(t)&&c(t)},c=e=>{if(e.type===`footnoteRef`&&typeof e.id==`string`){let n=(r.get(e.id)??0)+1,a=bc(e.id,n);r.set(e.id,n),t.set(e,Object.freeze({referenceId:a}));let o=i.get(e.id);o?o.push(a):i.set(e.id,[a])}else if(e.type===`footnoteSection`&&Array.isArray(e.footnotes)){let t=[];for(let n of e.footnotes)!vc(n)||a.has(n.id)||(a.add(n.id),t.push({id:n.id,text:n.text}));o.push({token:e,footnotes:t})}e.type!==`image`&&e.type!==`code`&&e.type!==`codespan`&&(s(e.tokens),s(e.items),s(e.header),s(e.rows))};s(e);for(let e of o){let t=e.footnotes.map(e=>Object.freeze({...e,backrefs:Object.freeze([...i.get(e.id)??[]])}));n.set(e.token,Object.freeze({footnotes:Object.freeze(t)}))}return Object.freeze({referenceProps:t,sectionProps:n})},Sc=1e6,Cc=e=>typeof e==`object`&&!!e&&`offset`in e,wc=(e,t,{currentBufferLength:n=0,maxOffsetGap:r=Sc}={})=>typeof e==`string`?t===`offset`?{kind:`drop`,message:`offset mode active, string chunk dropped. Call resetStream() before switching streaming input modes.`}:{kind:`append`,value:e,nextMode:`append`}:!Cc(e)||typeof e.value!=`string`?{kind:`drop`,message:`Invalid chunk object passed to writeChunk(); expected { value: string, offset: number }.`}:!Number.isSafeInteger(e.offset)||e.offset<0?{kind:`drop`,message:`Invalid offset chunk passed to writeChunk(); offset must be a non-negative safe integer.`}:t===`append`?{kind:`drop`,message:`append mode active, offset chunk dropped. Call resetStream() before switching streaming input modes.`}:e.offset-n>r?{kind:`drop`,message:`offset chunk skipped: offset ${e.offset} is more than ${r} chars beyond the current buffer length (${n}).`}:{kind:`offset`,ch Line truncated
@@ -0,0 +1 @@
import{$ as e,A as t,B as n,E as r,I as i,K as a,L as o,N as s,Q as c,Z as l,at as u,bt as d,dt as f,et as p,ft as m,g as h,it as g,j as _,k as v,m as y,nt as b,p as x,u as S,vt as C}from"../chunks/DGrvnoUE.js";import{n as w}from"../chunks/BZuNOv8h.js";import"../chunks/xihTtKlq.js";import"../chunks/CY9OlB4q.js";import{t as T}from"../chunks/BYYkuYgk.js";import{n as E,r as D,t as O}from"../chunks/Bht2nTIZ.js";var k=d({load:()=>A}),A=async({params:e})=>({title:`Historique`,conversations:await T.allChats(e.space,0),tasks:await D.listTasks(e.space),space:e.space}),j=s(`<option> </option>`),M=s(`<div class="formelement w-60"><select class="textinput"><option>Toutes les tâches</option><!></select></div>`),N=s(`<span class="mx-1">·</span> <a class="text-sky-700 dark:text-sky-300">Tâche planifiée</a>`,1),P=s(`<div class="dark:bg-stone-800 rounded p-2 my-2"><div class="flex flex-row items-center"><div class="flex-1 font-bold text-base"><a> </a></div> <button class="bt small" title="Supprimer la conversation"><i class="icon-trash-empty"></i></button></div> <div class="mt-1 text-xs text-stone-500"><span title="Créée le"> </span> <span class="mx-1">·</span> <span title="Dernière interaction"> </span> <!></div></div>`),ee=s(`<p class="my-4 text-center text-sm text-stone-500">Aucune conversation trouvée.</p>`),te=s(`<div class="my-4 text-center"><button class="bt small"> </button></div>`),F=s(`<div class="container"><div class="my-2 flex gap-2"><div class="formelement flex-1"><input class="textinput" type="search" placeholder="Rechercher une conversation..."/></div> <!></div> <!> <!> <!></div> <!>`,1);function I(i,s){m(s,!0);let d=e=>{if(!e)return`—`;let t=new Date(e);return Number.isNaN(t.getTime())?`—`:t.toLocaleString(`fr-FR`,{day:`numeric`,month:`long`,year:`numeric`,hour:`2-digit`,minute:`2-digit`})},D=g(``),k=g(``),A=g(p(s.data.conversations)),I=g(0),L=g(!1),R=g(null),z=u(()=>n(A).length===(n(I)+1)*20),B=u(()=>s.data.tasks??[]),V=async()=>{b(I,0);let e=n(k)||void 0,t=await T.allChats(s.data.space,0,n(D),e);b(A,t??[],!0)},H,U=()=>{H!==void 0&&clearTimeout(H),H=setTimeout(V,300)},W=()=>{V()},G=async()=>{if(!n(L)){b(L,!0);try{let e=n(k)||void 0,t=await T.allChats(s.data.space,n(I)+1,n(D),e)??[];b(A,[...n(A),...t],!0),b(I,n(I)+1)}catch{E(`failure`,`Erreur lors du chargement des conversations`)}finally{b(L,!1)}}},K=async()=>{if(n(R))try{await T.deleteChat(s.data.space,n(R).id),E(`success`,`Conversation supprimée`),await w(),await V()}catch{E(`failure`,`Erreur lors de la suppression de la conversation`)}finally{b(R,null)}};var q=F(),J=c(q),Y=l(J),X=l(Y),Z=l(X);x(Z),C(X);var ne=e(X,2),re=i=>{var s=M(),c=l(s),u=l(c);u.value=u.__value=``;var d=e(u);r(d,17,()=>n(B),e=>e.id,(e,r)=>{var i=j(),o=l(i,!0);C(i);var s={};a(()=>{t(o,n(r).label),s!==(s=n(r).id)&&(i.value=(i.__value=n(r).id)??``)}),_(e,i)}),C(c),C(s),o(`change`,c,W),h(c,()=>n(k),e=>b(k,e)),_(i,s)};v(ne,e=>{n(B).length>0&&e(re)}),C(Y);var Q=e(Y,2);r(Q,17,()=>n(A),e=>e.id,(r,i)=>{var u=P(),f=l(u),p=l(f),m=l(p),h=l(m,!0);C(m),C(p);var g=e(p,2);C(f);var x=e(f,2),S=l(x),w=l(S);C(S);var T=e(S,4),E=l(T);C(T);var D=e(T,2),O=t=>{var r=N(),o=e(c(r),2);a(()=>y(o,`href`,`/${s.data.space}/tasks?task=${n(i).taskId}`)),_(t,r)};v(D,e=>{n(i).taskId&&e(O)}),C(x),C(u),a((e,r)=>{y(m,`href`,`/${s.data.space}/${n(i).id}`),t(h,n(i).title),t(w,`Créée le ${e??``}`),t(E,`Dernière interaction : ${r??``}`)},[()=>d(n(i)._date_created),()=>d(n(i)._date_updated)]),o(`click`,g,()=>b(R,n(i),!0)),_(r,u)});var $=e(Q,2),ie=e=>{var t=ee();_(e,t)};v($,e=>{n(A).length===0&&e(ie)});var ae=e($,2),oe=e=>{var r=te(),i=l(r),s=l(i,!0);C(i),C(r),a(()=>{i.disabled=n(L),t(s,n(L)?`Chargement...`:`Charger plus`)}),o(`click`,i,G),_(e,r)};v(ae,e=>{n(z)&&e(oe)}),C(J);var se=e(J,2);{let e=u(()=>n(R)!==null),t=u(()=>`Voulez-vous vraiment supprimer « ${n(R)?.title} » ? Cette action est irréversible.`);O(se,{get open(){return n(e)},title:`Supprimer la conversation`,get message(){return n(t)},confirmLabel:`Supprimer`,onConfirm:K,onCancel:()=>b(R,null)})}o(`input`,Z,U),S(Z,()=>n(D),e=>b(D,e)),_(i,q),f()}i([`input`,`change`,`click`]);export{I as component,k as universal};
@@ -1,4 +0,0 @@
import{$ as e,A as t,B as n,C as r,E as i,I as a,K as o,L as s,M as c,N as l,Q as u,R as d,X as f,Z as p,a as m,at as h,bt as g,dt as _,et as v,ft as y,it as b,j as x,k as S,m as C,nt as w,p as T,u as E,vt as D}from"../chunks/DGrvnoUE.js";import{n as O}from"../chunks/Soo4K-rz.js";import"../chunks/xihTtKlq.js";import"../chunks/QHwlfjO8.js";import{t as k}from"../chunks/guSkOB4x.js";var A=g({load:()=>j}),j=async({params:e})=>({title:`Historique`,conversations:await k.allChats(e.space,0),space:e.space}),M=0,N=v([]),P=(e,t)=>{N.push({id:M++,type:e,text:t,status:`appearing`})},F=e=>e;function I(e){let t=e-1;return t*t*t+1}function L(e,{delay:t=0,duration:n=400,easing:r=F}={}){let i=+getComputedStyle(e).opacity;return{delay:t,duration:n,easing:r,css:e=>`opacity: ${e*i}`}}function R(e,{delay:t=0,duration:n=400,easing:r=I,start:i=0,opacity:a=0}={}){let o=getComputedStyle(e),s=+o.opacity,c=o.transform===`none`?``:o.transform,l=1-i,u=s*(1-a);return{delay:t,duration:n,easing:r,css:(e,t)=>`
transform: ${c} scale(${1-l*t});
opacity: ${s-u*t}
`}}var z=l(`<div class="fixed inset-0 z-50 flex items-center justify-center p-4"><button type="button" class="absolute inset-0 cursor-default bg-black/50" aria-label="Fermer"></button> <div class="relative w-full max-w-sm rounded-lg bg-stone-50 p-4 shadow-xl dark:bg-stone-900" role="dialog" aria-modal="true" aria-labelledby="confirm-dialog-title"><div class="flex items-center gap-3"><div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-600 dark:bg-red-950 dark:text-red-400"><i class="icon-trash-empty"></i></div> <h2 id="confirm-dialog-title" class="text-base font-bold"> </h2></div> <p class="mt-3 text-sm text-stone-600 dark:text-stone-400"> </p> <div class="mt-4 flex justify-end gap-2"><button type="button" class="bt small"> </button> <button type="button" class="bt small danger"> </button></div></div></div>`);function B(n,i){y(i,!0);let a=m(i,`open`,3,!1),l=m(i,`title`,3,``),h=m(i,`message`,3,``),g=m(i,`confirmLabel`,3,`Confirmer`),v=m(i,`cancelLabel`,3,`Annuler`),b=()=>i.onCancel?.(),C=e=>{a()&&e.key===`Escape`&&b()};var w=c();d(`keydown`,f,C);var T=u(w),E=n=>{var a=z(),c=p(a),u=e(c,2),d=p(u),f=e(p(d),2),m=p(f,!0);D(f),D(d);var _=e(d,2),y=p(_,!0);D(_);var S=e(_,2),C=p(S),w=p(C,!0);D(C);var T=e(C,2),E=p(T,!0);D(T),D(S),D(u),D(a),o(()=>{t(m,l()),t(y,h()),t(w,v()),t(E,g())}),s(`click`,c,b),r(3,c,()=>L,()=>({duration:150})),s(`click`,C,b),s(`click`,T,function(...e){i.onConfirm?.apply(this,e)}),r(3,u,()=>R,()=>({duration:150,start:.95})),x(n,a)};S(T,e=>{a()&&e(E)}),x(n,w),_()}a([`click`]);var V=l(`<div class="dark:bg-stone-800 rounded p-2 my-2"><div class="flex flex-row items-center"><div class="flex-1 font-bold text-base"><a> </a></div> <button class="bt small" title="Supprimer la conversation"><i class="icon-trash-empty"></i></button></div> <span class="text-xs"> </span></div>`),H=l(`<p class="my-4 text-center text-sm text-stone-500">Aucune conversation trouvée.</p>`),U=l(`<div class="my-4 text-center"><button class="bt small"> </button></div>`),W=l(`<div class="container"><div class="formelement my-2"><input class="textinput" type="search" placeholder="Rechercher une conversation..."/></div> <!> <!> <!></div> <!>`,1);function G(r,a){y(a,!0);let c=b(``),l=b(v(a.data.conversations)),d=b(0),f=b(!1),m=b(null),g=h(()=>n(l).length===(n(d)+1)*20),A,j=()=>{A!==void 0&&clearTimeout(A),A=setTimeout(async()=>{w(d,0);let e=await k.allChats(a.data.space,0,n(c));w(l,e??[],!0)},300)},M=async()=>{if(!n(f)){w(f,!0);try{let e=await k.allChats(a.data.space,n(d)+1,n(c))??[];w(l,[...n(l),...e],!0),w(d,n(d)+1)}catch{P(`failure`,`Erreur lors du chargement des conversations`)}finally{w(f,!1)}}},N=async()=>{if(n(m))try{await k.deleteChat(a.data.space,n(m).id),P(`success`,`Conversation supprimée`),await O();let e=await k.allChats(a.data.space,0,n(c));w(l,e??[],!0),w(d,0)}catch{P(`failure`,`Erreur lors de la suppression de la conversation`)}finally{w(m,null)}};var F=W(),I=u(F),L=p(I),R=p(L);T(R),D(L);var z=e(L,2);i(z,17,()=>n(l),e=>e.id,(r,i)=>{var c=V(),l=p(c),u=p(l),d=p(u),f=p(d,!0);D(d),D(u);var h=e(u,2);D(l);var g=e(l,2),_=p(g,!0);D(g),D(c),o(()=>{C(d,`href`,`/${a.data.space}/${n(i).id}`),t(f,n(i).title),t(_,n(i)._date_created)}),s(`click`,h,()=>w(m,n(i),!0)),x(r,c)});var G=e(z,2),K=e=>{var t=H();x(e,t)};S(G,e=>{n(l).length===0&&e(K)});var q=e(G,2),J=e=>{var r=U(),i=p(r),a=p(i,!0);D(i),D(r),o(()=>{i.disabled=n(f),t(a,n(f)?`Chargement...`:`Charger plus`)}),s(`click`,i,M),x(e,r)};S(q,e=>{n(g)&&e(J)}),D(I);var Y=e(I,2);{let e=h(()=>n(m)!==null),t=h(()=>`Voulez-vous vraiment supprimer « ${n(m)?.title} » ? Cette action est irréversible.`);B(Y,{get open(){return n(e)},title:`Supprimer la conversation`,get message(){return n(t)},confirmLabel:`Supprimer`,onConfirm:N,onCancel:()=>w(m,null)})}s(`input`,R,j),E(R,()=>n(c),e=>w(c,e)),x(r,F),_()}a([`input`,`click`]);export{G as component,A as universal};
@@ -1 +1 @@
import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,nt as E,p as D,st as O,u as k,v as A,vt as j}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as M}from"../chunks/DqlBPR2w.js";import{t as N}from"../chunks/Cyrg28w2.js";import{t as P}from"../chunks/BI_fD_HY.js";import{n as F,t as I}from"../chunks/6mSXxE57.js";import{t as L}from"../chunks/CUminYLk.js";var R={getAgents:e=>M.get(`/agent/${e}`),getAgent:(e,t)=>M.get(`/agent/${e}/${t}`),createAgent:(e,t)=>M.post(`/agent/${e}`,t),updateAgent:(e,t)=>M.put(`/agent/${e}`,t),deleteAgent:(e,t)=>M.delete(`/agent/${e}/${t}`)},z={getSpace:e=>M.get(`/team/${e}`),updateSpace:(e,t)=>M.put(`/team/${e}`,t)},B=y({load:()=>V}),V=async({params:e})=>({title:`Paramétrage : Agents`,back:`../settings`,space:await z.getSpace(e.space),agents:await R.getAgents(e.space),providersModels:await P.getProvidersModels(e.space)}),H=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché"/> <!></div> <div class="formelement"><label for="systemPrompt">Prompt système</label> <textarea rows="10" id="systemPrompt" class="areainput" placeholder="prompt système"></textarea> <!></div> <div class="formelement"><label for="type" class="block my-1 flex-1">Type</label> <!> <!></div> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function U(t,r){S(r,!0);let a=_(r,`item`,7),o=C(x(p(()=>a().defaultProviderId+`|`+a().defaultModelId))),c=e=>e.group,l=e=>{e.focus()},u=e=>{e.preventDefault();let t=n(o).split(`|`);n(o).length>1?(a().defaultProviderId=t[0],a().defaultModelId=t[1]):(a().defaultProviderId=``,a().defaultModelId=``),r.onSave(a())},d=e=>{e.preventDefault(),r.onCancel()};var m=H(),y=h(m),T=h(y),A=h(T),M=e(h(A),2);D(M),i(()=>k(M,()=>a().name,e=>a().name=e)),v(M,e=>l?.(e));var N=e(M,2);I(N,{key:`name`,get errors(){return r.errors}}),j(A);var P=e(A,2),F=e(h(P),2);O(F);var R=e(F,2);I(R,{key:`baseUrl`,get errors(){return r.errors}}),j(P);var z=e(P,2),B=e(h(z),2);L(B,{get items(){return r.providersModels},valueMode:`id`,groupBy:c,get value(){return n(o)},set value(e){E(o,e,!0)}});var V=e(B,2);I(V,{key:`model`,get errors(){return r.errors}}),j(z);var U=e(z,2),W=h(U);g(2),j(U),j(T),j(y),j(m),f(`submit`,T,u),s(`change`,T,()=>{r.errors.clear()}),k(F,()=>a().systemPrompt,e=>a().systemPrompt=e),s(`click`,W,d),w(t,m),b()}a([`change`,`click`]);var W=l(`<button class="rounded w-full border border-dashed p-2 border-stone-500 cursor-pointer" tabindex="0"><i class="icon-plus"></i> Ajouter un agent</button>`),G=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span></div> <button title="Modifier">Agent par défaut</button> <button class="bt small mx-1" title="Modifier"><i class="icon-edit"></i></button> <button class="bt small mx-1" title="Supprimer"><i class="icon-trash-empty"></i></button></div>`),K=l(`<div class="container"><!> <!></div>`);function q(i,a){S(a,!0);let l=C(x(p(()=>a.data.space))),g=C(x(p(()=>a.data.agents))),_=C(!1),v=C(null),y=C(x({})),D=new F,O=()=>{n(v)||(D.clear(),E(y,{},!0),E(_,!0))},k=()=>{E(_,!1)},M=e=>{e.name||D.set(`name`,`Le nom est obligatoire !`),(e.defaultProviderId===``||e.defaultModelId===``)&&D.set(`model`,`Le modèle est obligatoire !`),D.size===0&&R.createAgent(a.data.space.id,e).then(e=>{n(g).push(e),E(_,!1),E(y,{},!0)}).catch(e=>{console.log(e)})},P=()=>{E(v,null),E(y,{},!0)},I=e=>{e.name||D.set(`name`,`Le nom est obligatoire !`),D.size===0&&R.updateAgent(a.data.space.id,e).then(e=>{E(g,n(g).map(t=>e.id===t.id?e:t),!0),E(v,null),E(y,{},!0)}).catch(e=>{console.log(e)})},L=async e=>{D.clear(),!n(_)&&R.getAgent(a.data.space.id,e).then(t=>{E(g,n(g).filter(e=>e.id===t.id?t:e),!0),E(v,e,!0)}).catch(e=>console.log(e))},B=e=>{R.deleteAgent(a.data.space.id,e).then(()=>{E(g,n(g).filter(t=>t.id!==e),!0)}).catch(e=>{console.log(e)})},V=e=>{let t=n(l);t.defaultAgentId=e,z.updateSpace(t.id,t).then(e=>{N.spaces.map(t=>t.id===N.current?e:t),E(l,e,!0)}).catch(e=>{console.log(e)})},H=e=>{e.key===`Escape`&&P()};var q=K();f(`keydown`,m,H);var J=h(q),Y=e=>{var t=c(),r=d(t);u(r,()=>`new`,e=>{U(e,{get item(){return n(y)},get errors(){return D},onSave:M,onCancel:k,get providersModels(){return a.data.providersModels}})}),w(e,t)},X=e=>{var t=W();s(`click`,t,O),w(e,t)};T(J,e=>{n(_)?e(Y):e(X,-1)});var Z=e(J,2);r(Z,17,()=>n(g),e=>e.id,(r,i)=>{var f=c(),p=d(f),m=e=>{var t=c(),r=d(t);u(r,()=>n(i).id,e=>{U(e,{get item(){return n(i)},get errors(){return D},onSave:I,onCancel:P,get providersModels(){return a.data.providersModels}})}),w(e,t)},g=r=>{var a=G(),c=h(a),u=h(c),d=h(u,!0);j(u),j(c);var f=e(c,2);let p;var m=e(f,2),g=e(m,2);j(a),o(()=>{t(d,n(i).name),p=A(f,1,`bt small mx- Line truncated import{$ as e,A as t,B as n,E as r,G as i,I as a,K as o,L as s,M as c,N as l,O as u,Q as d,R as f,U as p,X as m,Z as h,_t as g,a as _,b as v,bt as y,dt as b,et as x,ft as S,it as C,j as w,k as T,nt as E,p as D,st as O,u as k,v as A,vt as j}from"../chunks/DGrvnoUE.js";import"../chunks/xihTtKlq.js";import{t as M}from"../chunks/DtfiK5fE.js";import{t as N}from"../chunks/Cyrg28w2.js";import{t as P}from"../chunks/BeIYuf23.js";import{n as F,t as I}from"../chunks/6mSXxE57.js";import{t as L}from"../chunks/DdGy_ePN.js";var R={getAgents:e=>M.get(`/agent/${e}`),getAgent:(e,t)=>M.get(`/agent/${e}/${t}`),createAgent:(e,t)=>M.post(`/agent/${e}`,t),updateAgent:(e,t)=>M.put(`/agent/${e}`,t),deleteAgent:(e,t)=>M.delete(`/agent/${e}/${t}`)},z={getSpace:e=>M.get(`/team/${e}`),updateSpace:(e,t)=>M.put(`/team/${e}`,t)},B=y({load:()=>V}),V=async({params:e})=>({title:`Paramétrage : Agents`,back:`../settings`,space:await z.getSpace(e.space),agents:await R.getAgents(e.space),providersModels:await P.getProvidersModels(e.space)}),H=l(`<div><div class="formgroup my-2"><form><div class="formelement"><label for="name">Nom</label> <input id="name" type="text" class="textinput" placeholder="nom affiché"/> <!></div> <div class="formelement"><label for="systemPrompt">Prompt système</label> <textarea rows="10" id="systemPrompt" class="areainput" placeholder="prompt système"></textarea> <!></div> <div class="formelement"><label for="type" class="block my-1 flex-1">Type</label> <!> <!></div> <div class="text-right"><button type="button" class="bt">Annuler</button> <button type="submit" class="bt mx-4">Enregistrer</button></div></form></div></div>`);function U(t,r){S(r,!0);let a=_(r,`item`,7),o=C(x(p(()=>a().defaultProviderId+`|`+a().defaultModelId))),c=e=>e.group,l=e=>{e.focus()},u=e=>{e.preventDefault();let t=n(o).split(`|`);n(o).length>1?(a().defaultProviderId=t[0],a().defaultModelId=t[1]):(a().defaultProviderId=``,a().defaultModelId=``),r.onSave(a())},d=e=>{e.preventDefault(),r.onCancel()};var m=H(),y=h(m),T=h(y),A=h(T),M=e(h(A),2);D(M),i(()=>k(M,()=>a().name,e=>a().name=e)),v(M,e=>l?.(e));var N=e(M,2);I(N,{key:`name`,get errors(){return r.errors}}),j(A);var P=e(A,2),F=e(h(P),2);O(F);var R=e(F,2);I(R,{key:`baseUrl`,get errors(){return r.errors}}),j(P);var z=e(P,2),B=e(h(z),2);L(B,{get items(){return r.providersModels},valueMode:`id`,groupBy:c,get value(){return n(o)},set value(e){E(o,e,!0)}});var V=e(B,2);I(V,{key:`model`,get errors(){return r.errors}}),j(z);var U=e(z,2),W=h(U);g(2),j(U),j(T),j(y),j(m),f(`submit`,T,u),s(`change`,T,()=>{r.errors.clear()}),k(F,()=>a().systemPrompt,e=>a().systemPrompt=e),s(`click`,W,d),w(t,m),b()}a([`change`,`click`]);var W=l(`<button class="rounded w-full border border-dashed p-2 border-stone-500 cursor-pointer" tabindex="0"><i class="icon-plus"></i> Ajouter un agent</button>`),G=l(`<div class="rounded border p-2 my-2 border-stone-500 flex formgroup"><div class="flex-1 p-2"><span> </span></div> <button title="Modifier">Agent par défaut</button> <button class="bt small mx-1" title="Modifier"><i class="icon-edit"></i></button> <button class="bt small mx-1" title="Supprimer"><i class="icon-trash-empty"></i></button></div>`),K=l(`<div class="container"><!> <!></div>`);function q(i,a){S(a,!0);let l=C(x(p(()=>a.data.space))),g=C(x(p(()=>a.data.agents))),_=C(!1),v=C(null),y=C(x({})),D=new F,O=()=>{n(v)||(D.clear(),E(y,{},!0),E(_,!0))},k=()=>{E(_,!1)},M=e=>{e.name||D.set(`name`,`Le nom est obligatoire !`),(e.defaultProviderId===``||e.defaultModelId===``)&&D.set(`model`,`Le modèle est obligatoire !`),D.size===0&&R.createAgent(a.data.space.id,e).then(e=>{n(g).push(e),E(_,!1),E(y,{},!0)}).catch(e=>{console.log(e)})},P=()=>{E(v,null),E(y,{},!0)},I=e=>{e.name||D.set(`name`,`Le nom est obligatoire !`),D.size===0&&R.updateAgent(a.data.space.id,e).then(e=>{E(g,n(g).map(t=>e.id===t.id?e:t),!0),E(v,null),E(y,{},!0)}).catch(e=>{console.log(e)})},L=async e=>{D.clear(),!n(_)&&R.getAgent(a.data.space.id,e).then(t=>{E(g,n(g).filter(e=>e.id===t.id?t:e),!0),E(v,e,!0)}).catch(e=>console.log(e))},B=e=>{R.deleteAgent(a.data.space.id,e).then(()=>{E(g,n(g).filter(t=>t.id!==e),!0)}).catch(e=>{console.log(e)})},V=e=>{let t=n(l);t.defaultAgentId=e,z.updateSpace(t.id,t).then(e=>{N.spaces.map(t=>t.id===N.current?e:t),E(l,e,!0)}).catch(e=>{console.log(e)})},H=e=>{e.key===`Escape`&&P()};var q=K();f(`keydown`,m,H);var J=h(q),Y=e=>{var t=c(),r=d(t);u(r,()=>`new`,e=>{U(e,{get item(){return n(y)},get errors(){return D},onSave:M,onCancel:k,get providersModels(){return a.data.providersModels}})}),w(e,t)},X=e=>{var t=W();s(`click`,t,O),w(e,t)};T(J,e=>{n(_)?e(Y):e(X,-1)});var Z=e(J,2);r(Z,17,()=>n(g),e=>e.id,(r,i)=>{var f=c(),p=d(f),m=e=>{var t=c(),r=d(t);u(r,()=>n(i).id,e=>{U(e,{get item(){return n(i)},get errors(){return D},onSave:I,onCancel:P,get providersModels(){return a.data.providersModels}})}),w(e,t)},g=r=>{var a=G(),c=h(a),u=h(c),d=h(u,!0);j(u),j(c);var f=e(c,2);let p;var m=e(f,2),g=e(m,2);j(a),o(()=>{t(d,n(i).name),p=A(f,1,`bt small mx- Line truncated
+1 -1
View File
@@ -1 +1 @@
{"version":"1791236559767"} {"version":"1791316638543"}
+8 -8
View File
@@ -4,29 +4,29 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="text-scale" content="scale" /> <meta name="text-scale" content="scale" />
<link href="/_app/immutable/entry/start.CuX9LF19.js" rel="modulepreload"> <link href="/_app/immutable/entry/start.CVUmNBgW.js" rel="modulepreload">
<link href="/_app/immutable/chunks/Soo4K-rz.js" rel="modulepreload"> <link href="/_app/immutable/chunks/BZuNOv8h.js" rel="modulepreload">
<link href="/_app/immutable/chunks/DGrvnoUE.js" rel="modulepreload"> <link href="/_app/immutable/chunks/DGrvnoUE.js" rel="modulepreload">
<link href="/_app/immutable/entry/app.Iv4UP3yJ.js" rel="modulepreload"> <link href="/_app/immutable/entry/app.Bj-MC1YH.js" rel="modulepreload">
<link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload"> <link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload">
<link href="/_app/immutable/nodes/0.C86e0tcA.js" rel="modulepreload"> <link href="/_app/immutable/nodes/0.BLV5Ey1y.js" rel="modulepreload">
<link href="/_app/immutable/chunks/DTCALkcP.js" rel="modulepreload"> <link href="/_app/immutable/chunks/DTCALkcP.js" rel="modulepreload">
<link href="/_app/immutable/assets/0.BKrS386W.css" rel="stylesheet"> <link href="/_app/immutable/assets/0.C0TpjoIE.css" rel="stylesheet">
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">
<div style="display: contents"> <div style="display: contents">
<script> <script>
{ {
__sveltekit_1eyxneb = { __sveltekit_1uu3rg0 = {
base: "" base: ""
}; };
const element = document.currentScript.parentElement; const element = document.currentScript.parentElement;
Promise.all([ Promise.all([
import("/_app/immutable/entry/start.CuX9LF19.js"), import("/_app/immutable/entry/start.CVUmNBgW.js"),
import("/_app/immutable/entry/app.Iv4UP3yJ.js") import("/_app/immutable/entry/app.Bj-MC1YH.js")
]).then(([kit, app]) => { ]).then(([kit, app]) => {
kit.start(app, element); kit.start(app, element);
}); });
+4 -2
View File
@@ -47,6 +47,7 @@ func (s *Service) NewChat(
userID string, userID string,
teamID string, teamID string,
agentID string, agentID string,
taskID string,
) (*domain.Chat, error) { ) (*domain.Chat, error) {
team, err := s.repoUser.FindTeam(userID, teamID) team, err := s.repoUser.FindTeam(userID, teamID)
@@ -60,6 +61,7 @@ func (s *Service) NewChat(
UserID: userID, UserID: userID,
AgentID: agentID, AgentID: agentID,
TeamID: team.ID, TeamID: team.ID,
TaskID: taskID,
StartDatetime: &start, StartDatetime: &start,
Title: "Nouvelle conversation", Title: "Nouvelle conversation",
} }
@@ -170,8 +172,8 @@ func (s *Service) AddChatMessage(
return message, nil return message, nil
} }
func (s *Service) ListChats(userID string, teamID string, page int, query string) ([]*domain.Chat, error) { func (s *Service) ListChats(userID string, teamID string, page int, query string, taskID string) ([]*domain.Chat, error) {
return s.repoChat.ListChats(userID, teamID, page, query) return s.repoChat.ListChats(userID, teamID, page, query, taskID)
} }
func (s *Service) GetChat(userID string, teamID, chatID string) (*domain.Chat, error) { func (s *Service) GetChat(userID string, teamID, chatID string) (*domain.Chat, error) {
+49 -22
View File
@@ -3,6 +3,7 @@ package chat
import ( import (
"context" "context"
_ "embed" _ "embed"
"fmt"
"log/slog" "log/slog"
"sync" "sync"
@@ -87,43 +88,69 @@ func (s *ChatSession) run(ctx context.Context) error {
for _, tc := range msg.ToolCalls { for _, tc := range msg.ToolCalls {
toolImpl := s.toolService.GetToolImpl(tc.Function.Name) toolImpl := s.toolService.GetToolImpl(tc.Function.Name)
slog.Info("Execute tool", "name", tc.Function.Name, "impl", toolImpl) var toolRecord *domain.Tool
toolRecord, err := s.toolService.GetToolByName(s.userID, s.teamID, toolImpl.Name()) var executeErr error
if err != nil { if toolImpl == nil {
slog.Info("Execute tool", "error", err) executeErr = fmt.Errorf("unknown tool %s", tc.Function.Name)
toolResponse := &domain.Message{ slog.Info("Execute tool", "error", executeErr)
ChatID: s.chatID, } else {
TeamID: s.teamID, slog.Info("Execute tool", "name", tc.Function.Name, "impl", toolImpl)
ToolCallID: tc.ID, var err error
Role: string(domain.RoleTool), toolRecord, err = s.toolService.GetToolByName(s.userID, s.teamID, toolImpl.Name())
Content: "ERROR: " + err.Error(), if err != nil {
// l'outil n'est pas encore enregistré pour l'équipe :
// auto-enregistrement (comme le fait la liste des outils)
toolRecord, err = s.toolService.CreateTool(s.userID, &domain.Tool{
TeamID: s.teamID,
Name: toolImpl.Name(),
Enabled: true,
})
}
if err != nil {
executeErr = err
slog.Info("Execute tool", "error", err)
} }
s.repoChat.CreateChatMessage(s.userID, toolResponse)
} }
output, err := toolImpl.Execute(ctx, []byte(tc.Function.Arguments), toolRecord.Configuration)
var toolResponse *domain.Message var toolResponse *domain.Message
if err != nil { if executeErr != nil {
toolResponse = &domain.Message{ toolResponse = &domain.Message{
ChatID: s.chatID, ChatID: s.chatID,
TeamID: s.teamID, TeamID: s.teamID,
ToolCallID: tc.ID, ToolCallID: tc.ID,
Role: string(domain.RoleTool), Role: string(domain.RoleTool),
Content: "ERROR: " + err.Error(), Content: "ERROR: " + executeErr.Error(),
} }
} else { } else {
toolResponse = &domain.Message{ var output []byte
ChatID: s.chatID, output, executeErr = toolImpl.Execute(
TeamID: s.teamID, domain.WithToolContext(ctx, s.userID, s.teamID, s.modelID),
ToolCallID: tc.ID, []byte(tc.Function.Arguments),
Role: string(domain.RoleTool), toolRecord.Configuration,
Content: string(output), )
if executeErr != nil {
toolResponse = &domain.Message{
ChatID: s.chatID,
TeamID: s.teamID,
ToolCallID: tc.ID,
Role: string(domain.RoleTool),
Content: "ERROR: " + executeErr.Error(),
}
} else {
toolResponse = &domain.Message{
ChatID: s.chatID,
TeamID: s.teamID,
ToolCallID: tc.ID,
Role: string(domain.RoleTool),
Content: string(output),
}
} }
} }
toolResponse, err = s.repoChat.CreateChatMessage(s.userID, toolResponse) persisted, err := s.repoChat.CreateChatMessage(s.userID, toolResponse)
if err != nil { if err != nil {
return err return err
} }
s.messages = append(s.messages, toolResponse) s.messages = append(s.messages, persisted)
} }
} else { } else {
@@ -25,3 +25,7 @@ Never present a partial result as complete. If, despite your efforts, you cannot
Use the available tools and skills whenever they can help you answer more accurately, verify a fact, or complete the task. Don't answer from memory when a tool can provide the answer. If several tools are relevant, combine them. When a task matches an available skill, consult it before starting. Use the available tools and skills whenever they can help you answer more accurately, verify a fact, or complete the task. Don't answer from memory when a tool can provide the answer. If several tools are relevant, combine them. When a task matches an available skill, consult it before starting.
You may skip them for purely conversational exchanges or questions whose answer depends on no information that needs verifying. You may skip them for purely conversational exchanges or questions whose answer depends on no information that needs verifying.
## Scheduled tasks
When the user asks to perform something later or on a schedule ("do this every day at 8am", "tomorrow morning give me...", "every Monday summarize..."), actually schedule it with the scheduler tool instead of just promising. Translate the request into a cron spec (5 fields: minute hour day-of-month month day-of-week; e.g. "0 8 * * *" is 8am every day). Set repeat=false for one-shot requests. The prompt you schedule must be fully self-contained: it will run in a fresh conversation with no memory of the current one.
+318
View File
@@ -0,0 +1,318 @@
package task
import (
"context"
"fmt"
"log/slog"
"sync"
"time"
gocron "github.com/netresearch/go-cron"
"trankilou.fr/lassistanoque/backend/internal/domain"
)
// ChatRunner est la partie du service de chat nécessaire à l'exécution
// d'une tâche (interface pour découplage et tests).
type ChatRunner interface {
NewChat(userID string, teamID string, agentID string, taskID string) (*domain.Chat, error)
AddChatMessage(
ctx context.Context,
userID string,
teamID string,
chatID string,
agentID string,
prompt string,
params *domain.ChatParams,
) (*domain.Message, error)
}
// Service planifie l'exécution de tâches (prompt dans une nouvelle
// conversation) selon une spécification cron, avec ou sans répétition.
// Les tâches sont persistées : elles sont replanifiées au démarrage et
// leurs exécutions manquées pendant un arrêt sont rattrapées (go-cron
// MissedRunOnce pour les répétées, manuellement pour les ponctuelles).
type Service struct {
repo domain.TaskRepository
chat ChatRunner
cron *gocron.Cron
mu sync.Mutex
entries map[string]gocron.EntryID
}
func NewService(repo domain.TaskRepository) *Service {
return &Service{
repo: repo,
cron: gocron.New(),
entries: make(map[string]gocron.EntryID),
}
}
// SetChatService est appelé après la construction : le service de chat a
// besoin du service d'outils, dont l'outil scheduler qui a besoin d'ici.
func (s *Service) SetChatService(chatService ChatRunner) {
s.chat = chatService
}
// Start replanifie les tâches actives persistées et démarre l'ordonnanceur.
// Les exécutions manquées pendant l'arrêt sont rattrapées :
// - tâches répétées : par go-cron (WithPrev + MissedRunOnce), à partir de
// la dernière exécution persistée ;
// - tâches ponctuelles : go-cron ignore le rattrapage des entrées
// run-once, elles sont exécutées ici si leur échéance est passée.
func (s *Service) Start() {
tasks, err := s.repo.ListActiveTasks()
if err != nil {
slog.Error("task.Start.ListActiveTasks", "error", err)
}
now := time.Now()
catchups := 0
for _, t := range tasks {
if !t.Repeat && t.NextDatetime != nil && t.NextDatetime.Before(now) {
// l'échéance persistée est dans le passé : l'exécution a été
// manquée pendant l'arrêt (next_datetime n'est plus mis à jour
// après l'exécution d'une tâche ponctuelle)
slog.Info("task catch-up", "id", t.ID, "label", t.Label, "due", t.NextDatetime.Format(time.RFC3339))
go s.runTask(t.ID)
catchups++
// l'exécution passera la tâche "done" : rien à replanifier
continue
}
s.schedule(t)
}
s.cron.Start()
slog.Info("task scheduler started", "tasks", len(tasks), "catchups", catchups)
}
// Stop arrête l'ordonnanceur.
func (s *Service) Stop() {
s.cron.Stop()
}
// CreateTask valide la spécification cron, persiste la tâche et la planifie.
func (s *Service) CreateTask(userID string, teamID string, task *domain.Task) (*domain.Task, error) {
if task.Label == "" {
return nil, fmt.Errorf("'label' is required")
}
if task.Prompt == "" {
return nil, fmt.Errorf("'prompt' is required")
}
schedule, err := gocron.ParseStandard(task.Cron)
if err != nil {
return nil, fmt.Errorf("invalid cron spec %q: %w", task.Cron, err)
}
next := schedule.Next(time.Now())
if next.IsZero() {
return nil, fmt.Errorf("cron spec %q has no next execution", task.Cron)
}
task.TeamID = teamID
task.Status = domain.TaskStatusActive
nextTime := next
task.NextDatetime = &nextTime
created, err := s.repo.CreateTask(task)
if err != nil {
return nil, err
}
s.schedule(created)
return created, nil
}
// ListTasks retourne les tâches d'une équipe accessible à l'utilisateur.
func (s *Service) ListTasks(userID string, teamID string) ([]*domain.Task, error) {
return s.repo.ListTasks(userID, teamID)
}
// GetTask retourne une tâche d'une équipe accessible à l'utilisateur.
func (s *Service) GetTask(userID string, teamID string, id string) (*domain.Task, error) {
return s.repo.GetTaskByID(userID, teamID, id)
}
// UpdateTask met à jour les champs éditables (label, prompt, cron, repeat)
// et replanifie la tâche. Une tâche terminée est réactivée.
func (s *Service) UpdateTask(userID string, teamID string, task *domain.Task) (*domain.Task, error) {
existing, err := s.repo.GetTaskByID(userID, teamID, task.ID)
if err != nil {
return nil, err
}
if task.Label == "" {
return nil, fmt.Errorf("'label' is required")
}
if task.Prompt == "" {
return nil, fmt.Errorf("'prompt' is required")
}
schedule, err := gocron.ParseStandard(task.Cron)
if err != nil {
return nil, fmt.Errorf("invalid cron spec %q: %w", task.Cron, err)
}
if schedule.Next(time.Now()).IsZero() {
return nil, fmt.Errorf("cron spec %q has no next execution", task.Cron)
}
existing.Label = task.Label
existing.Prompt = task.Prompt
existing.Cron = task.Cron
existing.Repeat = task.Repeat
existing.Status = domain.TaskStatusActive
nextTime := schedule.Next(time.Now())
existing.NextDatetime = &nextTime
updated, err := s.repo.UpdateTask(existing)
if err != nil {
return nil, err
}
s.unschedule(updated.ID)
s.schedule(updated)
return updated, nil
}
// DeleteTask supprime une tâche et déplanifie son entrée.
func (s *Service) DeleteTask(userID string, teamID string, id string) error {
if err := s.repo.DeleteTask(userID, teamID, id); err != nil {
return err
}
s.unschedule(id)
return nil
}
// schedule ajoute une tâche à l'ordonnanceur et met à jour sa prochaine
// exécution en base. Les tâches sans répétition utilisent AddOnceFunc :
// une seule exécution, l'entrée disparaît ensuite.
func (s *Service) schedule(t *domain.Task) {
s.mu.Lock()
defer s.mu.Unlock()
if t.Status != domain.TaskStatusActive {
return
}
// idempotent : replanifier une tâche déjà planifiée remplace son entrée
if entryID, ok := s.entries[t.ID]; ok {
s.cron.Remove(entryID)
delete(s.entries, t.ID)
}
run := func() { s.runTask(t.ID) }
var entryID gocron.EntryID
var err error
if t.Repeat {
// rattrapage des exécutions manquées pendant un arrêt : go-cron
// compare la dernière exécution aux occurrences passées. Sans
// dernière exécution connue, il part de la création de la tâche.
// Aucune période de grâce : un rattrapage reste dû quel que soit
// l'âge de l'occurrence manquée.
prev := t.DateCreated
if t.LastDatetime != nil {
prev = *t.LastDatetime
}
entryID, err = s.cron.AddFunc(t.Cron, run,
gocron.WithPrev(prev),
gocron.WithMissedPolicy(gocron.MissedRunOnce),
)
} else {
// go-cron ignore le rattrapage des entrées run-once : une tâche
// ponctuelle dont l'échéance est passée est rattrapée dans Start()
entryID, err = s.cron.AddOnceFunc(t.Cron, run)
}
if err != nil {
slog.Error("task.schedule", "id", t.ID, "cron", t.Cron, "error", err)
return
}
s.entries[t.ID] = entryID
}
func (s *Service) unschedule(taskID string) {
s.mu.Lock()
defer s.mu.Unlock()
if entryID, ok := s.entries[taskID]; ok {
s.cron.Remove(entryID)
delete(s.entries, taskID)
}
}
// runTask exécute une tâche : nouvelle conversation portant le prompt de la
// tâche, avec le modèle enregistré. Après une exécution sans répétition,
// la tâche passe au statut "done".
func (s *Service) runTask(taskID string) {
if s.chat == nil {
slog.Error("task.runTask: chat service not set")
return
}
// relit la tâche fraîche depuis la base
tasks, err := s.repo.ListActiveTasks()
if err != nil {
slog.Error("task.runTask.ListActiveTasks", "error", err)
return
}
var task *domain.Task
for _, t := range tasks {
if t.ID == taskID {
task = t
break
}
}
if task == nil {
// tâche supprimée entre-temps
s.unschedule(taskID)
return
}
userID, err := s.repo.FirstUserOfTeam(task.TeamID)
if err != nil {
slog.Error("task.runTask.FirstUserOfTeam", "team", task.TeamID, "error", err)
return
}
// la conversation créée est liée à la tâche (navigation tâche <-> conversations)
chatModel, err := s.chat.NewChat(userID, task.TeamID, "", task.ID)
if err != nil {
slog.Error("task.runTask.NewChat", "error", err)
return
}
_, err = s.chat.AddChatMessage(
context.Background(),
userID,
task.TeamID,
chatModel.ID,
"",
task.Prompt,
&domain.ChatParams{ModelID: task.ModelID},
)
if err != nil {
slog.Error("task.runTask.AddChatMessage", "error", err)
return
}
slog.Info("task executed", "id", task.ID, "label", task.Label, "chat", chatModel.ID)
// persiste la dernière exécution : c'est ce marqueur qui permet à
// go-cron de détecter, au redémarrage, les occurrences manquées
now := time.Now()
task.LastDatetime = &now
if !task.Repeat {
task.Status = domain.TaskStatusDone
next := time.Time{}
task.NextDatetime = &next
if _, err := s.repo.UpdateTask(task); err != nil {
slog.Error("task.runTask.UpdateTask", "error", err)
}
s.unschedule(task.ID)
} else {
// persiste aussi la prochaine échéance (information d'affichage)
if schedule, err := gocron.ParseStandard(task.Cron); err == nil {
next := schedule.Next(now)
task.NextDatetime = &next
}
if _, err := s.repo.UpdateTask(task); err != nil {
slog.Error("task.runTask.UpdateTask", "error", err)
}
}
}
@@ -0,0 +1,410 @@
package task
import (
"context"
"database/sql"
"testing"
"time"
_ "github.com/mattn/go-sqlite3"
"trankilou.fr/lassistanoque/backend/internal/adapter/database/turso"
"trankilou.fr/lassistanoque/backend/internal/domain"
)
type fakeChatRunner struct {
prompts []string
}
func (f *fakeChatRunner) NewChat(userID, teamID, agentID, taskID string) (*domain.Chat, error) {
return &domain.Chat{ID: "chat-1", TeamID: teamID, UserID: userID, TaskID: taskID}, nil
}
func (f *fakeChatRunner) AddChatMessage(
ctx context.Context,
userID, teamID, chatID, agentID, prompt string,
params *domain.ChatParams,
) (*domain.Message, error) {
f.prompts = append(f.prompts, prompt)
return &domain.Message{}, nil
}
func newTestRepo(t *testing.T) domain.TaskRepository {
t.Helper()
// cache partagé : l'ordonnanceur tourne dans sa propre goroutine et
// doit voir la même base que le test (une :memory: classique est
// propre à chaque connexion du pool)
db, err := sql.Open("sqlite3", "file::memory:?cache=shared&_busy_timeout=5000")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { db.Close() })
schema := `
create table tasks (
id text not null primary key, team_id text not null, model_id text not null,
label text not null, prompt text not null, cron text not null,
repeat integer not null default 1, status text not null, next_datetime numeric,
last_datetime numeric,
_date_created numeric not null default current_timestamp, _date_updated numeric,
_version text not null);
create table user_teams (
id text not null primary key, user_id text not null, team_id text not null,
administrator bool default 0, _date_created numeric not null default current_timestamp,
_date_updated numeric, _version text not null);
insert into user_teams (id, user_id, team_id, _date_created, _version)
values ('ut1','user-1','team-1','2026-01-01 10:00:00','v');
`
if _, err := db.Exec(schema); err != nil {
t.Fatal(err)
}
return turso.NewTursoTaskRepository(db)
}
func TestCreateTaskValidation(t *testing.T) {
svc := NewService(newTestRepo(t))
if _, err := svc.CreateTask("user-1", "team-1", &domain.Task{Label: "l", Prompt: "p", Cron: "invalid"}); err == nil {
t.Errorf("invalid cron spec should fail")
}
if _, err := svc.CreateTask("user-1", "team-1", &domain.Task{Prompt: "p", Cron: "0 8 * * *"}); err == nil {
t.Errorf("missing label should fail")
}
if _, err := svc.CreateTask("user-1", "team-1", &domain.Task{Label: "l", Cron: "0 8 * * *"}); err == nil {
t.Errorf("missing prompt should fail")
}
}
func TestCreateTaskRecurring(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
created, err := svc.CreateTask("user-1", "team-1", &domain.Task{
ModelID: "m1",
Label: "Meteo du matin",
Prompt: "Donne-moi la meteo",
Cron: "0 8 * * *",
Repeat: true,
})
if err != nil {
t.Fatal(err)
}
if created.Status != domain.TaskStatusActive {
t.Errorf("status = %s", created.Status)
}
if created.NextDatetime == nil || created.NextDatetime.Before(time.Now()) {
t.Errorf("next datetime should be in the future, got %v", created.NextDatetime)
}
tasks, err := svc.ListTasks("user-1", "team-1")
if err != nil {
t.Fatal(err)
}
if len(tasks) != 1 || tasks[0].ID != created.ID {
t.Fatalf("expected 1 task %s, got %v", created.ID, tasks)
}
}
func TestOneShotExecution(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
fake := &fakeChatRunner{}
svc.SetChatService(fake)
_, err := svc.CreateTask("user-1", "team-1", &domain.Task{
Label: "Ponctuel",
Prompt: "Fais quelque chose",
Cron: "@every 1s",
Repeat: false,
})
if err != nil {
t.Fatal(err)
}
svc.Start()
defer svc.Stop()
// attend l'exécution
deadline := time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
if len(fake.prompts) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
if len(fake.prompts) == 0 || fake.prompts[0] != "Fais quelque chose" {
t.Fatalf("task did not execute, prompts=%v", fake.prompts)
}
// statut "done" après une exécution sans répétition
// (runTask persiste le statut juste après l'exécution : on l'attend)
var done *domain.Task
deadline = time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
tasks, _ := repo.ListTasks("user-1", "team-1")
done = nil
for _, tk := range tasks {
done = tk
}
if done != nil && done.Status == domain.TaskStatusDone {
break
}
time.Sleep(100 * time.Millisecond)
}
if done == nil || done.Status != domain.TaskStatusDone {
t.Fatalf("expected status done, got %+v", done)
}
// pas de deuxième exécution
time.Sleep(2 * time.Second)
if len(fake.prompts) != 1 {
t.Fatalf("one-shot task ran %d times", len(fake.prompts))
}
}
func TestUpdateTask(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
created, err := svc.CreateTask("user-1", "team-1", &domain.Task{
Label: "Ancien", Prompt: "ancien prompt", Cron: "0 8 * * *", Repeat: true,
})
if err != nil {
t.Fatal(err)
}
updated, err := svc.UpdateTask("user-1", "team-1", &domain.Task{
ID: created.ID, Label: "Nouveau", Prompt: "nouveau prompt", Cron: "0 6 * * *", Repeat: false,
})
if err != nil {
t.Fatal(err)
}
if updated.Label != "Nouveau" || updated.Prompt != "nouveau prompt" ||
updated.Cron != "0 6 * * *" || updated.Repeat {
t.Fatalf("update not applied: %+v", updated)
}
if updated.NextDatetime == nil || updated.NextDatetime.Hour() != 6 {
t.Fatalf("next datetime should be recalculated at 6am, got %v", updated.NextDatetime)
}
// cron invalide refusé
if _, err := svc.UpdateTask("user-1", "team-1", &domain.Task{
ID: created.ID, Label: "x", Prompt: "y", Cron: "pasunecron", Repeat: true,
}); err == nil {
t.Errorf("invalid cron spec should fail")
}
// une tâche done est réactivée par une mise à jour
done := updated
done.Status = domain.TaskStatusDone
if _, err := repo.UpdateTask(done); err != nil {
t.Fatal(err)
}
reactivated, err := svc.UpdateTask("user-1", "team-1", &domain.Task{
ID: created.ID, Label: "Reprise", Prompt: "p", Cron: "0 9 * * *", Repeat: true,
})
if err != nil {
t.Fatal(err)
}
if reactivated.Status != domain.TaskStatusActive {
t.Fatalf("done task should be reactivated, got %s", reactivated.Status)
}
}
func TestDeleteTask(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
created, err := svc.CreateTask("user-1", "team-1", &domain.Task{
Label: "l", Prompt: "p", Cron: "0 8 * * *", Repeat: true,
})
if err != nil {
t.Fatal(err)
}
if err := svc.DeleteTask("user-1", "team-1", created.ID); err != nil {
t.Fatal(err)
}
tasks, _ := svc.ListTasks("user-1", "team-1")
if len(tasks) != 0 {
t.Fatalf("expected 0 tasks after delete, got %d", len(tasks))
}
}
// createMissedRecurringTask insère une tâche récurrente dont la dernière
// exécution remonte à plus d'une heure, avec une occurrence toutes les 30
// minutes : des exécutions ont été manquées, comme pendant un arrêt.
func createMissedRecurringTask(t *testing.T, repo domain.TaskRepository, prompt string) *domain.Task {
t.Helper()
last := time.Now().Add(-65 * time.Minute)
task := &domain.Task{
TeamID: "team-1", ModelID: "m1",
Label: "Manquee", Prompt: prompt,
Cron: "@every 30m", Repeat: true,
Status: domain.TaskStatusActive,
LastDatetime: &last,
}
created, err := repo.CreateTask(task)
if err != nil {
t.Fatal(err)
}
return created
}
// createMissedOneShotTask insère une tâche ponctuelle active dont l'échéance
// est passée, comme après un arrêt du serveur.
func createMissedOneShotTask(t *testing.T, repo domain.TaskRepository, prompt string) *domain.Task {
t.Helper()
past := time.Now().Add(-2 * time.Hour)
task := &domain.Task{
TeamID: "team-1", ModelID: "m1",
Label: "Manquee", Prompt: prompt,
Cron: "@every 1h", Repeat: false,
Status: domain.TaskStatusActive,
NextDatetime: &past,
}
created, err := repo.CreateTask(task)
if err != nil {
t.Fatal(err)
}
return created
}
// waitPrompts attend que le fake chat runner ait enregistré n prompts.
func waitPrompts(t *testing.T, fake *fakeChatRunner, n int) bool {
t.Helper()
deadline := time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
if len(fake.prompts) >= n {
return true
}
time.Sleep(100 * time.Millisecond)
}
return false
}
func TestStartCatchUpMissedRecurringTask(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
fake := &fakeChatRunner{}
svc.SetChatService(fake)
// dernière exécution il y a 65 min, occurrence toutes les 30 min :
// go-cron (WithPrev + MissedRunOnce) doit rattraper au démarrage
createMissedRecurringTask(t, repo, "prompt rattrapage")
svc.Start()
defer svc.Stop()
if !waitPrompts(t, fake, 1) {
t.Fatalf("missed task did not execute at startup, prompts=%v", fake.prompts)
}
if fake.prompts[0] != "prompt rattrapage" {
t.Fatalf("unexpected prompt %q", fake.prompts[0])
}
// une seule exécution de rattrapage (pas une par occurrence manquée)
time.Sleep(1 * time.Second)
if len(fake.prompts) != 1 {
t.Fatalf("catch-up ran %d times, expected 1", len(fake.prompts))
}
}
func TestStartCatchUpMissedOneShotTask(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
fake := &fakeChatRunner{}
svc.SetChatService(fake)
created := createMissedOneShotTask(t, repo, "ponctuel manque")
svc.Start()
defer svc.Stop()
if !waitPrompts(t, fake, 1) {
t.Fatalf("missed one-shot task did not execute at startup, prompts=%v", fake.prompts)
}
// la tâche passe "done" et n'est pas replanifiée
deadline := time.Now().Add(5 * time.Second)
var done *domain.Task
for time.Now().Before(deadline) {
done, _ = svc.GetTask("user-1", "team-1", created.ID)
if done != nil && done.Status == domain.TaskStatusDone {
break
}
time.Sleep(100 * time.Millisecond)
}
if done == nil || done.Status != domain.TaskStatusDone {
t.Fatalf("expected status done after catch-up, got %+v", done)
}
time.Sleep(1 * time.Second)
if len(fake.prompts) != 1 {
t.Fatalf("one-shot catch-up ran %d times", len(fake.prompts))
}
}
func TestStartDoesNotCatchUpFutureTask(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
fake := &fakeChatRunner{}
svc.SetChatService(fake)
// dernière exécution récente, occurrence dans une heure :
// rien à rattraper, pas d'exécution immédiate
last := time.Now().Add(-10 * time.Minute)
_, err := repo.CreateTask(&domain.Task{
TeamID: "team-1", ModelID: "m1",
Label: "Future", Prompt: "trop tot",
Cron: "@every 1h", Repeat: true,
Status: domain.TaskStatusActive,
LastDatetime: &last,
})
if err != nil {
t.Fatal(err)
}
svc.Start()
defer svc.Stop()
time.Sleep(1 * time.Second)
if len(fake.prompts) != 0 {
t.Fatalf("task with no missed occurrence should not run, prompts=%v", fake.prompts)
}
}
func TestRunTaskPersistsLastAndNextDatetime(t *testing.T) {
repo := newTestRepo(t)
svc := NewService(repo)
fake := &fakeChatRunner{}
svc.SetChatService(fake)
_, err := svc.CreateTask("user-1", "team-1", &domain.Task{
Label: "Repetitive", Prompt: "encore", Cron: "@every 1s", Repeat: true,
})
if err != nil {
t.Fatal(err)
}
svc.Start()
defer svc.Stop()
if !waitPrompts(t, fake, 1) {
t.Fatalf("task did not execute, prompts=%v", fake.prompts)
}
// après une exécution, la dernière exécution et la prochaine échéance
// doivent être persistées (last_datetime nil à la création)
deadline := time.Now().Add(5 * time.Second)
ok := false
for time.Now().Before(deadline) {
tasks, _ := repo.ListTasks("user-1", "team-1")
if len(tasks) == 1 && tasks[0].LastDatetime != nil && tasks[0].NextDatetime != nil && tasks[0].NextDatetime.After(time.Now()) {
ok = true
break
}
time.Sleep(100 * time.Millisecond)
}
if !ok {
t.Fatal("last_datetime/next_datetime should be persisted after each execution")
}
}
+2 -2
View File
@@ -4,8 +4,8 @@ import type { Chat, Chunk, ChatRequest, ChatWithMessages } from "$lib/types/api"
export const chatApi = { export const chatApi = {
createChat: (space: string, data: Partial<ChatRequest>) => api.post<Chat>(`/chat/${space}`, data), createChat: (space: string, data: Partial<ChatRequest>) => api.post<Chat>(`/chat/${space}`, data),
createChatMessage: (space: string, id: string, data: Partial<ChatRequest>) => api.postStream<Chunk>(`/chat/${space}/${id}`, data), createChatMessage: (space: string, id: string, data: Partial<ChatRequest>) => api.postStream<Chunk>(`/chat/${space}/${id}`, data),
allChats: (space: string, pageNum: number, query?: string) => allChats: (space: string, pageNum: number, query?: string, taskId?: string) =>
api.get<Chat[]>(`/chat/${space}/all/${pageNum}${query ? `?q=${encodeURIComponent(query)}` : ''}`), api.get<Chat[]>(`/chat/${space}/all/${pageNum}${query || taskId ? `?${[query && `q=${encodeURIComponent(query)}`, taskId && `task=${taskId}`].filter(Boolean).join('&')}` : ''}`),
getChat: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}`), getChat: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}`),
subscribe: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}/subscribe`), subscribe: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}/subscribe`),
deleteChat: (space: string, id: string) => api.delete(`/chat/${space}/${id}`), deleteChat: (space: string, id: string) => api.delete(`/chat/${space}/${id}`),
@@ -0,0 +1,9 @@
import { api } from '../client';
import type { Task } from "$lib/types/api"
export const taskApi = {
listTasks: (space: string) => api.get<Task[]>(`/task/${space}`),
updateTask: (space: string, id: string, data: Partial<Task>) =>
api.put<Task>(`/task/${space}/${id}`, data),
deleteTask: (space: string, id: string) => api.delete(`/task/${space}/${id}`),
};
+15
View File
@@ -92,6 +92,21 @@ export type Chat = {
_version: string _version: string
} }
export interface Task {
id: string
teamId: string
modelId: string
label: string
prompt: string
cron: string
repeat: boolean
status: string
nextDatetime: string | null
_date_created: string
_date_updated: string
_version: string
}
export interface Message { export interface Message {
id: string id: string
role: string role: string
@@ -97,6 +97,16 @@
</script> </script>
<div class="h-full flex flex-col gap-2"> <div class="h-full flex flex-col gap-2">
{#if data.chatWithMessage.chat.taskId}
<div class="container">
<a
class="text-xs text-sky-700 dark:text-sky-300"
href={`/${data.spaceId}/tasks?task=${data.chatWithMessage.chat.taskId}`}
>
<i class="icon-tasks"></i> Tâche planifiée
</a>
</div>
{/if}
<div id="history" class="flex-1 container overflow-auto" bind:this={historyDiv}> <div id="history" class="flex-1 container overflow-auto" bind:this={historyDiv}>
{#each messages as message (message.id)} {#each messages as message (message.id)}
<div class={["message", "rounded", message.role]}> <div class={["message", "rounded", message.role]}>
@@ -4,12 +4,26 @@
import { putMessage } from "$lib/state/toaster.svelte"; import { putMessage } from "$lib/state/toaster.svelte";
import ConfirmDialog from "$lib/components/ConfirmDialog.svelte"; import ConfirmDialog from "$lib/components/ConfirmDialog.svelte";
import type { PageProps } from './$types'; import type { PageProps } from './$types';
import type { Chat } from "$lib/types/api"; import type { Chat, Task } from "$lib/types/api";
let { data }: PageProps = $props(); let { data }: PageProps = $props();
const PAGE_SIZE = 20; const PAGE_SIZE = 20;
const formatDate = (value: string | null | undefined) => {
if (!value) return "—";
const date = new Date(value);
if (Number.isNaN(date.getTime())) return "—";
return date.toLocaleString("fr-FR", {
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
let search = $state(""); let search = $state("");
let taskFilter = $state("");
// svelte-ignore state_referenced_locally -- la liste est gérée localement // svelte-ignore state_referenced_locally -- la liste est gérée localement
// (filtre, pagination, suppression) et ne doit pas suivre les rechargements de data // (filtre, pagination, suppression) et ne doit pas suivre les rechargements de data
let conversations = $state<Chat[]>(data.conversations); let conversations = $state<Chat[]>(data.conversations);
@@ -18,23 +32,32 @@
let conversationToDelete = $state<Chat | null>(null); let conversationToDelete = $state<Chat | null>(null);
const hasMore = $derived(conversations.length === (page + 1) * PAGE_SIZE); const hasMore = $derived(conversations.length === (page + 1) * PAGE_SIZE);
const tasks = $derived<Task[]>(data.tasks ?? []);
const refresh = async () => {
page = 0;
const taskId = taskFilter || undefined;
const result = await chatApi.allChats(data.space, 0, search, taskId);
conversations = result ?? [];
};
let searchTimer: ReturnType<typeof setTimeout> | undefined; let searchTimer: ReturnType<typeof setTimeout> | undefined;
const handleSearch = () => { const handleSearch = () => {
if (searchTimer !== undefined) clearTimeout(searchTimer); if (searchTimer !== undefined) clearTimeout(searchTimer);
searchTimer = setTimeout(async () => { searchTimer = setTimeout(refresh, 300);
page = 0; };
const result = await chatApi.allChats(data.space, 0, search);
conversations = result ?? []; const handleTaskFilter = () => {
}, 300); refresh();
}; };
const loadMore = async () => { const loadMore = async () => {
if (loading) return; if (loading) return;
loading = true; loading = true;
try { try {
const result = await chatApi.allChats(data.space, page + 1, search); const taskId = taskFilter || undefined;
const result = await chatApi.allChats(data.space, page + 1, search, taskId);
const next = result ?? []; const next = result ?? [];
conversations = [...conversations, ...next]; conversations = [...conversations, ...next];
page += 1; page += 1;
@@ -51,9 +74,7 @@
await chatApi.deleteChat(data.space, conversationToDelete.id); await chatApi.deleteChat(data.space, conversationToDelete.id);
putMessage("success", "Conversation supprimée"); putMessage("success", "Conversation supprimée");
await invalidateAll(); await invalidateAll();
const result = await chatApi.allChats(data.space, 0, search); await refresh();
conversations = result ?? [];
page = 0;
} catch { } catch {
putMessage("failure", "Erreur lors de la suppression de la conversation"); putMessage("failure", "Erreur lors de la suppression de la conversation");
} finally { } finally {
@@ -63,14 +84,26 @@
</script> </script>
<div class="container"> <div class="container">
<div class="formelement my-2"> <div class="my-2 flex gap-2">
<input <div class="formelement flex-1">
class="textinput" <input
type="search" class="textinput"
placeholder="Rechercher une conversation..." type="search"
bind:value={search} placeholder="Rechercher une conversation..."
oninput={handleSearch} bind:value={search}
/> oninput={handleSearch}
/>
</div>
{#if tasks.length > 0}
<div class="formelement w-60">
<select class="textinput" bind:value={taskFilter} onchange={handleTaskFilter}>
<option value="">Toutes les tâches</option>
{#each tasks as task (task.id)}
<option value={task.id}>{task.label}</option>
{/each}
</select>
</div>
{/if}
</div> </div>
{#each conversations as conversation (conversation.id)} {#each conversations as conversation (conversation.id)}
@@ -87,7 +120,18 @@
<i class="icon-trash-empty"></i> <i class="icon-trash-empty"></i>
</button> </button>
</div> </div>
<span class="text-xs">{conversation._date_created}</span> <div class="mt-1 text-xs text-stone-500">
<span title="Créée le">Créée le {formatDate(conversation._date_created)}</span>
<span class="mx-1">·</span>
<span title="Dernière interaction">Dernière interaction : {formatDate(conversation._date_updated)}</span>
{#if conversation.taskId}
<span class="mx-1">·</span>
<a
class="text-sky-700 dark:text-sky-300"
href={`/${data.space}/tasks?task=${conversation.taskId}`}
>Tâche planifiée</a>
{/if}
</div>
</div> </div>
{/each} {/each}
@@ -1,10 +1,12 @@
import { chatApi } from "$lib/api/endpoints/chat" import { chatApi } from "$lib/api/endpoints/chat"
import { taskApi } from "$lib/api/endpoints/task"
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => { export const load: PageLoad = async ({ params }) => {
return { return {
title: 'Historique', title: 'Historique',
conversations: await chatApi.allChats(params.space, 0), conversations: await chatApi.allChats(params.space, 0),
tasks: await taskApi.listTasks(params.space),
space: params.space, space: params.space,
}; };
} }
@@ -1,3 +1,214 @@
<div> <script lang="ts">
Tâches import { invalidateAll } from "$app/navigation";
import { page } from "$app/state";
import { taskApi } from "$lib/api/endpoints/task";
import { chatApi } from "$lib/api/endpoints/chat";
import { putMessage } from "$lib/state/toaster.svelte";
import ConfirmDialog from "$lib/components/ConfirmDialog.svelte";
import type { PageProps } from './$types';
import type { Chat, Task } from "$lib/types/api";
let { data }: PageProps = $props();
// svelte-ignore state_referenced_locally -- la liste est gérée localement
const tasks = $derived<Task[]>(data.tasks ?? []);
let editing = $state<Task | null>(null);
let taskToDelete = $state<Task | null>(null);
let saving = $state(false);
// conversations liées à une tâche (chargées à la demande) ;
// ?task=<id> dans l'URL ouvre directement la section
let expandedTask = $state<string | null>(page.url.searchParams.get("task"));
let taskConversations = $state<Record<string, Chat[]>>({});
let loadingConversations = $state(false);
const loadConversations = async (taskId: string) => {
loadingConversations = true;
try {
const result = await chatApi.allChats(data.space, 0, undefined, taskId);
taskConversations = { ...taskConversations, [taskId]: result ?? [] };
} catch {
putMessage("failure", "Erreur lors du chargement des conversations");
} finally {
loadingConversations = false;
}
};
const toggleConversations = async (task: Task) => {
if (expandedTask === task.id) {
expandedTask = null;
return;
}
expandedTask = task.id;
if (!taskConversations[task.id]) {
await loadConversations(task.id);
}
};
// ouverture initiale depuis ?task=<id>
let initialExpandDone = false;
$effect(() => {
if (!initialExpandDone && expandedTask) {
initialExpandDone = true;
loadConversations(expandedTask);
}
initialExpandDone = true;
});
const formatDate = (value: string | null) => {
if (!value) return "—";
const date = new Date(value);
if (Number.isNaN(date.getTime())) return "—";
return date.toLocaleString("fr-FR", {
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const startEdit = (task: Task) => {
editing = { ...task };
};
const handleSave = async (e: Event) => {
e.preventDefault();
if (!editing) return;
if (!editing.label.trim() || !editing.prompt.trim() || !editing.cron.trim()) {
putMessage("failure", "Titre, prompt et planification sont obligatoires");
return;
}
saving = true;
try {
await taskApi.updateTask(data.space, editing.id, {
label: editing.label,
prompt: editing.prompt,
cron: editing.cron,
repeat: editing.repeat,
});
putMessage("success", "Tâche mise à jour");
editing = null;
await invalidateAll();
} catch {
putMessage("failure", "Erreur lors de la mise à jour de la tâche");
} finally {
saving = false;
}
};
const handleDelete = async () => {
if (!taskToDelete) return;
try {
await taskApi.deleteTask(data.space, taskToDelete.id);
putMessage("success", "Tâche supprimée");
await invalidateAll();
} catch {
putMessage("failure", "Erreur lors de la suppression de la tâche");
} finally {
taskToDelete = null;
}
};
</script>
<div class="container">
{#if tasks.length === 0}
<p class="my-4 text-center text-sm text-stone-500">
Aucune tâche planifiée. Demandez-en une dans le chat
(« résume-moi l'actualité tous les jours à 8h »).
</p>
{/if}
{#each tasks as task (task.id)}
{#if editing && editing.id === task.id}
<div class="dark:bg-stone-800 rounded p-3 my-2">
<form onsubmit={handleSave}>
<div class="formgroup my-2">
<div class="formelement">
<label for={`label-${task.id}`}>Titre</label>
<input id={`label-${task.id}`} class="textinput" type="text" bind:value={editing.label} />
</div>
<div class="formelement">
<label for={`cron-${task.id}`}>Planification (cron)</label>
<input id={`cron-${task.id}`} class="textinput" type="text" bind:value={editing.cron} />
</div>
<div class="formelement">
<label for={`repeat-${task.id}`}>Répétition</label>
<input id={`repeat-${task.id}`} type="checkbox" bind:checked={editing.repeat} />
</div>
</div>
<div class="formelement">
<label for={`prompt-${task.id}`}>Prompt</label>
<textarea id={`prompt-${task.id}`} class="textinput w-full" rows="4" bind:value={editing.prompt}></textarea>
</div>
<div class="mt-2 flex gap-2">
<button class="bt small" type="submit" disabled={saving}>
{saving ? "Enregistrement..." : "Enregistrer"}
</button>
<button class="bt small" type="button" onclick={() => (editing = null)}>Annuler</button>
</div>
</form>
</div>
{:else}
<div class="dark:bg-stone-800 rounded p-2 my-2" class:ring-2={expandedTask === task.id}
class:ring-sky-500={expandedTask === task.id}>
<div class="flex flex-row items-center">
<div class="flex-1">
<div class="font-bold text-base">{task.label}</div>
<div class="text-xs text-stone-500">
{task.cron}
{task.repeat ? "· répétée" : "· ponctuelle"}
{task.status === "done" ? "· terminée" : ""}
</div>
</div>
<button
class="bt small"
title="Conversations liées"
onclick={() => toggleConversations(task)}
>
<i class="icon-chat"></i>
</button>
<button class="bt small" title="Modifier la tâche" onclick={() => startEdit(task)}>
<i class="icon-edit"></i>
</button>
<button class="bt small" title="Supprimer la tâche" onclick={() => (taskToDelete = task)}>
<i class="icon-trash-empty"></i>
</button>
</div>
<p class="mt-1 text-sm text-stone-600 dark:text-stone-400">{task.prompt}</p>
<span class="text-xs">Prochaine exécution : {formatDate(task.nextDatetime)}</span>
{#if expandedTask === task.id}
<div class="mt-2 border-t border-stone-600 pt-2">
<div class="text-xs font-medium uppercase text-stone-500">Conversations liées</div>
{#if loadingConversations && !taskConversations[task.id]}
<p class="text-sm text-stone-500">Chargement...</p>
{:else if (taskConversations[task.id] ?? []).length === 0}
<p class="text-sm text-stone-500">Aucune conversation pour cette tâche.</p>
{:else}
<ul class="mt-1">
{#each taskConversations[task.id] as conversation (conversation.id)}
<li class="my-1 text-sm">
<a class="text-sky-700 dark:text-sky-300" href={`/${data.space}/${conversation.id}`}>
{conversation.title}
</a>
<span class="ml-2 text-xs text-stone-500">{formatDate(conversation._date_created)}</span>
</li>
{/each}
</ul>
{/if}
</div>
{/if}
</div>
{/if}
{/each}
</div> </div>
<ConfirmDialog
open={taskToDelete !== null}
title="Supprimer la tâche"
message={`Voulez-vous vraiment supprimer « ${taskToDelete?.label} » ? Cette action est irréversible.`}
confirmLabel="Supprimer"
onConfirm={handleDelete}
onCancel={() => (taskToDelete = null)}
/>
@@ -1,3 +1,10 @@
export function load() { import { taskApi } from "$lib/api/endpoints/task"
return { title: 'Tâches' }; import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
return {
title: 'Tâches',
tasks: await taskApi.listTasks(params.space),
space: params.space,
};
} }
+1
View File
@@ -25,6 +25,7 @@ require (
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/netresearch/go-cron v0.16.1 // indirect
github.com/ollama/ollama v0.17.6 // indirect github.com/ollama/ollama v0.17.6 // indirect
github.com/openai/openai-go v1.12.0 // indirect github.com/openai/openai-go v1.12.0 // indirect
github.com/sixafter/aes-ctr-drbg v1.19.2 // indirect github.com/sixafter/aes-ctr-drbg v1.19.2 // indirect
+2
View File
@@ -43,6 +43,8 @@ github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4
github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
github.com/mozilla-ai/any-llm-go v0.9.0 h1:+pRG33idm22qcDTyaE97IqX9EGpWocfOUT6QIocnWjI= github.com/mozilla-ai/any-llm-go v0.9.0 h1:+pRG33idm22qcDTyaE97IqX9EGpWocfOUT6QIocnWjI=
github.com/mozilla-ai/any-llm-go v0.9.0/go.mod h1:L86RiIeF62s1SzHbMr+tKUj9lZ7AgOPJTxpjveCZMnM= github.com/mozilla-ai/any-llm-go v0.9.0/go.mod h1:L86RiIeF62s1SzHbMr+tKUj9lZ7AgOPJTxpjveCZMnM=
github.com/netresearch/go-cron v0.16.1 h1:X34Uohtmz99eYlDdZRpTyatJZRmhMD9GSVzYZ96z3PE=
github.com/netresearch/go-cron v0.16.1/go.mod h1:MGZe9ZJsjwqb+ahm//Xjzz4C8RkD1RwGTx9km7TTOOE=
github.com/ollama/ollama v0.17.6 h1:zxInCopQToAMm+OniZSiHFcry03kiL6i1mmcTvpK4Us= github.com/ollama/ollama v0.17.6 h1:zxInCopQToAMm+OniZSiHFcry03kiL6i1mmcTvpK4Us=
github.com/ollama/ollama v0.17.6/go.mod h1:tCX4IMV8DHjl3zY0THxuEkpWDZSOchJpzTuLACpMwFw= github.com/ollama/ollama v0.17.6/go.mod h1:tCX4IMV8DHjl3zY0THxuEkpWDZSOchJpzTuLACpMwFw=
github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0= github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0=