diff --git a/README.md b/README.md index cd63ba7..29fd6fb 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,7 @@ redémarrages (volume `/data`). Variables d'environnement du conteneur : | `LOKI_PRESETS` | `rust` : les presets (liste, éditeur et aperçus, suppression, placement auto, presets externes, bascule) sont tenus par la façade Rust ; l'application au moteur reste au Go (expérimental, migration en cours) | Go | | `LOKI_UPDATE` | `rust` : la mise à jour de Loki (`/api/update`, `/api/update/apply`) est servie par la façade Rust ; en conteneur, l'image se met à jour par Docker (expérimental, migration en cours) | Go | | `LOKI_MCP` | `rust` : les serveurs MCP — configuration, catalogue, état, pool de sessions stdio et HTTP — sont tenus par la façade Rust ; le Go lui demande les outils MCP de l'agent et leurs appels (expérimental, migration en cours) | Go | +| `LOKI_BACKENDS` | `rust` : les backends llama.cpp — statut, vérification git, binaires précompilés, bascule fast/opt, backends custom, GPU vus par un moteur — et le job des moteurs sont tenus par la façade Rust ; les jobs du Go (compilation, moteur de l'image, Strata) lui rapportent leurs étapes (expérimental, migration en cours) | Go | | `LOKI_PROJECTS` | `rust` : le hub des projets (liste et comptes, création, renommage, description, suppression, bascule) est tenu par la façade Rust ; les discussions restent à qui tient la conversation (expérimental, migration en cours) | Go | | `LOKI_SYSTEM` | `rust` : les interrupteurs système — accès internet et Crawl4AI, pilotage du navigateur, clé de complétion, écoute réseau du moteur — sont tenus par la façade Rust ; le navigateur piloté reste au Go (expérimental, migration en cours) | Go | | `LOKI_ENGINE` | `rust` : le pilotage du moteur (démarrage, arrêt, redémarrage, déchargement et rechargement de la VRAM) est tenu par la façade Rust, en conteneur avec son superviseur ; le verrou de l'optimiseur reste au Go (expérimental, migration en cours) | Go | diff --git a/docs/superpowers/specs/2026-10-15-rust-migration-lot22-backends-design.md b/docs/superpowers/specs/2026-10-15-rust-migration-lot22-backends-design.md new file mode 100644 index 0000000..52fc856 --- /dev/null +++ b/docs/superpowers/specs/2026-10-15-rust-migration-lot22-backends-design.md @@ -0,0 +1,111 @@ +# Lot 22 — backends llama.cpp et job des moteurs tenus par la façade + +## Contexte + +Le panneau Moteur s'appuie sur une famille de routes du Go : +- `web_llamacpp.go` : statut, vérification git, bascule fast/opt, job ; +- `backend_prebuilt.go` : binaires précompilés officiels ; +- `web_api.go` : backends custom et leur désinstallation ; +- `web_devices.go` : GPU vus par un moteur. + +Elles partagent **un** job (`lcJob`) avec la mise à jour du moteur de l'image +(`web_engine.go`) et l'installation de Strata (`backend_strata.go`). L'entête +du job est en base (`state/build_job`), ses lignes dans +`$LOKI_HOME/loki-build.log`. Au démarrage, un job noté « en cours » est déclaré +interrompu (`lcRestore`). + +## Le lot + +Avec `LOKI_BACKENDS=rust` (expérimental), la façade (`rust/loki-rs/src/backends`) +sert les routes suivantes : + +| Route | Rôle | +| --- | --- | +| `/api/llamacpp` | statut : dépôt git, binaire, moteur de l'image, précompilé, moteur téléchargé, plan de build, conseil, job | +| `/api/llamacpp/check` | `git fetch`, puis le retard sur origin | +| `/api/llamacpp/prebuilt/check` | dernière release officielle comparée à la version installée | +| `/api/llamacpp/prebuilt` | job : téléchargement, extraction (liens compris), VERSION, ménage, BIN, service arrêté puis relancé | +| `/api/llamacpp/use` | bascule fast/opt, refusée pendant une optimisation | +| `/api/llamacpp/job` | progression et lignes à partir d'un décalage | +| `/api/llamacpp/uninstall-custom` | désinstallation d'un backend custom | +| `/api/backends`, `/api/backends/custom` | les backends présents | +| `/api/backends/devices` | GPU vus par un moteur, avec un cache mémoire et un cache disque | + +**Le job vit dans la façade** (`backends/job.rs`) : même entête en base, même +journal, même reprise au démarrage. Les jobs que le Go fait encore tourner lui +rapportent chaque étape par l'API interne `/internal/facade/v1/build-job/*` +(`start`, `line`, `phase`, `fail`, `done`, `commits`, `end`, `snapshot`). +Ces jobs sont : +- la compilation depuis les sources (`install`, `update`, `install-custom`, + relayées au Go qui garde son refus 409 quand l'image fournit le moteur) ; +- la mise à jour du moteur de l'image ; +- Strata. + +Côté Go (`facade_backends.go`), quand la façade tient le lot : +- `startLcJob`, `lcAppend`, `lcPhase`, `lcFail`, `lcDone`, `lcSetCommit` et + `lcJobSnapshot` passent par la façade ; +- le garde de l'optimiseur reste au Go, avant le démarrage ; +- le Go ne restaure plus de job au démarrage ; +- les routes reçues par le tunnel sont relayées à la façade. + +Pour arrêter et relancer le service, la façade pilote le moteur si elle le +tient (lot 16), sinon elle le demande au Go (`/internal/v1/service/action`, +avec `if_active`). Les sondes de la machine passent par un PATH et une racine +injectables (`backends/probe.rs`) : +- `nvidia-smi`, `nvcc`, `hipcc`, `/opt/rocm` ; +- `glslc`, `vulkaninfo`, `ldconfig` et les chemins de `libvulkan`. + +## Correction du Go + +`prebuiltVersionFormat` lisait le format comme 3ᵉ champ du marqueur VERSION. +Hors CUDA Windows, la version CUDA est vide : le marqueur +« `b300 fmt2` » n'a alors que deux champs. Le format n'était donc jamais +reconnu, et chaque vérification retéléchargeait la release sous Linux et +macOS au lieu de dire « déjà à jour ». Le format est désormais le dernier +champ, et la version CUDA ignore ce champ. Le port Rust suit. + +## Parité + +`internal/loki/parity_backends_test.go` (Linux) tire du Go un journal rejoué +par `tests/backends.rs`. Le journal est sauté si `/usr/local/cuda*` ou +`/opt/rocm` existent sur la machine. + +Le journal contient : +- **le statut** dans tous ses états : + - dépôt git reproductible (dates et identité fixées), retard connu ou vérifié, tête détachée ; + - origine perdue, BIN dans un fork ; + - précompilé versionné, moteur téléchargé, moteur de l'image ; +- **les backends custom** et chaque refus de désinstallation ; +- **la bascule fast/opt** ; +- **la dernière release** : + - refus HTTP, tag vide, JSON illisible ; + - aucun asset adapté ; +- **le job précompilé** : + - installation, « déjà à jour », ancien format réextrait ; + - optimisation en cours, GitHub qui refuse ; + - archive absente, archive piégée (`../`), archive sans serveur ; +- **les GPU** : + - liaison PCIe, mémoire complétée par nvidia-smi ; + - cache, mémoire nulle non figée, repli sur le disque ; + - moteur planté, tué ou non exécutable, pilote ancien, cartes de même nom ; +- **après chaque appel** : BIN, entête en base, journal, `devices.json` et l'arborescence de `backends/` et `engine/` ; +- **machine par machine** (dix fausses machines) : le plan de build, le conseil et la variante de release ; +- **le job pas à pas** : + - phases déduites des lignes de build, troncature à 4000 lignes, vues à partir d'un décalage ; + - écritures en base limitées à une toutes les 2 s ; + - refus d'un second job ; + - reprise au démarrage dans tous les cas : absent, illisible, fini, interrompu, journal vide ou trop long. + +Autres tests : +- le Go (`TestFacadeBackends`) vérifie que ses jobs rapportent chaque étape à + la façade, dans l'ordre, et que la compilation n'est pas relayée ; +- la façade (`api_interne_du_job`, `service_arrete_puis_relance`) vérifie + l'API interne et le service arrêté puis relancé autour de l'installation. + +## Écarts assumés + +- Les erreurs réseau (GitHub injoignable) gardent le texte de `reqwest`. +- Quand un asset de la release a un champ de mauvais type, le message n'est + pas celui du Go. +- `git fetch` lancé par `/api/llamacpp/check` pendant un job du Go n'écrit + plus ses lignes dans ce job. diff --git a/internal/loki/backend_prebuilt.go b/internal/loki/backend_prebuilt.go index 6488521..9cb0b28 100644 --- a/internal/loki/backend_prebuilt.go +++ b/internal/loki/backend_prebuilt.go @@ -29,7 +29,8 @@ import ( "time" ) -const llamaReleasesAPI = "https://api.github.com/repos/ggml-org/llama.cpp/releases/latest" +// llamaReleasesAPI : variable pour que les tests la pointent sur un faux GitHub. +var llamaReleasesAPI = "https://api.github.com/repos/ggml-org/llama.cpp/releases/latest" type ghAsset struct { Name string `json:"name"` @@ -41,18 +42,25 @@ func prebuiltDir() string { return filepath.Join(backendsDir(), "llama.cpp-prebuilt") } +// prebuiltVersionFields : les champs du marqueur VERSION, « tag cudaVer +// format ». La version CUDA est vide hors CUDA Windows : « b300 fmt2 » n'a +// alors que DEUX champs, et le format est le second. +func prebuiltVersionFields() []string { + b, err := os.ReadFile(filepath.Join(prebuiltDir(), "VERSION")) + if err != nil { + return nil + } + return strings.Fields(strings.TrimSpace(string(b))) +} + // prebuiltVersion lit le marqueur VERSION du dossier prebuilt : "tag cudaVer" // (cudaVer vide hors CUDA Windows). func prebuiltVersion() (tag, cudaVer string) { - b, err := os.ReadFile(filepath.Join(prebuiltDir(), "VERSION")) - if err != nil { - return "", "" - } - f := strings.Fields(strings.TrimSpace(string(b))) + f := prebuiltVersionFields() if len(f) > 0 { tag = f[0] } - if len(f) > 1 { + if len(f) > 1 && !strings.HasPrefix(f[1], "fmt") { cudaVer = f[1] } return @@ -64,15 +72,13 @@ func prebuiltVersion() (tag, cudaVer string) { // sera refaite au lieu d'être déclarée « déjà à jour ». const prebuiltFormat = "fmt2" -// prebuiltVersionFormat lit le 3e champ du marqueur VERSION ("" si absent). +// prebuiltVersionFormat lit le format, dernier champ du marqueur VERSION ("" +// si absent). Lu jadis comme 3e champ, il manquait dès que la version CUDA +// était vide (Linux, macOS) : chaque vérification réinstallait la release. func prebuiltVersionFormat() string { - b, err := os.ReadFile(filepath.Join(prebuiltDir(), "VERSION")) - if err != nil { - return "" - } - f := strings.Fields(strings.TrimSpace(string(b))) - if len(f) > 2 { - return f[2] + f := prebuiltVersionFields() + if len(f) > 1 && strings.HasPrefix(f[len(f)-1], "fmt") { + return f[len(f)-1] } return "" } diff --git a/internal/loki/facade_backends.go b/internal/loki/facade_backends.go new file mode 100644 index 0000000..0e833cc --- /dev/null +++ b/internal/loki/facade_backends.go @@ -0,0 +1,154 @@ +package loki + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "os" + "strconv" + "strings" + "time" +) + +// facade_backends.go — backends llama.cpp tenus par la façade Rust +// (LOKI_BACKENDS=rust, lot 22 de la migration ; expérimental, le Go reste le +// défaut) : statut, vérification git, binaires précompilés, bascule fast/opt, +// suivi du job, backends custom et GPU vus par un moteur +// (rust/loki-rs/src/backends). +// +// La façade détient alors LE job des moteurs. Ceux que le Go fait encore +// tourner — compilation depuis les sources (install, update, install-custom, +// que la façade lui relaie), moteur de l'image, Strata — lui rapportent chaque +// étape (/internal/facade/v1/build-job/*) : lcAppend, lcPhase, lcFail, lcDone, +// startLcJob et lcJobSnapshot passent par elle, et le Go ne restaure plus de +// job au démarrage (la façade s'en charge). + +const facadeBackendsEnv = "LOKI_BACKENDS" + +// facadeBackends : la façade tient-elle les backends et le job ? +func facadeBackends() bool { + return strings.EqualFold(strings.TrimSpace(os.Getenv(facadeBackendsEnv)), "rust") && + facadeAddr() != "" && internalToken() != "" +} + +// facadeBackendsRoutes : les routes que la façade sert alors (backends/mod.rs). +var facadeBackendsRoutes = map[string]bool{ + "/api/llamacpp": true, + "/api/llamacpp/check": true, + "/api/llamacpp/prebuilt": true, + "/api/llamacpp/prebuilt/check": true, + "/api/llamacpp/use": true, + "/api/llamacpp/job": true, + "/api/llamacpp/uninstall-custom": true, + "/api/backends": true, + "/api/backends/custom": true, + "/api/backends/devices": true, +} + +// facadeJobClient : appels courts (une ligne de journal, une phase). +var facadeJobClient = &http.Client{Timeout: 30 * time.Second} + +// facadeJobCall envoie une étape du job à la façade. out peut être nil. +// Une réponse 409 rend l'erreur que la façade explique (job déjà en cours). +func facadeJobCall(op string, body map[string]any, out any) error { + b, err := json.Marshal(body) + if err != nil { + return err + } + req, err := http.NewRequest(http.MethodPost, "http://"+facadeAddr()+"/internal/facade/v1/build-job/"+op, bytes.NewReader(b)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set(internalTokenHeader, internalToken()) + resp, err := facadeJobClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusConflict { + var e struct { + Error string `json:"error"` + } + _ = json.NewDecoder(resp.Body).Decode(&e) + if e.Error == "" { + e.Error = resp.Status + } + return errors.New(e.Error) + } + if resp.StatusCode >= 300 { + return fmt.Errorf("façade : %s", resp.Status) + } + if out != nil { + return json.NewDecoder(resp.Body).Decode(out) + } + return nil +} + +// facadeJobNote : une étape dont l'échec ne doit pas arrêter le job (le +// journal perd une ligne, rien de plus) — tracée sur la sortie d'erreur. +func facadeJobNote(op string, body map[string]any) { + if err := facadeJobCall(op, body, nil); err != nil { + fmt.Fprintf(os.Stderr, "[job] étape %s non transmise à la façade : %v\n", op, err) + } +} + +// facadeJobStart démarre le job côté façade, puis son corps ici. +func facadeJobStart(action string, run func()) error { + if err := facadeJobCall("start", map[string]any{"action": action}, nil); err != nil { + return err + } + setBuildSink(lcAppend) + go func() { + defer func() { + setBuildSink(nil) + facadeJobNote("end", map[string]any{}) + }() + run() + }() + return nil +} + +// facadeJobSnapshot : la vue du job tenue par la façade. +func facadeJobSnapshot(from int, withLines bool) map[string]any { + lines := "0" + if withLines { + lines = "1" + } + req, err := http.NewRequest(http.MethodGet, "http://"+facadeAddr()+ + "/internal/facade/v1/build-job/snapshot?from="+strconv.Itoa(from)+"&lines="+lines, nil) + if err != nil { + return map[string]any{"exists": false} + } + req.Header.Set(internalTokenHeader, internalToken()) + resp, err := facadeJobClient.Do(req) + if err != nil { + return map[string]any{"exists": false} + } + defer resp.Body.Close() + var out map[string]any + if resp.StatusCode != http.StatusOK || json.NewDecoder(resp.Body).Decode(&out) != nil { + return map[string]any{"exists": false} + } + return out +} + +// lcSetCommit note le commit d'avant ("old") ou d'après ("new") une mise à +// jour. +func lcSetCommit(which, commit string) { + if facadeBackends() { + facadeJobNote("commits", map[string]any{which: commit}) + return + } + lcMu.Lock() + if lcCur != nil { + if which == "old" { + lcCur.OldCommit = commit + } else { + lcCur.NewCommit = commit + } + } + lcMu.Unlock() +} diff --git a/internal/loki/facade_chat.go b/internal/loki/facade_chat.go index 75bb605..96b665b 100644 --- a/internal/loki/facade_chat.go +++ b/internal/loki/facade_chat.go @@ -151,7 +151,7 @@ var facadeChatRoutes = map[string]bool{ // mémoire (facade_mem.go), les presets (facade_presets.go), le pilotage du // moteur (facade_engine.go), les interrupteurs système (facade_system.go), les // projets (facade_projects.go), les serveurs MCP (facade_mcp.go), la mise à -// jour (facade_update.go). +// jour (facade_update.go), les backends llama.cpp (facade_backends.go). // Posé APRÈS requireWebAuth : seule une requête authentifiée ici part, avec le // jeton interne qui en tient lieu là-bas. func withFacadeChat(path string, h http.HandlerFunc) http.HandlerFunc { @@ -182,6 +182,8 @@ func withFacadeChat(path string, h http.HandlerFunc) http.HandlerFunc { held, unavailable = facadeMCP, "serveurs MCP indisponibles : " case facadeUpdateRoutes[path]: held, unavailable = facadeUpdate, "mise à jour indisponible : " + case facadeBackendsRoutes[path]: + held, unavailable = facadeBackends, "moteurs indisponibles : " default: return h } diff --git a/internal/loki/facade_chat_test.go b/internal/loki/facade_chat_test.go index 7d8b627..1c1fdf2 100644 --- a/internal/loki/facade_chat_test.go +++ b/internal/loki/facade_chat_test.go @@ -2,6 +2,7 @@ package loki import ( "encoding/json" + "errors" "io" "net/http" "net/http/httptest" @@ -927,3 +928,139 @@ func TestFacadeMiseAJour(t *testing.T) { } } } + +// Lot 22 : les routes des backends partent à la façade, et les jobs du Go +// (compilation, moteur de l'image, Strata) lui rapportent chaque étape — le +// job vit chez elle. +func TestFacadeBackends(t *testing.T) { + testHome(t) + resetBackendsState() + t.Cleanup(resetBackendsState) + var mu sync.Mutex + var calls []string + busy := false + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get(internalTokenHeader) != jetonTest { + w.WriteHeader(403) + return + } + b, _ := io.ReadAll(r.Body) + mu.Lock() + calls = append(calls, r.Method+" "+r.URL.RequestURI()+" "+string(b)) + refuse := busy + mu.Unlock() + switch r.URL.Path { + case "/internal/facade/v1/build-job/start": + if refuse { + w.WriteHeader(409) + io.WriteString(w, `{"ok":false,"error":"un job engine est déjà en cours"}`) + return + } + io.WriteString(w, `{"ok":true}`) + case "/internal/facade/v1/build-job/snapshot": + io.WriteString(w, `{"exists":true,"action":"engine","running":true}`) + default: + io.WriteString(w, `{"ok":true,"de":"facade"}`) + } + })) + defer srv.Close() + t.Setenv(internalTokenEnv, jetonTest) + t.Setenv(facadeAddrEnv, strings.TrimPrefix(srv.URL, "http://")) + local := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "go") } + + t.Setenv(facadeBackendsEnv, "") + w := httptest.NewRecorder() + withFacadeChat("/api/llamacpp", local)(w, httptest.NewRequest("GET", "/api/llamacpp", nil)) + if w.Body.String() != "go" || len(calls) != 0 { + t.Fatalf("sans LOKI_BACKENDS : %q", w.Body.String()) + } + t.Setenv(facadeBackendsEnv, "rust") + for p := range facadeBackendsRoutes { + w := httptest.NewRecorder() + withFacadeChat(p, local)(w, httptest.NewRequest("POST", p, strings.NewReader("{}"))) + if !strings.Contains(w.Body.String(), "facade") { + t.Fatalf("%s non relayé : %q", p, w.Body.String()) + } + } + // La compilation reste au Go. + for _, p := range []string{"/api/llamacpp/install", "/api/llamacpp/update", "/api/llamacpp/install-custom"} { + if facadeBackendsRoutes[p] { + t.Fatalf("%s ne doit pas partir à la façade", p) + } + } + mu.Lock() + calls = nil + mu.Unlock() + + // Un job du Go : chaque étape part à la façade, dans l'ordre. + done := make(chan struct{}) + if err := startLcJob("engine", func() { + lcPhase("recherche…") + emitBuildLine("[ 10%] Building CXX object a/b.cpp.o") + lcSetCommit("old", "") + lcSetCommit("new", "bbb") + lcFail(errors.New("raté")) + lcDone("fini") + close(done) + }); err != nil { + t.Fatal(err) + } + <-done + want := []string{ + `POST /internal/facade/v1/build-job/start {"action":"engine"}`, + `POST /internal/facade/v1/build-job/phase {"phase":"recherche…"}`, + `POST /internal/facade/v1/build-job/line {"line":"[ 10%] Building CXX object a/b.cpp.o"}`, + `POST /internal/facade/v1/build-job/commits {"old":""}`, + `POST /internal/facade/v1/build-job/commits {"new":"bbb"}`, + `POST /internal/facade/v1/build-job/fail {"error":"raté"}`, + `POST /internal/facade/v1/build-job/done {"msg":"fini"}`, + `POST /internal/facade/v1/build-job/end {}`, + } + for i := 0; i < 100; i++ { + mu.Lock() + n := len(calls) + mu.Unlock() + if n >= len(want) { + break + } + time.Sleep(10 * time.Millisecond) + } + mu.Lock() + got := append([]string(nil), calls...) + calls = nil + busy = true + mu.Unlock() + if strings.Join(got, "\n") != strings.Join(want, "\n") { + t.Fatalf("étapes transmises :\n%s", strings.Join(got, "\n")) + } + // Rien ne reste dans le job du Go, et le sink est retiré. + if lcCur != nil { + t.Fatalf("job tenu par le Go : %+v", lcCur) + } + // Un second job : la façade le refuse, le Go le dit. + if err := startLcJob("strata", func() { t.Error("ne doit pas tourner") }); err == nil || err.Error() != "un job engine est déjà en cours" { + t.Fatalf("refus : %v", err) + } + // La vue du job (statut du moteur de l'image) vient de la façade. + if v := lcJobSnapshot(0, false); v["action"] != "engine" || v["running"] != true { + t.Fatalf("vue : %v", v) + } + mu.Lock() + last := calls[len(calls)-1] + mu.Unlock() + if last != "GET /internal/facade/v1/build-job/snapshot?from=0&lines=0 " { + t.Fatalf("vue demandée : %q", last) + } + if v := lcJobSnapshot(3, true); v["exists"] != true { + t.Fatalf("vue avec lignes : %v", v) + } + // Façade injoignable : le job ne démarre pas, la vue dit « aucun job ». + t.Setenv(facadeAddrEnv, "127.0.0.1:1") + if err := startLcJob("engine", func() { t.Error("ne doit pas tourner") }); err == nil { + t.Fatal("job démarré sans façade") + } + if v := lcJobSnapshot(0, true); v["exists"] != false { + t.Fatalf("vue sans façade : %v", v) + } + lcAppend("perdue") // tracée, sans panique +} diff --git a/internal/loki/parity_backends_test.go b/internal/loki/parity_backends_test.go new file mode 100644 index 0000000..f77db05 --- /dev/null +++ b/internal/loki/parity_backends_test.go @@ -0,0 +1,922 @@ +//go:build linux + +package loki + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "encoding/json" + "errors" + "io/fs" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "sort" + "strings" + "sync" + "testing" + "time" +) + +// parity_backends_test.go — journal de référence des backends llama.cpp +// (lot 22 de la migration Rust) : statut (dépôt git, binaire, moteur de +// l'image, précompilé, moteur téléchargé, plan de build et conseil selon la +// machine), vérification git, backends custom et leur désinstallation, +// bascule fast/opt, vérification de la dernière release, job des binaires +// précompilés (téléchargement, extraction avec liens, ménage, marqueur +// VERSION, échecs), GPU vus par un moteur (caches mémoire et disque), puis le +// job lui-même pas à pas et sa reprise au démarrage. Les machines sont de faux +// outils dans le PATH (nvidia-smi, nvcc, hipcc, glslc, vulkaninfo, ldconfig) ; +// GitHub est un faux serveur. Rangé dans +// rust/loki-rs/tests/parity_backends/backends.json ; tests/backends.rs le +// rejoue par la façade. +// +// LOKI_PARITY_UPDATE=1 go test ./internal/loki -run TestPariteBackends + +const parityBackendsFile = "../../rust/loki-rs/tests/parity_backends/backends.json" + +// Une entrée d'archive servie par le faux GitHub. +type parityArchEntry struct { + Name string `json:"name"` + Type string `json:"type"` // file | dir | symlink | hardlink + Body string `json:"body,omitempty"` + Link string `json:"link,omitempty"` + Mode int64 `json:"mode,omitempty"` +} + +// Ce que sert le faux GitHub : la release (« {{GH}} » = son adresse) et les +// archives par nom. +type parityRelease struct { + Status int `json:"status"` + JSON string `json:"json"` + Assets map[string][]parityArchEntry `json:"assets,omitempty"` +} + +type parityBackendsStep struct { + Name string `json:"name"` + Machine string `json:"machine,omitempty"` // outils du PATH (machines) + Git []string `json:"git,omitempty"` // avant les fichiers : init | commit | clone | pull | detach | remote-bad + Files map[string]string `json:"files,omitempty"` // sous LOKI_HOME : contenu ; « #! » exécutable ; « -> x » lien ; « - » supprimé ; « / » dossier + Config map[string]string `json:"config,omitempty"` // "" = supprimé + Engine *string `json:"engine_env,omitempty"` + Release *parityRelease `json:"release,omitempty"` + Tune bool `json:"tune,omitempty"` + Method string `json:"method"` + Path string `json:"path"` + Body string `json:"body,omitempty"` + Wait bool `json:"wait,omitempty"` // job lancé : attendre sa fin, relire /api/llamacpp/job + Status int `json:"status"` + Out any `json:"out"` + Job any `json:"job,omitempty"` + After map[string]string `json:"after"` + Tree []string `json:"tree"` +} + +// Les machines : nom → outil → script. +var parityMachines = map[string]map[string]string{ + "nu": {}, + "nvidia": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: NVIDIA GeForce RTX 3090 (UUID: GPU-1)';;\n--query-gpu=compute_cap) printf '8.6\\n8.9\\n8.6\\n';;\n'') echo '| NVIDIA-SMI 570.00 Driver Version: 570.00 CUDA Version: 12.8 |';;\n--query-gpu=*) printf '0, NVIDIA GeForce RTX 3090, 24576, 100, 8.6, 00000000:01:00.0, 1, 4, 16, 16, 9751\\n1, Carte B, 8192, 5, 7.5, [N/A], [N/A], 3, 8, 16, 7001\\n';;\nesac\n", + "nvcc": "#!/bin/sh\nexit 0\n", + }, + "nvidia-sans-nvcc": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: NVIDIA (UUID: GPU-1)';;\n--query-gpu=compute_cap) echo '12.0';;\nesac\n", + }, + "nvidia-muet": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'rien';;\nesac\n", + "nvcc": "#!/bin/sh\nexit 0\n", + }, + "nvidia-en-panne": { + "nvidia-smi": "#!/bin/sh\nexit 9\n", + "nvcc": "#!/bin/sh\nexit 0\n", + }, + "rocm": { + "hipcc": "#!/bin/sh\nexit 0\n", + }, + "glslc-ldconfig": { + "glslc": "#!/bin/sh\nexit 0\n", + "ldconfig": "#!/bin/sh\necho '\tlibvulkan.so.1 (libc6,x86-64) => /usr/lib/libvulkan.so.1'\n", + }, + "vulkan": { + "glslc": "#!/bin/sh\nexit 0\n", + "vulkaninfo": "#!/bin/sh\nexit 0\n", + }, + "nvidia-jumelles": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: Carte B';;\n--query-gpu=*) printf '0, Carte B, 8192, 5, 7.5, [N/A], 1, 3, 8, 16, 7001\\n1, Carte B, 8192, 5, 7.5, [N/A], 1, 3, 8, 16, 7001\\n';;\nesac\n", + }, + "liaison-partielle": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n--query-gpu=*) echo '0, Carte P, 4096, 1, 8.6, 00000000:02:00.0, [N/A], [N/A], 4, 8, 5001';;\nesac\n", + }, + "vulkaninfo-seul": { + "vulkaninfo": "#!/bin/sh\nexit 0\n", + }, + "arch-ancienne": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n--query-gpu=index*pci.bus_id*) echo 'Field \"pci.bus_id\" is not a valid field to query.'; exit 2;;\n--query-gpu=*) echo '0, Vieille carte, 4096, 10, 6.1';;\n-L) echo 'GPU 0: Vieille carte';;\nesac\n", + }, +} + +var ( + parityTSRe = regexp.MustCompile(`"(started_at|ended_at)":[1-9][0-9]*`) + parityJobsRe = regexp.MustCompile(`"jobs":[0-9]+`) +) + +func TestPariteBackends(t *testing.T) { + for _, p := range []string{"/usr/local/cuda", "/opt/rocm"} { + if _, err := os.Stat(p); err == nil { + t.Skipf("%s présent : la machine fausserait le journal", p) + } + } + if m, _ := filepath.Glob("/usr/local/cuda-*"); len(m) > 0 { + t.Skip("CUDA installé : la machine fausserait le journal") + } + gitBin, err := exec.LookPath("git") + if err != nil { + t.Skip("git absent") + } + home := testHome(t) + t.Setenv("LOKI_ENGINE_BIN", "") + tools := t.TempDir() + t.Setenv("PATH", tools) + resetBackendsState() + t.Cleanup(resetBackendsState) + + // Le faux GitHub. + var mu sync.Mutex + var rel parityRelease + gh := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mu.Lock() + cur := rel + mu.Unlock() + if r.URL.Path == "/latest" { + w.WriteHeader(cur.Status) + _, _ = w.Write([]byte(strings.ReplaceAll(cur.JSON, "{{GH}}", "http://"+r.Host))) + return + } + entries, ok := cur.Assets[strings.TrimPrefix(r.URL.Path, "/dl/")] + if !ok { + http.NotFound(w, r) + return + } + _, _ = w.Write(parityTarGz(t, entries)) + })) + defer gh.Close() + old := llamaReleasesAPI + llamaReleasesAPI = gh.URL + "/latest" + defer func() { llamaReleasesAPI = old }() + + mask := func(s string) string { + s = strings.ReplaceAll(s, gh.URL, "{{GH}}") + s = strings.ReplaceAll(s, home, "{{HOME}}") + s = parityJobsRe.ReplaceAllString(s, `"jobs":"{{JOBS}}"`) + return parityTSRe.ReplaceAllString(s, `"$1":"{{T}}"`) + } + unmask := func(s string) string { return strings.ReplaceAll(s, "{{HOME}}", home) } + handlers := map[string]http.HandlerFunc{ + "/api/llamacpp": handleLlamacpp, + "/api/llamacpp/check": handleLlamacppCheck, + "/api/llamacpp/prebuilt/check": handleLlamacppPrebuiltCheck, + "/api/llamacpp/prebuilt": handleLlamacppPrebuilt, + "/api/llamacpp/use": handleLlamacppUse, + "/api/llamacpp/job": handleLlamacppJob, + "/api/llamacpp/uninstall-custom": handleLlamacppUninstallCustom, + "/api/backends": handleBackends, + "/api/backends/custom": handleBackendsCustom, + "/api/backends/devices": handleBackendDevices, + } + call := func(method, path, body string) (int, any) { + req := httptest.NewRequest(method, path, strings.NewReader(body)) + rec := httptest.NewRecorder() + handlers[strings.SplitN(path, "?", 2)[0]](rec, req) + var out any + if err := json.Unmarshal([]byte(mask(rec.Body.String())), &out); err != nil { + t.Fatalf("%s : corps illisible %q", path, rec.Body.String()) + } + return rec.Code, out + } + machine := func(name string) { + entries, _ := os.ReadDir(tools) + for _, e := range entries { + _ = os.Remove(filepath.Join(tools, e.Name())) + } + if err := os.Symlink(gitBin, filepath.Join(tools, "git")); err != nil { + t.Fatal(err) + } + for tool, script := range parityMachines[name] { + if err := os.WriteFile(filepath.Join(tools, tool), []byte(script), 0o755); err != nil { + t.Fatal(err) + } + } + } + machine("nu") + + run := func(st parityBackendsStep) parityBackendsStep { + if st.Machine != "" { + machine(st.Machine) + } + for _, g := range st.Git { + parityGit(t, gitBin, home, g) + } + files := map[string]string{} + for k, v := range st.Files { + files[k] = unmask(v) + } + parityApplyFiles(t, home, files) + for k, v := range st.Config { + if err := SetConfigKey(k, unmask(v)); err != nil { + t.Fatal(err) + } + } + if st.Engine != nil { + t.Setenv("LOKI_ENGINE_BIN", unmask(*st.Engine)) + } + if st.Release != nil { + mu.Lock() + rel = *st.Release + mu.Unlock() + } + var lock *tuneLock + if st.Tune { + l, err := tuneLockAcquire("web", false) + if err != nil { + t.Fatal(err) + } + lock = l + } + st.Status, st.Out = call(st.Method, st.Path, unmask(st.Body)) + if lock != nil { + lock.release() + } + if st.Wait { + deadline := time.Now().Add(30 * time.Second) + for lcJobSnapshot(0, false)["running"] == true { + if time.Now().After(deadline) { + t.Fatalf("%s : le job ne finit pas", st.Name) + } + time.Sleep(20 * time.Millisecond) + } + _, st.Job = call("GET", "/api/llamacpp/job?from=0", "") + } + st.After = map[string]string{} + if v := ReadConfig()["BIN"]; v != "" { + st.After["config/BIN"] = mask(v) + } + if v := getStr(bkState, "build_job"); v != "" { + st.After["state/build_job"] = mask(v) + } + if b, err := os.ReadFile(filepath.Join(home, "loki-build.log")); err == nil { + st.After["loki-build.log"] = mask(string(b)) + } + if b, err := os.ReadFile(filepath.Join(home, "devices.json")); err == nil { + st.After["devices.json"] = mask(string(b)) + } + st.Tree = parityTree(t, home) + for i := range st.Tree { + st.Tree[i] = mask(st.Tree[i]) + } + return st + } + + str := func(s string) *string { return &s } + tarOK := []parityArchEntry{ + {Name: "llama-b300/", Type: "dir", Mode: 0o755}, + {Name: "llama-b300/llama-server", Type: "file", Body: "#!/bin/sh\necho serveur\n", Mode: 0o750}, + {Name: "llama-b300/libggml.so.1.0", Type: "file", Body: "lib", Mode: 0o644}, + {Name: "llama-b300/libggml.so.1", Type: "symlink", Link: "libggml.so.1.0"}, + {Name: "llama-b300/libggml.so", Type: "symlink", Link: "absente.so"}, + {Name: "llama-b300/llama-cli", Type: "hardlink", Link: "llama-b300/llama-server"}, + {Name: "llama-b300/sous/doc.txt", Type: "file", Body: "doc", Mode: 0o600}, + } + relJSON := func(tag string, names ...string) string { + var assets []string + for _, n := range names { + assets = append(assets, `{"name":"`+n+`","browser_download_url":"{{GH}}/dl/`+n+`","size":2500000}`) + } + return `{"tag_name":"` + tag + `","assets":[` + strings.Join(assets, ",") + `]}` + } + cpu := "llama-b300-bin-ubuntu-x64.tar.gz" + if runtime.GOARCH == "arm64" { + cpu = "llama-b300-bin-ubuntu-arm64.tar.gz" + } + allAssets := []string{"llama-b300-bin-macos-arm64.zip", "cudart-llama-bin-win-cuda-12.4-x64.zip", + "llama-b300-bin-win-cuda-12.4-x64.zip", "llama-b300-bin-ubuntu-vulkan-x64.tar.gz", + "llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz", "llama-b300-bin-ubuntu-vulkan-arm64.tar.gz", + "llama-b300-bin-ubuntu-arm64.tar.gz", "llama-b300-bin-ubuntu-x64.tar.gz"} + okRel := &parityRelease{Status: 200, JSON: relJSON("b300", allAssets...), + Assets: map[string][]parityArchEntry{cpu: tarOK}} + pb := "backends/llama.cpp-prebuilt/" + + var steps []parityBackendsStep + for _, st := range []parityBackendsStep{ + // --- statut, rien d'installé --- + {Name: "statut vide", Method: "GET", Path: "/api/llamacpp"}, + {Name: "backends vides", Method: "GET", Path: "/api/backends"}, + {Name: "custom vides", Method: "GET", Path: "/api/backends/custom"}, + {Name: "job absent", Method: "GET", Path: "/api/llamacpp/job"}, + + // --- précompilé déjà là --- + {Name: "deux versions précompilées", Files: map[string]string{ + pb + "llama-b100/llama-server": "#!/bin/sh\n", + pb + "llama-b200/build/bin/llama-server": "#!/bin/sh\n", + pb + "VERSION": "b100 12.4 fmt2\n", + }, Config: map[string]string{"BIN": "{{HOME}}/" + pb + "llama-b200/build/bin/llama-server"}, + Method: "GET", Path: "/api/llamacpp"}, + {Name: "VERSION absent : la plus récente", Files: map[string]string{pb + "VERSION": "-"}, + Method: "GET", Path: "/api/llamacpp"}, + {Name: "BIN précompilé disparu", Config: map[string]string{"BIN": "{{HOME}}/" + pb + "llama-b050/llama-server"}, + Method: "GET", Path: "/api/llamacpp"}, + + // --- backends custom --- + {Name: "backends custom", Files: map[string]string{ + "backends/fork-a/build/bin/llama-server": "#!/bin/sh\n", + "backends/fork-a/CMakeLists.txt": "", + "backends/fork-b/bin/llama-server": "#!/bin/sh\n", + "backends/fork-c/build/bin/llama-server": "/", + "backends/fork-c/llama-server.exe": "x", + "backends/.cache/llama-server": "x", + "backends/vide/": "/", + "backends/lien": "-> fork-b", + "backends/fichier": "x", + pb + "bin/llama-server": "#!/bin/sh\n", // vu par le balayage, mais pas un backend custom + }, Config: map[string]string{"BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server"}, + Method: "GET", Path: "/api/backends"}, + {Name: "custom seulement", Method: "GET", Path: "/api/backends/custom"}, + {Name: "statut sur un fork", Method: "GET", Path: "/api/llamacpp"}, + {Name: "désinstaller le canonique", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"llama.cpp"}`}, + {Name: "désinstaller le précompilé", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":" LLAMA.CPP-prebuilt "}`}, + {Name: "désinstaller sans nom", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":""}`}, + {Name: "désinstaller, corps illisible", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{`}, + {Name: "désinstaller l'actif", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"Fork-A"}`}, + {Name: "désinstaller par un chemin", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"../fork-b"}`}, + {Name: "désinstaller un absent", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"fork-z"}`}, + {Name: "désinstaller un lien", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"lien"}`}, + {Name: "désinstaller un fichier", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"fichier"}`}, + {Name: "désinstaller un dossier sans binaire", Method: "POST", Path: "/api/llamacpp/uninstall-custom", Body: `{"name":"vide"}`}, + + // --- dépôt git du build local --- + {Name: "dépôt cloné", Git: []string{ + "init src", "commit src 2024-01-02T03:04:05+00:00 premier état", + "clone src backends/llama.cpp", + }, Files: map[string]string{"backends/llama.cpp/build/bin/llama-server": "#!/bin/sh\n"}, + Config: map[string]string{"BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server"}, + Method: "GET", Path: "/api/llamacpp"}, + {Name: "amont avancé, pas encore vu", Git: []string{"commit src 2024-02-03T04:05:06+00:00 & état"}, + Method: "GET", Path: "/api/llamacpp"}, + {Name: "vérification git", Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "retard connu", Method: "GET", Path: "/api/llamacpp"}, + {Name: "binaire Release", Files: map[string]string{ + "backends/llama.cpp/build/bin/llama-server": "-", + "backends/llama.cpp/build/bin/Release/llama-server": "#!/bin/sh\n", + }, Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "sans binaire", Files: map[string]string{"backends/llama.cpp/build/bin/Release/llama-server": "-"}, + Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "à jour, sans binaire", Git: []string{"pull backends/llama.cpp"}, Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "tête détachée", Git: []string{"detach backends/llama.cpp"}, Method: "GET", Path: "/api/llamacpp"}, + {Name: "vérification, tête détachée", Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "origine perdue", Git: []string{"remote-bad backends/llama.cpp"}, Method: "POST", Path: "/api/llamacpp/check"}, + {Name: "pas de dépôt", Config: map[string]string{"BIN": "/nulle/part/llama-server"}, + Files: map[string]string{"backends/llama.cpp/.git": "-"}, Method: "POST", Path: "/api/llamacpp/check"}, + + // --- bascule fast / opt --- + {Name: "bascule fast", Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"fast"}`}, + {Name: "bascule opt sans build", Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"opt"}`}, + {Name: "bascule opt", Files: map[string]string{"backends/llama.cpp/build/llama-server": "#!/bin/sh\n"}, + Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"opt"}`}, + {Name: "bascule opt depuis un fork", Config: map[string]string{"BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server"}, + Files: map[string]string{"backends/fork-a/build/llama-server": "#!/bin/sh\n"}, + Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"opt"}`}, + {Name: "mode inconnu", Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"turbo"}`}, + {Name: "mode absent", Method: "POST", Path: "/api/llamacpp/use", Body: ``}, + {Name: "mode de travers", Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":1}`}, + {Name: "bascule pendant une optimisation", Tune: true, Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"fast"}`}, + {Name: "fast sans précompilé", Files: map[string]string{pb: "-"}, + Method: "POST", Path: "/api/llamacpp/use", Body: `{"mode":"fast"}`}, + + // --- moteur téléchargé, moteur de l'image --- + {Name: "moteur téléchargé", Files: map[string]string{"engine/server-cuda-b10450/llama-server": "#!/bin/sh\n"}, + Config: map[string]string{"BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server"}, + Method: "GET", Path: "/api/llamacpp"}, + {Name: "moteur de l'image", Engine: str(" {{HOME}}/engine/server-cuda-b10450/llama-server "), + Method: "GET", Path: "/api/llamacpp"}, + {Name: "moteur de l'image absent", Engine: str("{{HOME}}/image/llama-server"), + Method: "GET", Path: "/api/llamacpp"}, + {Name: "moteur de l'image : un dossier", Engine: str("{{HOME}}/engine"), + Method: "GET", Path: "/api/llamacpp"}, + + // --- dernière release --- + {Name: "release : CPU", Release: okRel, Engine: str(""), Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release refusée", Release: &parityRelease{Status: 403, JSON: `{"message":"rate limit"}`}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release sans tag", Release: &parityRelease{Status: 200, JSON: `{"tag_name":"","assets":[]}`}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release illisible", Release: &parityRelease{Status: 200, JSON: `{"tag_name":`}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release vide", Release: &parityRelease{Status: 200, JSON: ``}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release, tag de travers", Release: &parityRelease{Status: 200, JSON: `{"tag_name":5}`}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "release sans asset adapté", Release: &parityRelease{Status: 200, JSON: relJSON("b301", "llama-b301-bin-macos-arm64.zip")}, + Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + + // --- job des binaires précompilés --- + {Name: "installation", Release: okRel, Files: map[string]string{ + pb + "llama-b100/llama-server": "#!/bin/sh\n", + pb + "llama-b200/llama-server": "#!/bin/sh\n", + pb + "llama-b30/llama-server": "#!/bin/sh\n", // préfixe de llama-b300 : supprimé quand même + pb + "autre/llama-server": "#!/bin/sh\n", + pb + "VERSION": "b100 12.4 fmt2\n", + }, Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "statut après installation", Method: "GET", Path: "/api/llamacpp"}, + {Name: "release à jour", Method: "POST", Path: "/api/llamacpp/prebuilt/check"}, + {Name: "lignes à partir de 3", Method: "GET", Path: "/api/llamacpp/job?from=3"}, + {Name: "lignes au-delà", Method: "GET", Path: "/api/llamacpp/job?from=99"}, + {Name: "lignes, from négatif", Method: "GET", Path: "/api/llamacpp/job?from=-4"}, + {Name: "lignes, from illisible", Method: "GET", Path: "/api/llamacpp/job?from=abc"}, + {Name: "lignes, from démesuré", Method: "GET", Path: "/api/llamacpp/job?from=99999999999999999999"}, + {Name: "déjà à jour", Files: map[string]string{pb + "llama-b250/x": ""}, + Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "ancien format : réextrait", Files: map[string]string{pb + "VERSION": "b300 \n"}, + Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "pendant une optimisation", Tune: true, Method: "POST", Path: "/api/llamacpp/prebuilt"}, + {Name: "GitHub refuse", Release: &parityRelease{Status: 403, JSON: `{}`}, + Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "rien d'adapté", Release: &parityRelease{Status: 200, JSON: relJSON("b302", "llama-b302-bin-macos-arm64.zip")}, + Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "archive absente", Release: &parityRelease{Status: 200, JSON: relJSON("b303", allAssets...)}, + Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "archive piégée", Release: &parityRelease{Status: 200, JSON: relJSON("b304", allAssets...), + Assets: map[string][]parityArchEntry{cpu: { + {Name: "llama-b304/ok", Type: "file", Body: "x", Mode: 0o644}, + {Name: "../evasion", Type: "file", Body: "x", Mode: 0o644}, + }}}, Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "archive sans serveur", Release: &parityRelease{Status: 200, JSON: relJSON("b305", allAssets...), + Assets: map[string][]parityArchEntry{cpu: { + {Name: "llama-b305/llama-cli", Type: "file", Body: "x", Mode: 0o755}, + }}}, Files: map[string]string{pb: "-"}, Method: "POST", Path: "/api/llamacpp/prebuilt", Wait: true}, + {Name: "statut après échecs", Method: "GET", Path: "/api/llamacpp"}, + + // --- GPU vus par un moteur --- + {Name: "GPU sans moteur", Config: map[string]string{"BIN": ""}, Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU d'un moteur absent", Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"/nulle/part/llama-server"}`}, + {Name: "GPU : pas un llama-server", Files: map[string]string{"outils/autre": "#!/bin/sh\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/outils/autre"}`}, + {Name: "GPU listés", Machine: "nvidia", Files: map[string]string{ + "gpu/LLAMA-SERVER": "#!/bin/sh\n[ \"$1\" = --list-devices ] || exit 7\necho 'Available devices:'\necho \" CUDA0: NVIDIA GeForce RTX 3090 (0 MiB, 0 MiB free)\"\necho \" CUDA1: Carte B (8192 MiB, 8000 MiB free)\"\necho \" Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 20000 MiB free)\"\necho \" CUDA2: ordre ${CUDA_DEVICE_ORDER:-aucun} cvd ${CUDA_VISIBLE_DEVICES:-aucun} (1 MiB, 1 MiB free)\" >&2\n", + }, Method: "POST", Path: "/api/backends/devices", Body: `{"bin":" {{HOME}}/gpu/LLAMA-SERVER "}`}, + {Name: "GPU en cache", Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: changé (1 MiB, 1 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/LLAMA-SERVER"}`}, + {Name: "GPU filtrés", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "1,0", "BIN": "{{HOME}}/gpu/LLAMA-SERVER"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho \" CUDA0: ordre $CUDA_DEVICE_ORDER cvd $CUDA_VISIBLE_DEVICES (10 MiB, 5 MiB free)\"\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":""}`}, + {Name: "GPU : mémoire nulle non figée", Machine: "nu", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "0"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Saturée (0 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : relu, pas en cache", Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Saturée (100 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : moteur planté, repli disque", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "1,0"}, + Files: map[string]string{"gpu/llama-server": "#!/bin/sh\necho ' CUDA0: partielle (1 MiB, 1 MiB free)'\nexit 3\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/llama-server"}`}, + {Name: "GPU : planté, partiel", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "2"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/llama-server"}`}, + {Name: "GPU : planté, rien", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "3"}, + Files: map[string]string{"gpu/llama-server": "#!/bin/sh\necho 'CUDA error: out of memory'\nexit 4\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/llama-server"}`}, + {Name: "GPU : tué", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "4"}, + Files: map[string]string{"gpu/llama-server": "#!/bin/sh\nkill -9 $$\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/llama-server"}`}, + {Name: "GPU : non exécutable", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "5"}, + Files: map[string]string{"gpu/llama-server": "pas un script"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":"{{HOME}}/gpu/llama-server"}`}, + {Name: "GPU : corps illisible, BIN de la config", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "6"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Lue (2 MiB, 1 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{"bin":`}, + {Name: "GPU : pilote ancien", Machine: "arch-ancienne", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "7"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Vieille carte (0 MiB, 0 MiB free)'\necho ' CUDA1: Vieille carte (0 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : deux cartes de même nom", Machine: "nvidia", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "8"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte B (0 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : lu à vide, gardé sur disque", Machine: "nu", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "9"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Pleine (0 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : cartes jumelles chez nvidia-smi", Machine: "nvidia-jumelles", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "10"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte B (0 MiB, 0 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : liaison sans génération connue", Machine: "liaison-partielle", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "11"}, + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte P (4096 MiB, 4000 MiB free)'\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : liste vide sur le disque, pas de repli", Machine: "nu", Config: map[string]string{"CUDA_VISIBLE_DEVICES": "vide"}, + Files: map[string]string{ + "devices.json": `{"{{HOME}}/gpu/LLAMA-SERVER\u0000vide": []}`, + "gpu/LLAMA-SERVER": "#!/bin/sh\nexit 3\n", + }, Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + {Name: "GPU : planté, repli sur le disque", + Files: map[string]string{"gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: partielle (1 MiB, 1 MiB free)'\nexit 3\n"}, + Method: "POST", Path: "/api/backends/devices", Body: `{}`}, + } { + steps = append(steps, run(st)) + } + + // --- plan de build, conseil et release, machine par machine --- + type planCase struct { + Machine string `json:"machine"` + Plan any `json:"plan"` + Reco any `json:"reco"` + Check any `json:"check"` + } + var plans []planCase + machineNames := make([]string, 0, len(parityMachines)) + for n := range parityMachines { + machineNames = append(machineNames, n) + } + sort.Strings(machineNames) + planRel := parityRelease{Status: 200, JSON: relJSON("b400", allAssets...)} + mu.Lock() + rel = planRel + mu.Unlock() + for _, n := range machineNames { + machine(n) + _, out := call("GET", "/api/llamacpp", "") + m := out.(map[string]any) + _, check := call("POST", "/api/llamacpp/prebuilt/check", "") + plans = append(plans, planCase{Machine: n, Plan: m["plan"], Reco: m["reco"], Check: check}) + } + machine("vulkaninfo-seul") + sansVulkanRel := parityRelease{Status: 200, JSON: relJSON("b401", "llama-b401-bin-ubuntu-rocm-7.0-x64.tar.gz", "llama-b401-bin-ubuntu-x64.tar.gz", "llama-b401-bin-ubuntu-arm64.tar.gz")} + mu.Lock() + rel = sansVulkanRel + mu.Unlock() + _, sansVulkan := call("POST", "/api/llamacpp/prebuilt/check", "") + machine("rocm") + rocmRel := parityRelease{Status: 200, JSON: relJSON("b402", "llama-b402-bin-ubuntu-vulkan-x64.tar.gz", "llama-b402-bin-ubuntu-x64.tar.gz", "llama-b402-bin-ubuntu-vulkan-arm64.tar.gz", "llama-b402-bin-ubuntu-arm64.tar.gz")} + mu.Lock() + rel = rocmRel + mu.Unlock() + _, rocmSansAsset := call("POST", "/api/llamacpp/prebuilt/check", "") + + got, err := parityJSON(map[string]any{ + "goarch": runtime.GOARCH, + "machines": parityMachines, + "steps": steps, + "plans": plans, + "plan_release": planRel, + "sans_vulkan": map[string]any{"release": sansVulkanRel, "out": sansVulkan}, + "rocm_sans_asset": map[string]any{"release": rocmRel, "out": rocmSansAsset}, + "job": parityJobScript(t, home), + }) + if err != nil { + t.Fatal(err) + } + if os.Getenv("LOKI_PARITY_UPDATE") == "1" { + if err := os.MkdirAll(filepath.Dir(parityBackendsFile), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(parityBackendsFile, got, 0o644); err != nil { + t.Fatal(err) + } + return + } + want, err := os.ReadFile(parityBackendsFile) + if err != nil { + t.Fatalf("journal de référence absent (%v) : LOKI_PARITY_UPDATE=1 pour le créer", err) + } + if string(got) != string(want) { + t.Errorf("les backends ne produisent plus le journal rangé dans %s.\n"+ + "Si c'est voulu : LOKI_PARITY_UPDATE=1 go test ./internal/loki -run TestPariteBackends,\n"+ + "puis cargo test --test backends dit si le port Rust suit.\n--- obtenu ---\n%s", parityBackendsFile, got) + } +} + +// resetBackendsState : pas de job ni de GPU en cache d'un test à l'autre. +func resetBackendsState() { + lcMu.Lock() + lcCur = nil + lcLastSave = time.Time{} + lcMu.Unlock() + setBuildSink(nil) + devCacheMu.Lock() + devCache = map[string]devCacheEntry{} + devCacheMu.Unlock() +} + +// parityApplyFiles pose les fichiers d'une étape, dans l'ordre des noms. +func parityApplyFiles(t *testing.T, home string, files map[string]string) { + t.Helper() + names := make([]string, 0, len(files)) + for n := range files { + names = append(names, n) + } + sort.Strings(names) + for _, n := range names { + v := files[n] + p := filepath.Join(home, n) + switch { + case v == "-": + if err := os.RemoveAll(p); err != nil { + t.Fatal(err) + } + continue + case v == "/": + if err := os.MkdirAll(p, 0o755); err != nil { + t.Fatal(err) + } + continue + } + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { + t.Fatal(err) + } + if target, ok := strings.CutPrefix(v, "-> "); ok { + _ = os.Remove(p) + if err := os.Symlink(target, p); err != nil { + t.Fatal(err) + } + continue + } + mode := os.FileMode(0o644) + if strings.HasPrefix(v, "#!") { + mode = 0o755 + } + // Remplacé, pas réécrit en place : un script qui vient de tourner ne + // gêne pas l'écriture (ETXTBSY). + _ = os.Remove(p) + if err := os.WriteFile(p, []byte(v), mode); err != nil { + t.Fatal(err) + } + } +} + +// parityGit : les opérations git d'une étape, dates et identité fixées pour +// des commits reproductibles. +func parityGit(t *testing.T, gitBin, home, op string) { + t.Helper() + f := strings.SplitN(op, " ", 4) + gitIn := func(dir, date string, args ...string) { + cmd := exec.Command(gitBin, args...) + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GIT_CONFIG_GLOBAL=/dev/null", "GIT_CONFIG_NOSYSTEM=1", + "GIT_AUTHOR_NAME=Loki", "GIT_AUTHOR_EMAIL=loki@exemple.fr", + "GIT_COMMITTER_NAME=Loki", "GIT_COMMITTER_EMAIL=loki@exemple.fr", + "GIT_AUTHOR_DATE="+date, "GIT_COMMITTER_DATE="+date) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("git %v : %v\n%s", args, err, out) + } + } + switch f[0] { + case "init": + dir := filepath.Join(home, f[1]) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + gitIn(dir, "", "init", "-q", "-b", "master") + case "commit": + dir := filepath.Join(home, f[1]) + if err := os.WriteFile(filepath.Join(dir, "README"), []byte(f[3]), 0o644); err != nil { + t.Fatal(err) + } + gitIn(dir, f[2], "add", "README") + gitIn(dir, f[2], "commit", "-q", "-m", f[3]) + case "clone": + gitIn(home, "", "clone", "-q", filepath.Join(home, f[1]), filepath.Join(home, f[2])) + case "pull": + gitIn(filepath.Join(home, f[1]), "", "pull", "-q", "--ff-only") + case "detach": + gitIn(filepath.Join(home, f[1]), "", "checkout", "-q", "--detach") + case "remote-bad": + gitIn(filepath.Join(home, f[1]), "", "remote", "set-url", "origin", filepath.Join(home, "nulle-part")) + default: + t.Fatalf("opération git inconnue : %s", op) + } +} + +// parityTarGz construit une archive .tar.gz. +func parityTarGz(t *testing.T, entries []parityArchEntry) []byte { + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + tw := tar.NewWriter(gz) + for _, e := range entries { + h := &tar.Header{Name: e.Name, Mode: e.Mode, ModTime: time.Unix(1700000000, 0)} + switch e.Type { + case "dir": + h.Typeflag = tar.TypeDir + case "symlink": + h.Typeflag, h.Linkname, h.Mode = tar.TypeSymlink, e.Link, 0o777 + case "hardlink": + h.Typeflag, h.Linkname = tar.TypeLink, e.Link + default: + h.Typeflag, h.Size = tar.TypeReg, int64(len(e.Body)) + } + if err := tw.WriteHeader(h); err != nil { + t.Error(err) + } + if h.Typeflag == tar.TypeReg { + _, _ = tw.Write([]byte(e.Body)) + } + } + _ = tw.Close() + _ = gz.Close() + return buf.Bytes() +} + +// parityTree : ce qu'il y a sous backends/ et engine/ (« d », « f mode », « l +// cible »), trié. +func parityTree(t *testing.T, home string) []string { + var out []string + for _, root := range []string{"backends", "engine"} { + _ = filepath.WalkDir(filepath.Join(home, root), func(p string, d fs.DirEntry, err error) error { + if err != nil { + return nil + } + rel, _ := filepath.Rel(home, p) + if strings.Contains(rel, "/.git/") || strings.HasSuffix(rel, "/.git") { + if d.IsDir() { + return filepath.SkipDir + } + return nil + } + info, err := os.Lstat(p) + if err != nil { + return nil + } + switch { + case info.Mode()&os.ModeSymlink != 0: + target, _ := os.Readlink(p) + out = append(out, "l "+rel+" -> "+target) + case info.IsDir(): + out = append(out, "d "+rel) + default: + b, _ := os.ReadFile(p) + out = append(out, "f "+rel+" "+info.Mode().Perm().String()+" "+string(b)) + } + return nil + }) + } + sort.Strings(out) + return out +} + +// parityJobScript rejoue le job pas à pas (sans la façade) : début, lignes +// de build (phases déduites, fichiers compilés), troncature à lcMaxLines, +// phases, commits, échec, fin, refus d'un second job, vues à partir d'un +// décalage, état écrit en base et journal ; puis la reprise au démarrage. +func parityJobScript(t *testing.T, home string) any { + resetBackendsState() + _ = os.Remove(lcJobLogPath()) + type op struct { + Op string `json:"op"` + Arg string `json:"arg,omitempty"` + From int `json:"from,omitempty"` + Out any `json:"out,omitempty"` + } + tsRe := regexp.MustCompile(`"(started_at|ended_at)":[1-9][0-9]*`) + norm := func(v any) any { + b, _ := json.Marshal(v) + var out any + _ = json.Unmarshal([]byte(tsRe.ReplaceAllString(string(b), `"$1":"{{T}}"`)), &out) + return out + } + var ops []op + done := make(chan struct{}) + release := make(chan struct{}) + do := func(o op) { + switch o.Op { + case "start": + err := startLcJob(o.Arg, func() { <-release; close(done) }) + if err != nil { + o.Out = err.Error() + } else { + o.Out = "ok" + } + case "line": + lcAppend(o.Arg) + case "lines": + for i := 0; i < 4002; i++ { + lcAppend("[" + o.Arg + "] bruit") + } + case "phase": + lcPhase(o.Arg) + case "fail": + lcFail(errors.New(o.Arg)) + case "done": + lcDone(o.Arg) + case "old", "new": + lcSetCommit(o.Op, o.Arg) + case "end": + close(release) + <-done + deadline := time.Now().Add(10 * time.Second) + for lcJobSnapshot(0, false)["running"] == true && time.Now().Before(deadline) { + time.Sleep(10 * time.Millisecond) + } + case "snapshot": + o.Out = norm(lcJobSnapshot(o.From, true)) + case "summary": // vue longue résumée : nombre de lignes, première, dernière + v := lcJobSnapshot(o.From, true) + lines, _ := v["lines"].([]string) + v["lines"] = map[string]any{"n": len(lines), "first": lines[0], "last": lines[len(lines)-1]} + o.Out = norm(v) + case "head": + o.Out = norm(lcJobSnapshot(0, false)) + case "state": + o.Out = tsRe.ReplaceAllString(getStr(bkState, "build_job"), `"$1":"{{T}}"`) + case "log": + b, _ := os.ReadFile(lcJobLogPath()) + o.Out = string(b) + } + ops = append(ops, o) + } + for _, o := range []op{ + {Op: "head"}, + {Op: "line", Arg: "avant tout job"}, + {Op: "start", Arg: "update"}, + {Op: "state"}, + {Op: "start", Arg: "engine"}, + {Op: "line", Arg: "-- The C compiler identification is GNU 13.2.0 avec un très long suffixe é"}, + {Op: "head"}, + {Op: "line", Arg: "[ 12%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml.cpp.o"}, + {Op: "line", Arg: " Compiling CUDA source file ..\\ggml-cuda\\fattn.cu..."}, + {Op: "line", Arg: "softmax.cuh"}, + {Op: "line", Arg: "[100%] Linking CXX executable bin/llama-server"}, + {Op: "line", Arg: "état : é.cpp"}, + {Op: "head"}, + {Op: "old", Arg: "abc1234"}, + {Op: "phase", Arg: "git pull origin/master…"}, + {Op: "new", Arg: ""}, + {Op: "state"}, + {Op: "line", Arg: "-- Configuring done"}, // moins de 2 s après la dernière écriture : pas réécrit + {Op: "state"}, + {Op: "snapshot", From: 2}, + {Op: "lines", Arg: "bloc"}, + {Op: "snapshot", From: 4005}, + {Op: "summary", From: 0}, + {Op: "summary", From: 3}, + {Op: "line", Arg: "Build files have been written to: /src/build"}, + {Op: "summary", From: 0}, + {Op: "line", Arg: "une de plus"}, + {Op: "summary", From: 0}, + {Op: "fail", Arg: "compilation échouée: exit status 2"}, + {Op: "done", Arg: "tout de même"}, + {Op: "end"}, + {Op: "head"}, + {Op: "state"}, + } { + do(o) + } + logLines := strings.Count(func() string { b, _ := os.ReadFile(lcJobLogPath()); return string(b) }(), "\n") + + // Reprise au démarrage : un job noté « en cours » est mort avec le + // processus précédent ; un job fini est rendu tel quel. + type restoreCase struct { + State string `json:"state"` + Log *string `json:"log"` + Out any `json:"out"` + After string `json:"after"` + } + str := func(s string) *string { return &s } + var restores []restoreCase + for _, rc := range []restoreCase{ + {State: ``}, + {State: `{"action":""}`}, + {State: `{"action":"prebuilt","phase":"fini","running":false,"started_at":5,"ended_at":6}`, Log: str("a\nb\n")}, + {State: `{"action":"update","phase":"compilation… 3 fichiers","compiled":3,"running":true,"started_at":5,"old":"abc"}`, Log: str("x\n")}, + {State: `{"action":"strata","running":true}`}, + {State: `{"action":"engine","running":false}`, Log: str("")}, + {State: `{"action":"engine","running":false}`, Log: str("\n\n")}, + {State: `pas du json`}, + {State: `{"action":"engine","compiled":"3"}`}, + } { + resetBackendsState() + if rc.State == "" { + _ = putStr(bkState, "build_job", "") + } else if err := putStr(bkState, "build_job", rc.State); err != nil { + t.Fatal(err) + } + _ = os.Remove(lcJobLogPath()) + if rc.Log != nil { + if err := os.WriteFile(lcJobLogPath(), []byte(*rc.Log), 0o644); err != nil { + t.Fatal(err) + } + } + lcRestore() + rc.Out = norm(lcJobSnapshot(0, true)) + rc.After = tsRe.ReplaceAllString(getStr(bkState, "build_job"), `"$1":"{{T}}"`) + restores = append(restores, rc) + } + // Journal de plus de lcMaxLines lignes. + resetBackendsState() + var long strings.Builder + for i := 0; i < lcMaxLines+3; i++ { + long.WriteString("ligne\n") + } + _ = putStr(bkState, "build_job", `{"action":"update","running":false}`) + _ = os.WriteFile(lcJobLogPath(), []byte(long.String()), 0o644) + lcRestore() + snap := lcJobSnapshot(lcMaxLines, true) + resetBackendsState() + _ = putStr(bkState, "build_job", "") + _ = os.Remove(lcJobLogPath()) + return map[string]any{"ops": ops, "log_lines": logLines, "restores": restores, "long_restore": norm(snap)} +} diff --git a/internal/loki/web_llamacpp.go b/internal/loki/web_llamacpp.go index 3ab3141..7b2085c 100644 --- a/internal/loki/web_llamacpp.go +++ b/internal/loki/web_llamacpp.go @@ -50,6 +50,10 @@ const lcMaxLines = 4000 // compteur de fichiers compilés à partir du contenu (mêmes heuristiques que le // spinner du CLI). Appelée par le sink de build (emitBuildLine). func lcAppend(line string) { + if facadeBackends() { + facadeJobNote("line", map[string]any{"line": line}) + return + } lcMu.Lock() defer lcMu.Unlock() if lcCur == nil { @@ -74,6 +78,10 @@ func lcAppend(line string) { // lcPhase pose une phase explicite (étapes hors build : clone, fetch, service…) // et la trace aussi dans le log. func lcPhase(phase string) { + if facadeBackends() { + facadeJobNote("phase", map[string]any{"phase": phase}) + return + } lcMu.Lock() if lcCur != nil { lcCur.Phase = phase @@ -91,6 +99,9 @@ func startLcJob(action string, run func()) error { if err := tuneGuard(); err != nil { return err } + if facadeBackends() { // le job est tenu par la façade (facade_backends.go) + return facadeJobStart(action, run) + } lcMu.Lock() defer lcMu.Unlock() if lcCur != nil && lcCur.Running { @@ -115,6 +126,10 @@ func startLcJob(action string, run func()) error { } func lcFail(err error) { + if facadeBackends() { + facadeJobNote("fail", map[string]any{"error": err.Error()}) + return + } lcMu.Lock() if lcCur != nil { lcCur.Err = err.Error() @@ -127,6 +142,10 @@ func lcFail(err error) { } func lcDone(msg string) { + if facadeBackends() { + facadeJobNote("done", map[string]any{"msg": msg}) + return + } lcMu.Lock() if lcCur != nil { lcCur.Phase = msg @@ -476,6 +495,9 @@ func handleLlamacppJob(w http.ResponseWriter, r *http.Request) { // lcJobSnapshot construit la vue JSON du job courant. withLines=false renvoie // juste l'entête (imbriquée dans /api/llamacpp). func lcJobSnapshot(from int, withLines bool) map[string]any { + if facadeBackends() { + return facadeJobSnapshot(from, withLines) + } lcMu.Lock() defer lcMu.Unlock() if lcCur == nil { @@ -576,9 +598,7 @@ func lcRunUpdate(clean bool) { } oldCommit := gitOutput(repo, "rev-parse", "--short", "HEAD") - lcMu.Lock() - lcCur.OldCommit = oldCommit - lcMu.Unlock() + lcSetCommit("old", oldCommit) branch := gitOutput(repo, "rev-parse", "--abbrev-ref", "HEAD") if branch == "" || branch == "HEAD" { @@ -604,9 +624,7 @@ func lcRunUpdate(clean bool) { } } newCommit := gitOutput(repo, "rev-parse", "--short", "HEAD") - lcMu.Lock() - lcCur.NewCommit = newCommit - lcMu.Unlock() + lcSetCommit("new", newCommit) // Le binaire en cours d'exécution ne peut pas être réécrit → stop du service // pendant le build, redémarrage après (même en échec). diff --git a/internal/loki/web_server.go b/internal/loki/web_server.go index aaef0c7..ac2297b 100644 --- a/internal/loki/web_server.go +++ b/internal/loki/web_server.go @@ -143,7 +143,9 @@ func newWebMux() *http.ServeMux { // Idem pour une installation de moteur : elle meurt avec le process. On // recharge son état pour l'annoncer « interrompue » au lieu de n'afficher // plus rien du tout. - lcRestoreOnce.Do(lcRestore) + if !facadeBackends() { // sinon la façade a repris le job (facade_backends.go) + lcRestoreOnce.Do(lcRestore) + } // Chiffrement de la mémoire : une migration interrompue (coupure de courant // en plein chiffrement) reprend ici, si la clé est disponible. Sans clé, elle // attend le déverrouillage (voir handleMemUnlock). Idempotent. diff --git a/rust/loki-rs/src/api.rs b/rust/loki-rs/src/api.rs index d3a5567..b887caa 100644 --- a/rust/loki-rs/src/api.rs +++ b/rust/loki-rs/src/api.rs @@ -18,6 +18,7 @@ use crate::{engstatus, gguf, paths, presets, sysinfo}; use std::collections::BTreeMap; /// Ce dont les routes ont besoin, partagé par toutes les connexions. +#[derive(Clone)] pub struct Ctx { pub store: Store, pub internal: InternalClient, @@ -52,6 +53,9 @@ pub struct Ctx { pub mcp: Option>, /// Mise à jour de Loki tenue par la façade (`LOKI_UPDATE=rust`). pub update: bool, + /// Backends llama.cpp et job des moteurs tenus par la façade + /// (`LOKI_BACKENDS=rust`). + pub backends: Option>, /// Jeton de l'API interne : une requête qui le porte vient du Go. pub internal_token: String, } @@ -73,6 +77,7 @@ impl Ctx { || self.projects || self.mcp.is_some() || self.update + || self.backends.is_some() } /// La requête vient du Go (jeton interne valide) : déjà authentifiée par diff --git a/rust/loki-rs/src/auth.rs b/rust/loki-rs/src/auth.rs index 1beee73..284dc91 100644 --- a/rust/loki-rs/src/auth.rs +++ b/rust/loki-rs/src/auth.rs @@ -32,6 +32,7 @@ pub struct AuthInfo { } /// Client de l'API interne du Go. +#[derive(Clone)] pub struct InternalClient { client: Client>, backend: SocketAddr, diff --git a/rust/loki-rs/src/backends/devices.rs b/rust/loki-rs/src/backends/devices.rs new file mode 100644 index 0000000..96541df --- /dev/null +++ b/rust/loki-rs/src/backends/devices.rs @@ -0,0 +1,327 @@ +//! `/api/backends/devices` : les GPU tels que les voit UN moteur +//! (`llama-server --list-devices`), port de `web_devices.go` — caches +//! mémoire (10 min) et disque (`devices.json`, dernière énumération réussie). + +use std::collections::{BTreeMap, HashMap}; +use std::path::{Path, PathBuf}; +use std::process::Stdio; +use std::sync::{LazyLock, Mutex}; +use std::time::{Duration, Instant}; + +use regex::Regex; +use serde_json::{Map, Value, json}; + +use super::probe::{GpuInfo, Probe}; + +/// `devCacheTTL`. +const CACHE_TTL: Duration = Duration::from_secs(600); + +/// Délai de l'énumération. +const LIST_TIMEOUT: Duration = Duration::from_secs(20); + +// `\s` du Go : blancs ASCII seulement. +static DEVICE_LINE: LazyLock = LazyLock::new(|| { + Regex::new( + &r"^\s*([A-Za-z]+[0-9]+):\s*(.+?)\s*\(([0-9]+)\s*MiB,\s*([0-9]+)\s*MiB free\)\s*$" + .replace(r"\s", r"[\t\n\f\r ]"), + ) + .expect("motif") +}); + +/// `parseListDevices`. +pub fn parse_list_devices(out: &str) -> Vec> { + let mut devs = Vec::new(); + for line in out.split('\n') { + let Some(m) = DEVICE_LINE.captures(line.trim_end_matches('\r')) else { + continue; + }; + let mut d = Map::new(); + d.insert("id".into(), json!(&m[1])); + d.insert("name".into(), json!(&m[2])); + d.insert("total_mib".into(), json!(atoi(&m[3]))); + d.insert("free_mib".into(), json!(atoi(&m[4]))); + devs.push(d); + } + devs +} + +/// `strconv.Atoi` d'une suite de chiffres : 0 si elle déborde. +fn atoi(s: &str) -> i64 { + s.parse().unwrap_or(0) +} + +/// Mémoire totale annoncée (`d["total_mib"].(int)`) : seuls les entiers +/// issus de l'énumération comptent ; 0 sinon. +fn total_mib(d: &Map) -> i64 { + d.get("total_mib").and_then(Value::as_i64).unwrap_or(0) +} + +/// `annotateDevices` : mémoire manquante et liaison PCIe, par nom de carte. +pub fn annotate(devs: &mut [Map], gpus: &[GpuInfo]) { + let mut by_name: HashMap = HashMap::new(); + let mut dup: HashMap = HashMap::new(); + for g in gpus { + let name = g.name.trim().to_string(); + if by_name.contains_key(&name) { + dup.insert(name, true); + continue; + } + by_name.insert(name, g); + } + for d in devs.iter_mut() { + let name = d + .get("name") + .and_then(Value::as_str) + .unwrap_or("") + .trim() + .to_string(); + let Some(g) = by_name.get(&name) else { + continue; + }; + if dup.contains_key(&name) { + continue; + } + if total_mib(d) <= 0 + && let Ok(mb) = g.mem_total.trim().parse::() + { + d.insert("total_mib".into(), json!(mb)); + } + if !d + .get("id") + .and_then(Value::as_str) + .unwrap_or("") + .starts_with("CUDA") + { + continue; + } + if g.link_gen_max == 0 && g.link_width_max == 0 && g.mem_clock_max == 0 { + continue; + } + d.insert( + "link".into(), + json!({ + "gen": g.link_gen, "gen_max": g.link_gen_max, + "width": g.link_width, "width_max": g.link_width_max, + "mem_clock_mhz": g.mem_clock_max, + }), + ); + } +} + +/// `hasZeroMemory`. +pub fn has_zero_memory(devs: &[Map]) -> bool { + devs.iter().any(|d| total_mib(d) <= 0) +} + +/// Une énumération en cache, et quand. +type Cached = (Vec>, Instant); + +/// Les deux caches de l'énumération. +pub struct Devices { + home: PathBuf, + mem: Mutex>, + persist: Mutex<()>, +} + +impl Devices { + pub fn new(home: PathBuf) -> Self { + Devices { + home, + mem: Mutex::new(HashMap::new()), + persist: Mutex::new(()), + } + } + + fn cache_get(&self, key: &str) -> Option>> { + let m = self.mem.lock().unwrap_or_else(|e| e.into_inner()); + m.get(key) + .filter(|(_, at)| at.elapsed() <= CACHE_TTL) + .map(|(d, _)| d.clone()) + } + + fn cache_put(&self, key: &str, devs: &[Map]) { + self.mem + .lock() + .unwrap_or_else(|e| e.into_inner()) + .insert(key.into(), (devs.to_vec(), Instant::now())); + } + + /// `devPersistPath`. + pub fn persist_path(&self) -> PathBuf { + self.home.join("devices.json") + } + + fn persist_load(&self) -> BTreeMap { + std::fs::read(self.persist_path()) + .ok() + .and_then(|b| serde_json::from_slice::>(&b).ok()) + .unwrap_or_default() + } + + fn persist_get(&self, key: &str) -> Option { + let _g = self.persist.lock().unwrap_or_else(|e| e.into_inner()); + self.persist_load() + .remove(key) + .filter(|d| d.as_array().is_some_and(|a| !a.is_empty())) + } + + fn persist_put(&self, key: &str, devs: &[Map]) { + let _g = self.persist.lock().unwrap_or_else(|e| e.into_inner()); + let mut m = self.persist_load(); + m.insert(key.into(), json!(devs)); + let _ = std::fs::write(self.persist_path(), crate::chatx::marshal_indent(&m)); + } + + /// `handleBackendDevices`, une fois `bin` résolu et vérifié : la réponse. + pub async fn list(&self, probe: &Probe, bin: &str, cvd: &str) -> Value { + let key = format!("{bin}\x00{cvd}"); + if let Some(devs) = self.cache_get(&key) { + return json!({ "ok": true, "devices": devs }); + } + let (out, err) = list_devices(bin, cvd).await; + let mut devs = parse_list_devices(&out); + if let Some(err) = err { + if let Some(good) = self.persist_get(&key) { + return json!({ "ok": true, "devices": good, "stale": true }); + } + if devs.is_empty() { + return json!({ "ok": false, "error": format!("le moteur n'a pas répondu : {err}") }); + } + return json!({ "ok": true, "devices": devs, "stale": true }); + } + if let Ok(gpus) = probe.detect_gpus().await { + annotate(&mut devs, &gpus); + } + if !has_zero_memory(&devs) { + self.cache_put(&key, &devs); + } + if !devs.is_empty() { + self.persist_put(&key, &devs); + } + json!({ "ok": true, "devices": devs }) + } +} + +/// `bin --list-devices`, sortie standard et d'erreur mêlées ; l'erreur au +/// format d'`exec` (`exit status N`, `signal: killed`…). +async fn list_devices(bin: &str, cvd: &str) -> (String, Option) { + let dir = crate::paths::go_dir(bin); + let env = crate::serve::run::Env::default(); + let (k, v) = crate::serve::run::library_path_value(&env, &dir); + let mut c = tokio::process::Command::new(bin); + c.arg("--list-devices").env(k, v); + if !cvd.is_empty() { + c.env("CUDA_VISIBLE_DEVICES", cvd) + .env("CUDA_DEVICE_ORDER", "PCI_BUS_ID"); + } + // Sortie standard et d'erreur dans le même tube, comme CombinedOutput. + let (reader, writer) = match std::io::pipe() { + Ok(p) => p, + Err(e) => return (String::new(), Some(e.to_string())), + }; + let writer2 = match writer.try_clone() { + Ok(w) => w, + Err(e) => return (String::new(), Some(e.to_string())), + }; + c.stdin(Stdio::null()) + .stdout(Stdio::from(writer)) + .stderr(Stdio::from(writer2)) + .kill_on_drop(true); + let mut child = match c.spawn() { + Ok(ch) => ch, + Err(e) => { + return ( + String::new(), + Some(crate::paths::os_err("fork/exec", bin, &e)), + ); + } + }; + drop(c); + let read = tokio::task::spawn_blocking(move || { + let mut r = reader; + let mut buf = Vec::new(); + let _ = std::io::Read::read_to_end(&mut r, &mut buf); + buf + }); + let status = tokio::time::timeout(LIST_TIMEOUT, child.wait()).await; + let status = match status { + Ok(s) => s, + Err(_) => { + let _ = child.start_kill(); + let _ = child.wait().await; + Err(std::io::Error::other("signal: killed")) + } + }; + let out = read.await.unwrap_or_default(); + let out = crate::system::go_lossy(&out); + let err = match status { + Ok(s) if s.success() => None, + Ok(s) => Some(exit_text(s)), + Err(e) => Some(e.to_string()), + }; + (out, err) +} + +/// Texte d'un `*exec.ExitError`. +fn exit_text(s: std::process::ExitStatus) -> String { + if let Some(code) = s.code() { + return format!("exit status {code}"); + } + #[cfg(unix)] + { + use std::os::unix::process::ExitStatusExt; + if let Some(sig) = s.signal() { + return format!("signal: {}", signal_name(sig)); + } + } + s.to_string() +} + +/// Nom d'un signal comme `syscall.Signal.String()`. +#[cfg(unix)] +fn signal_name(sig: i32) -> String { + match sig { + 1 => "hangup".into(), + 2 => "interrupt".into(), + 3 => "quit".into(), + 4 => "illegal instruction".into(), + 6 => "aborted".into(), + 7 => "bus error".into(), + 8 => "floating point exception".into(), + 9 => "killed".into(), + 11 => "segmentation fault".into(), + 13 => "broken pipe".into(), + 15 => "terminated".into(), + n => format!("signal {n}"), + } +} + +/// Le binaire est-il un serveur llama.cpp (garde-fou de la route) ? +pub fn is_llama_server(bin: &str) -> bool { + let base = Path::new(bin) + .file_name() + .map(|b| b.to_string_lossy().to_lowercase()) + .unwrap_or_default(); + base == "llama-server" || base == "llama-server.exe" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse() { + let d = parse_list_devices( + "Available devices:\n CUDA0: NVIDIA GeForce RTX 5060 Ti (15849 MiB, 15579 MiB free)\r\n bruit\n", + ); + assert_eq!(d.len(), 1); + assert_eq!(d[0]["id"], "CUDA0"); + assert_eq!(d[0]["total_mib"], 15849); + } + + #[test] + fn serveur() { + assert!(is_llama_server("/x/LLAMA-SERVER")); + assert!(!is_llama_server("/bin/sh")); + } +} diff --git a/rust/loki-rs/src/backends/job.rs b/rust/loki-rs/src/backends/job.rs new file mode 100644 index 0000000..3928e13 --- /dev/null +++ b/rust/loki-rs/src/backends/job.rs @@ -0,0 +1,414 @@ +//! LE job des moteurs (un seul à la fois) : port de `lcJob` et de sa +//! persistance (`web_llamacpp.go`, `web_llamacpp_job.go`). +//! +//! Quand la façade tient les backends, c'est elle qui détient le job : le +//! sien (binaires précompilés) comme ceux que le Go fait encore tourner +//! (compilation, moteur de l'image, Strata), qui lui rapportent chaque étape +//! par l'API interne (`/internal/facade/v1/build-job/*`). L'entête vit en base +//! (`state/build_job`), les lignes dans `$LOKI_HOME/loki-build.log`. + +use std::io::Write; +use std::path::PathBuf; +use std::sync::LazyLock; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +use regex::Regex; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use tokio::sync::Mutex; + +use crate::gojson; +use crate::store::{BK_STATE, Store}; + +/// `lcMaxLines`. +pub const MAX_LINES: usize = 4000; + +/// Clé de l'entête en base. +pub const STATE_KEY: &str = "build_job"; + +/// Progression throttlée : une écriture au plus toutes les 2 s. +const SAVE_EVERY: Duration = Duration::from_secs(2); + +/// Le job courant (`lcJob`). +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct Job { + pub action: String, + pub phase: String, + pub compiled: i64, + pub running: bool, + pub err: String, + pub started_at: i64, + pub ended_at: i64, + pub old_commit: String, + pub new_commit: String, + pub lines: Vec, + pub base: usize, +} + +/// `lcPersisted` : l'entête sur disque, dans l'ordre des champs du Go. +#[derive(Serialize, Deserialize, Default)] +struct Persisted { + #[serde(default)] + action: String, + #[serde(default)] + phase: String, + #[serde(default)] + compiled: i64, + #[serde(default)] + running: bool, + #[serde(default, rename = "error")] + err: String, + #[serde(default)] + started_at: i64, + #[serde(default)] + ended_at: i64, + #[serde(default, rename = "old")] + old_commit: String, + #[serde(default, rename = "new")] + new_commit: String, +} + +struct State { + cur: Option, + last_save: Option, +} + +/// Le détenteur du job. +pub struct Jobs { + home: PathBuf, + state: Mutex, +} + +fn now() -> i64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_or(0, |d| d.as_secs() as i64) +} + +impl Jobs { + pub fn new(home: PathBuf) -> Self { + Jobs { + home, + state: Mutex::new(State { + cur: None, + last_save: None, + }), + } + } + + /// `lcJobLogPath`. + pub fn log_path(&self) -> PathBuf { + self.home.join("loki-build.log") + } + + /// `lcSaveLine` : une ligne de plus au journal (append). + fn save_line(&self, line: &str) { + if let Ok(mut f) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(self.log_path()) + { + let _ = f.write_all(format!("{line}\n").as_bytes()); + } + } + + /// `lcSave` (appelée sous le verrou, comme au Go). + async fn save(&self, st: &mut State, store: &Store, force: bool) { + let Some(j) = &st.cur else { return }; + if !force && st.last_save.is_some_and(|t| t.elapsed() < SAVE_EVERY) { + return; + } + st.last_save = Some(Instant::now()); + let p = Persisted { + action: j.action.clone(), + phase: j.phase.clone(), + compiled: j.compiled, + running: j.running, + err: j.err.clone(), + started_at: j.started_at, + ended_at: j.ended_at, + old_commit: j.old_commit.clone(), + new_commit: j.new_commit.clone(), + }; + if let Err(e) = store + .put(BK_STATE, STATE_KEY, gojson::marshal(&p).into_bytes()) + .await + { + eprintln!("[moteurs] état du job non enregistré : {e}"); + } + } + + /// `startLcJob` (sans le garde de l'optimiseur, posé par l'appelant). + pub async fn start(&self, store: &Store, action: &str) -> Result<(), String> { + let mut st = self.state.lock().await; + if let Some(j) = &st.cur + && j.running + { + return Err(format!("un job {} est déjà en cours", j.action)); + } + st.cur = Some(Job { + action: action.into(), + running: true, + phase: "démarrage…".into(), + started_at: now(), + ..Job::default() + }); + let _ = std::fs::remove_file(self.log_path()); + self.save(&mut st, store, true).await; + Ok(()) + } + + /// Fin du corps du job (le `defer` de `startLcJob`). + pub async fn end(&self, store: &Store) { + let mut st = self.state.lock().await; + if let Some(j) = &mut st.cur { + j.running = false; + j.ended_at = now(); + } + self.save(&mut st, store, true).await; + } + + /// `lcAppend` : une ligne, et la phase qu'elle annonce. + pub async fn append(&self, store: &Store, line: &str) { + let mut st = self.state.lock().await; + let Some(j) = &mut st.cur else { return }; + j.lines.push(line.into()); + if j.lines.len() > MAX_LINES { + let drop = j.lines.len() - MAX_LINES; + j.lines.drain(..drop); + j.base += drop; + } + if !compiled_file(line).is_empty() { + j.compiled += 1; + j.phase = format!("compilation… {} fichiers", j.compiled); + } else { + let p = phase_label(line); + if !p.is_empty() { + j.phase = p; + } + } + self.save_line(line); + self.save(&mut st, store, false).await; + } + + /// Une ligne marquée (phase, échec, fin) : posée sans troncature, comme + /// au Go, et écrite tout de suite. + async fn mark(&self, store: &Store, line: String, f: impl FnOnce(&mut Job)) { + let mut st = self.state.lock().await; + let Some(j) = &mut st.cur else { return }; + f(j); + j.lines.push(line.clone()); + self.save_line(&line); + self.save(&mut st, store, true).await; + } + + /// `lcPhase`. + pub async fn phase(&self, store: &Store, phase: &str) { + let p = phase.to_string(); + self.mark(store, format!("▶ {phase}"), |j| j.phase = p) + .await; + } + + /// `lcFail`. + pub async fn fail(&self, store: &Store, err: &str) { + let e = err.to_string(); + self.mark(store, format!("✗ {err}"), |j| { + j.err = e; + j.phase = "échec".into(); + }) + .await; + } + + /// `lcDone`. + pub async fn done(&self, store: &Store, msg: &str) { + let m = msg.to_string(); + self.mark(store, format!("✓ {msg}"), |j| j.phase = m).await; + } + + /// `lcCur.OldCommit = …` / `lcCur.NewCommit = …` (sans écriture : la + /// prochaine les emporte). + pub async fn set_commits(&self, old: Option<&str>, new: Option<&str>) { + let mut st = self.state.lock().await; + if let Some(j) = &mut st.cur { + if let Some(o) = old { + j.old_commit = o.into(); + } + if let Some(n) = new { + j.new_commit = n.into(); + } + } + } + + /// `lcJobSnapshot`. + pub async fn snapshot(&self, from: i64, with_lines: bool) -> Value { + let st = self.state.lock().await; + let Some(j) = &st.cur else { + return json!({ "exists": false }); + }; + let mut out = json!({ + "exists": true, + "action": j.action, + "running": j.running, + "phase": j.phase, + "compiled": j.compiled, + "error": j.err, + "started_at": j.started_at, + "ended_at": j.ended_at, + "old": j.old_commit, + "new": j.new_commit, + }); + if with_lines { + let start = (from - j.base as i64).clamp(0, j.lines.len() as i64) as usize; + let rest = &j.lines[start..]; + // `append([]string(nil), …)` d'une tranche vide : nil → null. + out["lines"] = if rest.is_empty() { + Value::Null + } else { + json!(rest) + }; + out["next"] = json!(j.base + j.lines.len()); + } + out + } + + /// Le job court-il ? + pub async fn running(&self) -> bool { + self.state + .lock() + .await + .cur + .as_ref() + .is_some_and(|j| j.running) + } + + /// `lcRestore` : le dernier job connu au démarrage ; un job noté « en + /// cours » est mort avec le processus précédent. + pub async fn restore(&self, store: &Store) { + let Ok(Some(raw)) = store.get(BK_STATE, STATE_KEY).await else { + return; + }; + let Ok(p) = serde_json::from_slice::(&raw) else { + return; + }; + if p.action.is_empty() { + return; + } + let mut j = Job { + action: p.action, + phase: p.phase, + compiled: p.compiled, + running: false, + err: p.err, + started_at: p.started_at, + ended_at: p.ended_at, + old_commit: p.old_commit, + new_commit: p.new_commit, + ..Job::default() + }; + if p.running { + j.err = "interrompu : le service a redémarré pendant l'opération — relancez-la".into(); + j.phase = "interrompu".into(); + j.ended_at = now(); + } + if let Ok(b) = std::fs::read(self.log_path()) { + let s = String::from_utf8_lossy(&b); + let mut lines: Vec = s + .trim_end_matches('\n') + .split('\n') + .map(str::to_string) + .collect(); + if lines.len() == 1 && lines[0].is_empty() { + lines.clear(); + } + if lines.len() > MAX_LINES { + j.base = lines.len() - MAX_LINES; + lines.drain(..j.base); + } + j.lines = lines; + } + if p.running { + j.lines.push( + "✗ interrompu : le service a redémarré (la compilation ne survit pas au redémarrage)" + .into(), + ); + } + let mut st = self.state.lock().await; + if st.cur.is_none() { + st.cur = Some(j); + } + if p.running { + self.save(&mut st, store, true).await; + } + } +} + +/// `truncLabel` : coupé à l'octet, comme le Go ; un caractère coupé devient +/// U+FFFD par octet, comme l'encodeur JSON du Go le rendra. +fn trunc_label(s: &str, n: usize) -> String { + let s = s.trim(); + if s.len() > n { + return format!("{}…", crate::system::go_lossy(&s.as_bytes()[..n - 1])); + } + s.to_string() +} + +/// `phaseLabel`. +pub fn phase_label(line: &str) -> String { + let t = line.trim(); + if let Some(rest) = t.strip_prefix("-- ") { + return format!("configuration… {}", trunc_label(rest, 50)); + } + if t.contains("Linking") || t.contains("Build files have been written") { + return "édition de liens…".into(); + } + String::new() +} + +static RE_COMPILING_CUDA: LazyLock = + LazyLock::new(|| Regex::new(r"Compiling .*?([0-9A-Za-z_.\-]+\.cu)(?-u:\b)").expect("motif")); +static RE_BARE_SOURCE: LazyLock = + LazyLock::new(|| Regex::new(r"^[0-9A-Za-z_.\-]+\.(c|cc|cpp|cxx|cu|cuh)$").expect("motif")); +static RE_BUILDING_OBJ: LazyLock = LazyLock::new(|| { + Regex::new(r"Building (?:C|CXX|CUDA|ASM)[0-9A-Za-z_]* object .*?/([^/]+?)\.o(?:bj)?(?-u:\b)") + .expect("motif") +}); + +/// `compiledFile` : le source qu'une ligne de build annonce, "" sinon. Les +/// classes `\w` et `\b` du Go sont ASCII : on les garde ASCII ici aussi. +pub fn compiled_file(line: &str) -> String { + let t = line.trim(); + if let Some(m) = RE_COMPILING_CUDA.captures(t) { + return m[1].to_string(); + } + if let Some(m) = RE_BUILDING_OBJ.captures(t) { + return m[1].to_string(); + } + if RE_BARE_SOURCE.is_match(t) { + return t.to_string(); + } + String::new() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn labels() { + assert_eq!( + phase_label("-- The C compiler identification is GNU"), + "configuration… The C compiler identification is GNU" + ); + assert_eq!( + phase_label("[100%] Linking CXX executable"), + "édition de liens…" + ); + assert_eq!(phase_label("rien"), ""); + assert_eq!( + compiled_file("[ 45%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml.cpp.o"), + "ggml.cpp" + ); + assert_eq!(compiled_file("foo.cu"), "foo.cu"); + assert_eq!(compiled_file("rien"), ""); + } +} diff --git a/rust/loki-rs/src/backends/mod.rs b/rust/loki-rs/src/backends/mod.rs new file mode 100644 index 0000000..8cdfb4f --- /dev/null +++ b/rust/loki-rs/src/backends/mod.rs @@ -0,0 +1,936 @@ +//! Backends llama.cpp tenus par la façade (lot 22 de la migration, +//! `LOKI_BACKENDS=rust` ; expérimental, le Go reste le défaut) — port de +//! `web_llamacpp.go`, `web_llamacpp_job.go`, `backend_prebuilt.go`, de +//! `handleBackends`, `handleBackendsCustom`, `handleLlamacppUninstallCustom` +//! (`web_api.go`) et `handleBackendDevices` (`web_devices.go`). +//! +//! La façade détient LE job des moteurs ([`job::Jobs`]) : le sien (binaires +//! précompilés) et ceux que le Go fait encore tourner — compilation depuis les +//! sources (install, update, install-custom, relayées au Go), moteur de +//! l'image, Strata — qui lui rapportent chaque étape par l'API interne +//! (`/internal/facade/v1/build-job/*`). + +pub mod devices; +pub mod job; +pub mod prebuilt; +pub mod probe; + +use std::path::{Path, PathBuf}; +use std::process::Stdio; +use std::sync::Arc; + +use http_body_util::{BodyExt, Limited}; +use hyper::body::Incoming; +use hyper::{Method, Request, Response, StatusCode}; +use serde_json::{Value, json}; + +use crate::api::Ctx; +use crate::auth::json as send_json; +use crate::gojson::{self, Kind}; +use crate::paths::{go_clean, go_dir}; +use crate::proxy::Body; +use crate::serve::run::{EnginePaths, same_path}; +use crate::store::{BK_CONFIG, Store}; + +use probe::{Probe, is_dir, is_file}; + +/// Préfixe de l'API interne du job (pour le Go seulement). +pub const INTERNAL_PREFIX: &str = "/internal/facade/v1/build-job/"; + +/// `refuseIfProvided` n'est plus utile ici : les routes de compilation +/// restent au Go, qui répond lui-même. +const USE_REQ_TYPE: &str = r#"struct { Mode string "json:\"mode\"" }"#; +const NAME_REQ_TYPE: &str = r#"struct { Name string "json:\"name\"" }"#; +const BIN_REQ_TYPE: &str = r#"struct { Bin string "json:\"bin\"" }"#; + +/// Les backends tenus par la façade. +pub struct Backends { + pub home: PathBuf, + pub probe: Probe, + pub target: prebuilt::Target, + /// `LOKI_ENGINE_BIN` (moteur livré par l'image), lu au démarrage. + engine_bin_env: std::sync::RwLock, + /// `llamaReleasesAPI`. + pub releases_api: String, + pub jobs: job::Jobs, + pub devices: devices::Devices, + client: reqwest::Client, +} + +impl Backends { + pub fn new(home: PathBuf, engine_bin_env: String) -> Self { + Self::with( + home, + engine_bin_env, + Probe::system(), + prebuilt::RELEASES_API.into(), + ) + } + + /// Pour les tests : machine et API des releases choisies. + pub fn with(home: PathBuf, engine_bin_env: String, probe: Probe, releases_api: String) -> Self { + crate::chat::engine::install_crypto(); + Backends { + jobs: job::Jobs::new(home.clone()), + devices: devices::Devices::new(home.clone()), + home, + probe, + target: prebuilt::Target::current(), + engine_bin_env: std::sync::RwLock::new(engine_bin_env), + releases_api, + client: reqwest::Client::builder().build().unwrap_or_default(), + } + } + + /// Change le moteur livré par l'image (tests). + pub fn set_engine_bin_env(&self, v: &str) { + *self + .engine_bin_env + .write() + .unwrap_or_else(|e| e.into_inner()) = v.to_string(); + } + + fn engine_paths(&self) -> EnginePaths { + EnginePaths { + home: self.home.clone(), + } + } + + fn home_s(&self) -> String { + self.home.to_string_lossy().into_owned() + } + + /// `backendsDir`. + fn backends_dir(&self) -> PathBuf { + self.home.join("backends") + } + + /// `defaultRepoDir`. + fn default_repo_dir(&self) -> PathBuf { + self.backends_dir().join("llama.cpp") + } + + /// `llamacppRepoDir` : la racine du dépôt du BIN, sinon le dépôt canonique. + fn repo_dir(&self, cfg_bin: &str) -> PathBuf { + if !cfg_bin.is_empty() { + let real = crate::paths::eval_symlinks(Path::new(cfg_bin)) + .unwrap_or_else(|| cfg_bin.to_string()); + if let Some(root) = find_repo_root(&real) { + return PathBuf::from(root); + } + } + self.default_repo_dir() + } + + /// `providedEngineBin`. + fn provided_engine_bin(&self) -> String { + let env = self + .engine_bin_env + .read() + .unwrap_or_else(|e| e.into_inner()) + .clone(); + let p = env.trim(); + if p.is_empty() { + return String::new(); + } + if is_file(Path::new(&self.engine_paths().prebuilt_resolve_bin(p))) { + p.to_string() + } else { + String::new() + } + } + + /// `gitOutput` : sortie nettoyée, "" en cas d'échec. + async fn git(&self, repo: &Path, args: &[&str]) -> String { + self.probe + .output_in(Some(repo), "git", args) + .await + .map(|o| String::from_utf8_lossy(&o).trim().to_string()) + .unwrap_or_default() + } + + /// `listBackendBins` : un binaire par dossier de `backends/`. + pub fn list_backend_bins(&self) -> Vec<(String, String)> { + let root = format!("{}/backends", self.home_s()); + let Ok(rd) = std::fs::read_dir(&root) else { + return Vec::new(); + }; + let mut names: Vec = rd + .flatten() + .map(|e| e.file_name().to_string_lossy().into_owned()) + .collect(); + names.sort(); + const SUBPATHS: [&str; 9] = [ + "build/bin/llama-server", + "build-sm120/bin/llama-server", + "build/llama-server", + "bin/llama-server", + "llama-server", + "build/bin/Release/llama-server.exe", + "build/bin/llama-server.exe", + "build/bin/Release/llama-server", + "llama-server.exe", + ]; + let mut out = Vec::new(); + for name in names { + if name.starts_with('.') { + continue; + } + for sp in SUBPATHS { + let p = format!("{root}/{name}/{sp}"); + if is_file(Path::new(&p)) { + out.push((name.clone(), p)); + break; + } + } + } + out + } + + /// `backendDir` : `backends/` sans évasion possible. + fn backend_dir(&self, name: &str) -> Result { + let name = sanitize_backend_name(name); + let root = crate::paths::go_abs(&self.backends_dir().to_string_lossy()) + .ok_or_else(|| "répertoire courant illisible".to_string())?; + let p = crate::paths::go_join(&[&root, &name]); + if !p.starts_with(&format!("{root}/")) { + return Err("nom de backend invalide".into()); + } + Ok(p) + } +} + +/// `findRepoRoot` : le dossier du dépôt llama.cpp au-dessus d'un binaire. +fn find_repo_root(bin: &str) -> Option { + let mut d = go_dir(bin); + for _ in 0..6 { + if is_dir(&Path::new(&d).join(".git")) || is_file(&Path::new(&d).join("CMakeLists.txt")) { + return Some(d); + } + let parent = go_dir(&d); + if parent == d { + break; + } + d = parent; + } + None +} + +/// `llamaServerBin` : le binaire compilé sous `repo`, "" sinon. +fn llama_server_bin(repo: &Path) -> String { + let ext = if cfg!(windows) { ".exe" } else { "" }; + for rel in [ + format!("build/bin/Release/llama-server{ext}"), + format!("build/bin/llama-server{ext}"), + format!("build/Release/llama-server{ext}"), + format!("build/llama-server{ext}"), + ] { + let p = go_clean(&repo.join(&rel).to_string_lossy()); + if is_file(Path::new(&p)) { + return p; + } + } + String::new() +} + +/// `sanitizeBackendName`. +pub fn sanitize_backend_name(name: &str) -> String { + let name = name.trim().to_lowercase(); + let mut b = String::new(); + for r in name.chars() { + match r { + 'a'..='z' | '0'..='9' | '.' | '_' | '-' => b.push(r), + ' ' | '/' | '\\' => b.push('-'), + _ => {} + } + } + let out = b.trim_matches(['.', '-']).to_string(); + if out.is_empty() { + "backend".into() + } else { + out + } +} + +/// `engineOwns` / `engineTagOf`. +fn engine_tag_of(ep: &EnginePaths, bin: &str) -> String { + if !ep.engine_owns(bin) { + return String::new(); + } + crate::paths::base_name(&go_dir(bin)) +} + +/// `strconv.Atoi` : 0 sur erreur de syntaxe, borné sur débordement. +pub fn go_atoi(s: &str) -> i64 { + let digits = s.strip_prefix(['+', '-']).unwrap_or(s); + if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) { + return 0; + } + s.parse().unwrap_or(if s.starts_with('-') { + i64::MIN + } else { + i64::MAX + }) +} + +/// Journal d'un job tenu ici : chaque ligne va au job, dans l'ordre. +pub struct Log<'a> { + pub jobs: &'a job::Jobs, + pub store: &'a Store, +} + +impl Log<'_> { + pub async fn line(&self, s: &str) { + self.jobs.append(self.store, s).await; + } + pub async fn phase(&self, s: &str) { + self.jobs.phase(self.store, s).await; + } +} + +/// Le verrou de l'optimiseur (au Go) : le message s'il tient le moteur. +async fn tune_busy(store: &Store) -> Option { + let v = store + .internal_json(Method::GET, "/internal/v1/tune/guard", None) + .await + .ok()?; + (v.get("busy").and_then(Value::as_bool) == Some(true)).then(|| { + v.get("error") + .and_then(Value::as_str) + .unwrap_or("") + .to_string() + }) +} + +/// Le service moteur : celui de la façade si elle le pilote, sinon celui du +/// Go. `if_active` : seulement s'il tourne. Rend (lancé, erreur). +async fn service(ctx: &Ctx, action: &str, if_active: bool) -> (bool, String) { + if let Some(ctl) = &ctx.engine_ctl { + if if_active && !crate::enginectl::service_is_active(ctx) { + return (false, String::new()); + } + let err = crate::enginectl::service_action(ctx, ctl, action) + .await + .err() + .unwrap_or_default(); + return (true, err); + } + match ctx + .store + .internal_json( + Method::POST, + "/internal/v1/service/action", + Some(&json!({ "action": action, "if_active": if_active })), + ) + .await + { + Ok(v) => ( + v.get("ran").and_then(Value::as_bool).unwrap_or(false), + v.get("error") + .and_then(Value::as_str) + .unwrap_or("") + .to_string(), + ), + Err(e) => (true, e), + } +} + +/// Les routes servies par ce module. +pub fn handles(path: &str) -> bool { + matches!( + path, + "/api/llamacpp" + | "/api/llamacpp/check" + | "/api/llamacpp/prebuilt/check" + | "/api/llamacpp/prebuilt" + | "/api/llamacpp/use" + | "/api/llamacpp/job" + | "/api/llamacpp/uninstall-custom" + | "/api/backends" + | "/api/backends/custom" + | "/api/backends/devices" + ) +} + +/// L'API interne du job ? +pub fn is_internal(path: &str) -> bool { + path.starts_with(INTERNAL_PREFIX) +} + +fn fail(code: StatusCode, e: impl Into) -> Response { + send_json(code, &json!({ "ok": false, "error": e.into() })) +} + +/// `from_go` : remise par le Go (tunnel), déjà authentifiée par lui. +pub async fn serve( + ctx: &Ctx, + b: &Arc, + req: Request, + from_go: bool, +) -> Response { + let (parts, body) = req.into_parts(); + if !from_go && let Err(refus) = ctx.guard(&parts.headers).await { + return *refus; + } + let raw = Limited::new(body, 1 << 20) + .collect() + .await + .map(|b| b.to_bytes().to_vec()) + .unwrap_or_default(); + let store = &ctx.store; + let query = parts.uri.query().unwrap_or(""); + match parts.uri.path() { + "/api/llamacpp" => send_json(StatusCode::OK, &status(b, store).await), + "/api/llamacpp/check" => send_json(StatusCode::OK, &check(b, store).await), + "/api/llamacpp/prebuilt/check" => send_json(StatusCode::OK, &prebuilt_check(b).await), + "/api/llamacpp/prebuilt" => { + if let Some(e) = tune_busy(store).await { + return fail(StatusCode::CONFLICT, e); + } + if let Err(e) = b.jobs.start(store, "prebuilt").await { + return fail(StatusCode::CONFLICT, e); + } + let (b2, ctx2) = (b.clone(), ctx.clone()); + tokio::spawn(async move { + run_prebuilt(&ctx2, &b2).await; + b2.jobs.end(&ctx2.store).await; + }); + send_json(StatusCode::OK, &json!({ "ok": true })) + } + "/api/llamacpp/use" => { + if let Some(e) = tune_busy(store).await { + return send_json( + StatusCode::CONFLICT, + &json!({ "ok": false, "tuning": true, "error": e }), + ); + } + let d = gojson::decode_struct(&raw, USE_REQ_TYPE, &[("mode", Kind::Str)]); + let cfg = store.config().await; + let cfg_bin = cfg.get("BIN").cloned().unwrap_or_default(); + let bin = match d.str("mode").as_str() { + "fast" => prebuilt::server_bin(&b.home), + "opt" => llama_server_bin(&b.repo_dir(&cfg_bin)), + _ => return fail(StatusCode::BAD_REQUEST, "mode inconnu"), + }; + if bin.is_empty() { + return fail(StatusCode::BAD_REQUEST, "cette version n'est pas installée"); + } + if let Err(e) = store.put(BK_CONFIG, "BIN", bin.clone().into_bytes()).await { + return fail(StatusCode::INTERNAL_SERVER_ERROR, e); + } + let _ = service(ctx, "restart", true).await; + send_json(StatusCode::OK, &json!({ "ok": true, "bin": bin })) + } + "/api/llamacpp/job" => { + let from = query_param(query, "from"); + send_json(StatusCode::OK, &b.jobs.snapshot(go_atoi(&from), true).await) + } + "/api/llamacpp/uninstall-custom" => uninstall_custom(b, store, &raw).await, + "/api/backends" => { + let list: Vec = b + .list_backend_bins() + .into_iter() + .map(|(name, path)| json!({ "name": name, "path": path })) + .collect(); + send_json(StatusCode::OK, &json!(list)) + } + "/api/backends/custom" => { + let cfg_bin = store.config().await.get("BIN").cloned().unwrap_or_default(); + let list: Vec = b + .list_backend_bins() + .into_iter() + .filter(|(name, _)| name != "llama.cpp" && name != "llama.cpp-prebuilt") + .map(|(name, path)| { + let in_use = same_path(&path, &cfg_bin); + json!({ "name": name, "path": path, "in_use": in_use }) + }) + .collect(); + send_json(StatusCode::OK, &json!(list)) + } + "/api/backends/devices" => { + let d = gojson::decode_struct(&raw, BIN_REQ_TYPE, &[("bin", Kind::Str)]); + let cfg = store.config().await; + let mut bin = d.str("bin").trim().to_string(); + if bin.is_empty() { + bin = cfg.get("BIN").cloned().unwrap_or_default(); + } + let bin = b.engine_paths().prebuilt_resolve_bin(&bin); + if bin.is_empty() || !is_file(Path::new(&bin)) { + return send_json( + StatusCode::OK, + &json!({ "ok": false, "error": "moteur introuvable — choisissez d'abord un moteur" }), + ); + } + if !devices::is_llama_server(&bin) { + return fail( + StatusCode::BAD_REQUEST, + "ce chemin n'est pas un llama-server", + ); + } + let cvd = cfg.get("CUDA_VISIBLE_DEVICES").cloned().unwrap_or_default(); + send_json(StatusCode::OK, &b.devices.list(&b.probe, &bin, &cvd).await) + } + _ => fail(StatusCode::NOT_FOUND, "route inconnue"), + } +} + +/// Valeur d'un paramètre de requête (dernière occurrence ignorée : la +/// première, comme `Query().Get`). +fn query_param(query: &str, key: &str) -> String { + url::form_urlencoded::parse(query.as_bytes()) + .find(|(k, _)| k == key) + .map(|(_, v)| v.into_owned()) + .unwrap_or_default() +} + +/// `handleLlamacpp` : le statut complet. +pub async fn status(b: &Backends, store: &Store) -> Value { + let cfg = store.config().await; + let cfg_bin = cfg.get("BIN").cloned().unwrap_or_default(); + let repo = b.repo_dir(&cfg_bin); + let installed = is_dir(&repo.join(".git")); + let mut out = json!({ + "repo": repo.to_string_lossy(), + "installed": installed, + }); + if installed { + let branch = b.git(&repo, &["rev-parse", "--abbrev-ref", "HEAD"]).await; + out["commit"] = json!(b.git(&repo, &["rev-parse", "--short", "HEAD"]).await); + out["commit_date"] = json!(b.git(&repo, &["log", "-1", "--format=%ci"]).await); + out["commit_msg"] = json!(b.git(&repo, &["log", "-1", "--format=%s"]).await); + if !branch.is_empty() && branch != "HEAD" { + let behind = b + .git( + &repo, + &["rev-list", "--count", &format!("HEAD..origin/{branch}")], + ) + .await; + if !behind.is_empty() { + out["behind"] = json!(behind.parse::().unwrap_or(0)); + } + } + out["branch"] = json!(branch); + } + let bin = llama_server_bin(&repo); + let ep = b.engine_paths(); + out["bin"] = json!(bin); + out["config_bin"] = json!(cfg_bin); + out["in_use"] = json!(!bin.is_empty() && same_path(&bin, &cfg_bin)); + let provided = b.provided_engine_bin(); + out["provided"] = json!(!provided.is_empty()); + out["provided_bin"] = json!(provided); + out["engine"] = json!({ + "dir": b.home.join("engine").to_string_lossy(), + "in_use": ep.engine_owns(&cfg_bin), + "tag": engine_tag_of(&ep, &cfg_bin), + }); + let plan = b.probe.detect_build_plan().await; + out["plan"] = json!({ "backend": plan.backend, "arch": plan.cuda_arch, "jobs": plan.jobs }); + let (pb_tag, _) = prebuilt::version(&b.home); + let pb_bin = prebuilt::server_bin(&b.home); + out["prebuilt"] = json!({ + "tag": pb_tag, + "bin": pb_bin, + "dir": prebuilt::dir(&b.home).to_string_lossy(), + "in_use": !pb_bin.is_empty() && ep.prebuilt_owns(&cfg_bin), + }); + out["backends_dir"] = json!(b.backends_dir().to_string_lossy()); + out["reco"] = prebuilt::recommended_mode(plan.backend, b.target.os); + out["job"] = b.jobs.snapshot(0, false).await; + out +} + +/// `runStep` (sans terminal interactif) : la commande, sorties sur celles de +/// la façade ; l'erreur au format d'`exec`. +async fn run_step(probe: &Probe, dir: &Path, name: &str, args: &[&str]) -> Result<(), String> { + let Some(bin) = probe.look_path(name) else { + return Err(format!( + "exec: \"{name}\": executable file not found in $PATH" + )); + }; + let status = tokio::process::Command::new(&bin) + .args(args) + .current_dir(dir) + .stdin(Stdio::null()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .status() + .await + .map_err(|e| crate::paths::os_err("fork/exec", &bin.to_string_lossy(), &e))?; + match status.code() { + Some(0) => Ok(()), + Some(c) => Err(format!("exit status {c}")), + None => Err(status.to_string()), + } +} + +/// `handleLlamacppCheck` : git fetch, puis le retard sur origin. +async fn check(b: &Backends, store: &Store) -> Value { + let cfg_bin = store.config().await.get("BIN").cloned().unwrap_or_default(); + let repo = b.repo_dir(&cfg_bin); + if !is_dir(&repo.join(".git")) { + return json!({ "ok": false, "error": "llama.cpp n'est pas installé" }); + } + let mut branch = b.git(&repo, &["rev-parse", "--abbrev-ref", "HEAD"]).await; + if branch.is_empty() || branch == "HEAD" { + branch = "master".into(); + } + if let Err(e) = run_step(&b.probe, &repo, "git", &["fetch", "origin", "--quiet"]).await { + return json!({ "ok": false, "error": format!("git fetch a échoué : {e}") }); + } + let origin = format!("origin/{branch}"); + let behind_s = b + .git(&repo, &["rev-list", "--count", &format!("HEAD..{origin}")]) + .await; + let behind = if behind_s.is_empty() { + 0 + } else { + behind_s.parse::().unwrap_or(0) + }; + let has_binary = !llama_server_bin(&repo).is_empty(); + json!({ + "ok": true, + "behind": behind, + "local": b.git(&repo, &["rev-parse", "--short", "HEAD"]).await, + "remote": b.git(&repo, &["rev-parse", "--short", &origin]).await, + "remote_date": b.git(&repo, &["log", "-1", "--format=%ci", &origin]).await, + "remote_msg": b.git(&repo, &["log", "-1", "--format=%s", &origin]).await, + "branch": branch, + "has_binary": has_binary, + "needs_rebuild": behind > 0 || !has_binary, + }) +} + +/// La dernière release officielle (`fetchLlamaLatest`). +async fn fetch_latest(b: &Backends) -> Result<(String, Vec), String> { + prebuilt::fetch_latest(&b.client, &b.releases_api).await +} + +/// `handleLlamacppPrebuiltCheck`. +async fn prebuilt_check(b: &Backends) -> Value { + let (tag, assets) = match fetch_latest(b).await { + Ok(r) => r, + Err(e) => return json!({ "ok": false, "error": e }), + }; + let pick = match prebuilt::pick(&assets, &b.probe, b.target).await { + Ok(p) => p, + Err(e) => return json!({ "ok": false, "error": e }), + }; + let (cur, _) = prebuilt::version(&b.home); + let update = cur != tag || prebuilt::server_bin(&b.home).is_empty(); + json!({ + "ok": true, + "latest": tag, + "current": cur, + "variant": pick.label, + "size_mb": pick.main.size / 1_000_000, + "update": update, + }) +} + +/// `lcRunPrebuilt` : installe, pointe BIN, service arrêté pendant le +/// remplacement puis relancé. +async fn run_prebuilt(ctx: &Ctx, b: &Backends) { + let log = Log { + jobs: &b.jobs, + store: &ctx.store, + }; + let (svc_was_up, err) = if ctx.engine_ctl.is_some() { + if crate::enginectl::service_is_active(ctx) { + log.phase("arrêt du service le temps de l'installation…") + .await; + service(ctx, "stop", false).await + } else { + (false, String::new()) + } + } else { + // Côté Go, « arrête-le s'il tourne » dit aussi s'il tournait. + let r = service(ctx, "stop", true).await; + if r.0 { + log.phase("arrêt du service le temps de l'installation…") + .await; + } + r + }; + if svc_was_up && !err.is_empty() { + log.line(&format!("[warn] impossible d'arrêter le service : {err}")) + .await; + } + let mut res = install(b, &log).await; + if let Ok(bin) = &res { + match ctx + .store + .put(BK_CONFIG, "BIN", bin.clone().into_bytes()) + .await + { + Err(e) => { + res = Err(format!( + "binaires installés mais échec d'écriture de BIN : {e}" + )) + } + Ok(()) => log.line("BIN mis à jour").await, + } + } + if svc_was_up { + log.phase("redémarrage du service…").await; + let (_, e) = service(ctx, "start", false).await; + if !e.is_empty() { + log.line(&format!("[warn] redémarrage du service échoué : {e}")) + .await; + } + } + match res { + Err(e) => b.jobs.fail(&ctx.store, &e).await, + Ok(_) => { + let (tag, _) = prebuilt::version(&b.home); + b.jobs + .done( + &ctx.store, + &format!("binaires précompilés installés ({tag})"), + ) + .await; + } + } +} + +/// `prebuiltInstall` : télécharge et installe la dernière release ; rend le +/// chemin du binaire. +pub async fn install(b: &Backends, log: &Log<'_>) -> Result { + log.phase("récupération de la dernière release llama.cpp…") + .await; + let (tag, assets) = fetch_latest(b) + .await + .map_err(|e| format!("impossible d'interroger les releases llama.cpp : {e}"))?; + let (cur_tag, cur_cuda) = prebuilt::version(&b.home); + let pick = prebuilt::pick(&assets, &b.probe, b.target).await?; + log.line(&format!("release {tag} — variant retenu : {}", pick.label)) + .await; + let cur = prebuilt::server_bin(&b.home); + if cur_tag == tag && prebuilt::version_format(&b.home) == prebuilt::FORMAT && !cur.is_empty() { + log.line(&format!("déjà à jour ({tag})")).await; + prune(b, &cur, log).await; + return Ok(cur); + } + let dir = prebuilt::dir(&b.home); + std::fs::create_dir_all(&dir) + .map_err(|e| crate::paths::os_err("mkdir", &dir.to_string_lossy(), &e))?; + let mut cudart = pick.cudart.clone(); + if cudart.is_some() && !cudart_present(&dir).is_empty() && cur_cuda == pick.cuda_ver { + log.line(&format!( + "cudart {} déjà présent — téléchargement évité", + pick.cuda_ver + )) + .await; + cudart = None; + } + for a in [Some(pick.main.clone()), cudart].into_iter().flatten() { + log.phase(&format!( + "téléchargement de {} ({} Mo)…", + a.name, + a.size / 1_000_000 + )) + .await; + let tmp = dir.join(format!("{}.part", a.name)); + if let Err(e) = download(b, &a, &tmp, log).await { + let _ = std::fs::remove_file(&tmp); + return Err(format!("téléchargement de {} : {e}", a.name)); + } + log.phase(&format!("extraction de {}…", a.name)).await; + let (t2, d2) = (tmp.clone(), dir.clone()); + let ex = tokio::task::spawn_blocking(move || prebuilt::extract(&t2, &d2)) + .await + .unwrap_or_else(|e| Err(e.to_string())); + if let Err(e) = ex { + let _ = std::fs::remove_file(&tmp); + return Err(format!("extraction de {} : {e}", a.name)); + } + let _ = std::fs::remove_file(&tmp); + } + let vpath = dir.join("VERSION"); + std::fs::write( + &vpath, + format!("{tag} {} {}\n", pick.cuda_ver, prebuilt::FORMAT), + ) + .map_err(|e| crate::paths::os_err("open", &vpath.to_string_lossy(), &e))?; + let bin = prebuilt::server_bin(&b.home); + if bin.is_empty() { + return Err(format!( + "archives extraites mais llama-server introuvable sous {}", + dir.to_string_lossy() + )); + } + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let _ = std::fs::set_permissions(&bin, std::fs::Permissions::from_mode(0o755)); + } + prune(b, &bin, log).await; + log.line(&format!("binaire installé : {bin} (release {tag})")) + .await; + Ok(bin) +} + +/// Le téléchargement d'un asset, sa progression au journal du job au fil de +/// l'eau et dans l'ordre. +async fn download( + b: &Backends, + a: &prebuilt::Asset, + dest: &Path, + log: &Log<'_>, +) -> Result<(), String> { + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + let dl = async move { + let mut logf = |s: String| { + let _ = tx.send(s); + }; + prebuilt::download(&b.client, &a.url, dest, a.size, &mut logf).await + }; + let pump = async { + while let Some(s) = rx.recv().await { + log.line(&s).await; + } + }; + let (res, ()) = tokio::join!(dl, pump); + res +} + +/// cudart déjà extrait (`filepath.Glob(dir/**/cudart64*.dll)` puis +/// `dir/cudart64*.dll` : `**` vaut `*` pour Glob). +fn cudart_present(dir: &Path) -> Vec { + let is_dll = |n: &str| n.starts_with("cudart64") && n.ends_with(".dll"); + let mut found = Vec::new(); + if let Ok(rd) = std::fs::read_dir(dir) { + for e in rd.flatten() { + if let Ok(sub) = std::fs::read_dir(e.path()) { + for s in sub.flatten() { + if is_dll(&s.file_name().to_string_lossy()) { + found.push(s.path()); + } + } + } + } + } + if found.is_empty() + && let Ok(rd) = std::fs::read_dir(dir) + { + for e in rd.flatten() { + if is_dll(&e.file_name().to_string_lossy()) { + found.push(e.path()); + } + } + } + found +} + +/// `prebuiltPrune`, ses lignes au job. +async fn prune(b: &Backends, keep: &str, log: &Log<'_>) { + let mut lines = Vec::new(); + prebuilt::prune(&b.home, keep, &mut |s| lines.push(s)); + for l in lines { + log.line(&l).await; + } +} + +/// `handleLlamacppUninstallCustom`. +async fn uninstall_custom(b: &Backends, store: &Store, raw: &[u8]) -> Response { + let d = gojson::decode_struct(raw, NAME_REQ_TYPE, &[("name", Kind::Str)]); + let name = sanitize_backend_name(&d.str("name")); + if name.is_empty() { + return fail(StatusCode::BAD_REQUEST, "nom requis"); + } + if name == "llama.cpp" || name == "llama.cpp-prebuilt" { + return fail( + StatusCode::BAD_REQUEST, + "ce moteur se gère depuis les cartes ⚡ / 🔧", + ); + } + let dir = match b.backend_dir(&name) { + Ok(d) => d, + Err(e) => return fail(StatusCode::BAD_REQUEST, e), + }; + if !is_dir(Path::new(&dir)) { + return fail(StatusCode::NOT_FOUND, "backend introuvable"); + } + let cfg_bin = store.config().await.get("BIN").cloned().unwrap_or_default(); + for (n, p) in b.list_backend_bins() { + if n == name && same_path(&p, &cfg_bin) { + return fail( + StatusCode::CONFLICT, + "backend utilisé par le modèle actif — bascule d'abord ce modèle sur un autre moteur", + ); + } + } + if let Err(e) = std::fs::remove_dir_all(&dir) { + return fail( + StatusCode::INTERNAL_SERVER_ERROR, + crate::paths::os_err("unlinkat", &dir, &e), + ); + } + send_json(StatusCode::OK, &json!({ "ok": true })) +} + +/// L'API interne du job : le Go y rapporte les étapes de ses jobs. +pub async fn serve_internal(ctx: &Ctx, b: &Backends, req: Request) -> Response { + let (parts, body) = req.into_parts(); + let raw = Limited::new(body, 1 << 20) + .collect() + .await + .map(|b| b.to_bytes().to_vec()) + .unwrap_or_default(); + let v: Value = serde_json::from_slice(&raw).unwrap_or(Value::Null); + let s = |k: &str| v.get(k).and_then(Value::as_str).unwrap_or("").to_string(); + let store = &ctx.store; + let op = parts.uri.path().trim_start_matches(INTERNAL_PREFIX); + if op == "snapshot" { + let q = parts.uri.query().unwrap_or(""); + let from = go_atoi(&query_param(q, "from")); + let lines = query_param(q, "lines") == "1"; + return send_json(StatusCode::OK, &b.jobs.snapshot(from, lines).await); + } + if parts.method != Method::POST { + return fail(StatusCode::METHOD_NOT_ALLOWED, "POST attendu"); + } + match op { + "start" => { + if let Err(e) = b.jobs.start(store, &s("action")).await { + return fail(StatusCode::CONFLICT, e); + } + return send_json(StatusCode::OK, &json!({ "ok": true })); + } + "line" => b.jobs.append(store, &s("line")).await, + "phase" => b.jobs.phase(store, &s("phase")).await, + "fail" => b.jobs.fail(store, &s("error")).await, + "done" => b.jobs.done(store, &s("msg")).await, + "end" => b.jobs.end(store).await, + "commits" => { + let old = v.get("old").and_then(Value::as_str); + let new = v.get("new").and_then(Value::as_str); + b.jobs.set_commits(old, new).await; + } + _ => return fail(StatusCode::NOT_FOUND, "route inconnue"), + } + send_json(StatusCode::OK, &json!({ "ok": true })) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanitize() { + assert_eq!(sanitize_backend_name(" Mon Fork/Test "), "mon-fork-test"); + assert_eq!(sanitize_backend_name("../.."), "backend"); + assert_eq!(sanitize_backend_name(""), "backend"); + assert_eq!(sanitize_backend_name("é-x."), "x"); + } + + #[test] + fn atoi() { + assert_eq!(go_atoi("12"), 12); + assert_eq!(go_atoi("-3"), -3); + assert_eq!(go_atoi("+4"), 4); + assert_eq!(go_atoi("x"), 0); + assert_eq!(go_atoi(""), 0); + assert_eq!(go_atoi("99999999999999999999"), i64::MAX); + } +} diff --git a/rust/loki-rs/src/backends/prebuilt.rs b/rust/loki-rs/src/backends/prebuilt.rs new file mode 100644 index 0000000..996cdbd --- /dev/null +++ b/rust/loki-rs/src/backends/prebuilt.rs @@ -0,0 +1,559 @@ +//! Binaires précompilés officiels de llama.cpp : port de `backend_prebuilt.go` +//! (dernière release, choix de l'asset, téléchargement, extraction avec les +//! liens, marqueur VERSION, ménage des anciennes versions). + +use std::io::Read; +use std::path::{Path, PathBuf}; +use std::sync::LazyLock; + +use futures_util::StreamExt; +use regex::Regex; +use serde::Deserialize; +use serde_json::Value; + +use crate::gojson::Kind; +use tokio::io::AsyncWriteExt; + +use super::probe::Probe; + +/// `llamaReleasesAPI`. +pub const RELEASES_API: &str = "https://api.github.com/repos/ggml-org/llama.cpp/releases/latest"; + +/// La struct anonyme que `fetchLlamaLatest` décode. +const RELEASE_TYPE: &str = + r#"struct { TagName string "json:\"tag_name\""; Assets []loki.ghAsset "json:\"assets\"" }"#; + +/// `prebuiltFormat` : extraction qui recrée les liens des archives. +pub const FORMAT: &str = "fmt2"; + +/// `ghAsset`. +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] +pub struct Asset { + #[serde(default)] + pub name: String, + #[serde(default, rename = "browser_download_url")] + pub url: String, + #[serde(default)] + pub size: i64, +} + +/// `prebuiltDir`. +pub fn dir(home: &Path) -> PathBuf { + home.join("backends").join("llama.cpp-prebuilt") +} + +fn version_fields(home: &Path) -> Vec { + std::fs::read_to_string(dir(home).join("VERSION")) + .map(|s| s.split_whitespace().map(str::to_string).collect()) + .unwrap_or_default() +} + +/// `prebuiltVersion` : (tag, version CUDA). La version CUDA est vide hors +/// CUDA Windows : « b300 fmt2 » n'a alors que deux champs, le format en +/// second. +pub fn version(home: &Path) -> (String, String) { + let f = version_fields(home); + let cuda = f + .get(1) + .filter(|c| !c.starts_with("fmt")) + .cloned() + .unwrap_or_default(); + (f.first().cloned().unwrap_or_default(), cuda) +} + +/// `prebuiltVersionFormat` : le dernier champ du marqueur, s'il en est un. +pub fn version_format(home: &Path) -> String { + let f = version_fields(home); + match f.last() { + Some(last) if f.len() > 1 && last.starts_with("fmt") => last.clone(), + _ => String::new(), + } +} + +/// `prebuiltServerBin`. +pub fn server_bin(home: &Path) -> String { + crate::serve::run::EnginePaths { + home: home.to_path_buf(), + } + .prebuilt_server_bin() +} + +/// `prebuiltPrune` : les extractions d'autres releases supprimées. +pub fn prune(home: &Path, keep: &str, logf: &mut dyn FnMut(String)) { + let keep_dir = if keep.is_empty() { + String::new() + } else { + crate::paths::go_clean(keep) + }; + let d = dir(home); + let Ok(rd) = std::fs::read_dir(&d) else { + return; + }; + let mut names: Vec = rd + .flatten() + .filter(|e| e.file_type().is_ok_and(|t| t.is_dir())) + .map(|e| e.file_name().to_string_lossy().into_owned()) + .filter(|n| n.starts_with("llama-b")) + .collect(); + names.sort(); + for name in names { + let p = d.join(&name); + let ps = crate::paths::go_clean(&p.to_string_lossy()); + if !keep_dir.is_empty() && keep_dir.starts_with(&format!("{ps}/")) { + continue; + } + if std::fs::remove_dir_all(&p).is_ok() { + logf(format!("ancienne version supprimée : {name}")); + } + } +} + +/// `fetchLlamaLatest` : (tag, assets) de la dernière release. +pub async fn fetch_latest( + client: &reqwest::Client, + url: &str, +) -> Result<(String, Vec), String> { + let resp = client + .get(url) + .header("Accept", "application/vnd.github+json") + .header("User-Agent", "Go-http-client/1.1") + .timeout(std::time::Duration::from_secs(30)) + .send() + .await + .map_err(|e| e.to_string())?; + if resp.status().as_u16() != 200 { + return Err(format!("GitHub API : HTTP {}", resp.status().as_u16())); + } + let body = resp.bytes().await.map_err(|e| e.to_string())?; + // Erreurs de décodage au mot près du Go (`json.NewDecoder(…).Decode`). + let d = crate::gojson::decode_struct( + &body, + RELEASE_TYPE, + &[("tag_name", Kind::Str), ("assets", Kind::Any)], + ); + if let Some(e) = d.err { + return Err(e); + } + let assets: Vec = match d.fields.get("assets") { + Some(Value::Null) | None => Vec::new(), + Some(v) => serde_json::from_value(v.clone()).map_err(|e| e.to_string())?, + }; + let tag = d.str("tag_name"); + if tag.is_empty() { + return Err("release invalide (tag vide)".into()); + } + Ok((tag, assets)) +} + +/// `assetMatch` : les assets dont le nom contient TOUS les fragments. +pub fn asset_match(assets: &[Asset], frags: &[&str]) -> Vec { + assets + .iter() + .filter(|a| frags.iter().all(|f| a.name.contains(f))) + .cloned() + .collect() +} + +static RE_CUDA_ASSET_VER: LazyLock = + LazyLock::new(|| Regex::new(r"cuda-([0-9]+\.[0-9]+)").expect("motif")); + +/// Le choix de `pickPrebuilt`. +#[derive(Clone, Debug, PartialEq)] +pub struct Pick { + pub main: Asset, + pub cudart: Option, + pub label: String, + pub cuda_ver: String, +} + +/// Système et architecture visés (`runtime.GOOS`, `runtime.GOARCH`). +#[derive(Clone, Copy, Debug)] +pub struct Target { + pub os: &'static str, + pub arm64: bool, +} + +impl Target { + pub fn current() -> Self { + Target { + os: if cfg!(windows) { + "windows" + } else if cfg!(target_os = "macos") { + "darwin" + } else { + "linux" + }, + arm64: cfg!(target_arch = "aarch64"), + } + } +} + +/// `pickPrebuilt` : l'asset principal (+ cudart pour CUDA Windows) adapté à +/// la machine, et un libellé lisible du variant. +pub async fn pick(assets: &[Asset], probe: &Probe, t: Target) -> Result { + let first = |l: Vec| l.into_iter().next(); + let mut cudart = None; + let mut cuda_ver = String::new(); + let (main, label): (Option, String) = match t.os { + "windows" => 'w: { + if t.arm64 { + break 'w ( + first(asset_match(assets, &["llama-", "bin-win-cpu-arm64"])), + "CPU (Windows arm64)".into(), + ); + } + if probe.has_nvidia_gpu().await { + let cand: Vec = + asset_match(assets, &["llama-", "bin-win-cuda-", "-x64.zip"]) + .into_iter() + .filter(|a| !a.name.starts_with("cudart")) + .collect(); + let max_v = probe.driver_cuda_version().await; + let mut best: Option = None; + let mut best_v = 0.0; + for a in cand { + let Some(m) = RE_CUDA_ASSET_VER.captures(&a.name) else { + continue; + }; + let v: f64 = m[1].parse().unwrap_or(0.0); + let ok = (max_v == 0.0 && (best.is_none() || v < best_v)) + || (max_v > 0.0 && v <= max_v && v > best_v); + if ok { + cuda_ver = m[1].to_string(); + best = Some(a); + best_v = v; + } + } + if let Some(b) = best { + cudart = first(asset_match( + assets, + &["cudart-", &format!("win-cuda-{cuda_ver}")], + )); + break 'w (Some(b), format!("CUDA {cuda_ver} (Windows x64)")); + } + } + if let Some(a) = first(asset_match(assets, &["llama-", "bin-win-vulkan-x64"])) { + break 'w (Some(a), "Vulkan (Windows x64)".into()); + } + ( + first(asset_match(assets, &["llama-", "bin-win-cpu-x64"])), + "CPU (Windows x64)".into(), + ) + } + "darwin" => { + let arch = if t.arm64 { "arm64" } else { "x64" }; + ( + first(asset_match( + assets, + &["llama-", &format!("bin-macos-{arch}")], + )), + format!("Metal (macOS {arch})"), + ) + } + _ => 'l: { + let arch = if t.arm64 { "arm64" } else { "x64" }; + if (probe.has_tool("hipcc") || super::probe::is_dir(&probe.sys("/opt/rocm"))) + && let Some(a) = first(asset_match(assets, &["llama-", "bin-ubuntu-rocm-", arch])) + { + break 'l (Some(a), format!("ROCm (Linux {arch})")); + } + let nvidia = probe.has_nvidia_gpu().await; + if (nvidia || probe.has_tool("vulkaninfo")) + && let Some(a) = first(asset_match( + assets, + &["llama-", &format!("bin-ubuntu-vulkan-{arch}")], + )) + { + let mut label = format!("Vulkan (Linux {arch})"); + // Le Go relance nvidia-smi pour ce suffixe : même résultat. + if probe.has_nvidia_gpu().await { + label.push_str(" — pas de build CUDA officiel Linux ; compile localement pour du CUDA natif"); + } + break 'l (Some(a), label); + } + ( + first(asset_match( + assets, + &["llama-", &format!("bin-ubuntu-{arch}.tar.gz")], + )), + format!("CPU (Linux {arch})"), + ) + } + }; + match main { + Some(main) => Ok(Pick { + main, + cudart, + label, + cuda_ver, + }), + None => { + Err("aucun binaire précompilé adapté à cette machine dans la release officielle".into()) + } + } +} + +/// `recommendedMode` : {mode, why}. +pub fn recommended_mode(backend: &str, os: &str) -> serde_json::Value { + if os == "linux" && backend == "cuda" { + return serde_json::json!({ + "mode": "opt", + "why": "seule voie vers du CUDA natif : llama.cpp ne publie aucun binaire CUDA pour Linux, le précompilé ne donnerait que du Vulkan. Compte plusieurs minutes de compilation.", + }); + } + serde_json::json!({ "mode": "fast", "why": "" }) +} + +/// `downloadWithProgress` : progression journalisée par tranches de ~25 Mo. +pub async fn download( + client: &reqwest::Client, + url: &str, + dest: &Path, + total: i64, + logf: &mut (dyn FnMut(String) + Send), +) -> Result<(), String> { + let resp = client + .get(url) + .header("User-Agent", "Go-http-client/1.1") + .send() + .await + .map_err(|e| e.to_string())?; + if resp.status().as_u16() != 200 { + return Err(format!("HTTP {}", resp.status().as_u16())); + } + let total = if total <= 0 { + resp.content_length().map_or(-1, |n| n as i64) + } else { + total + }; + let mut f = tokio::fs::File::create(dest) + .await + .map_err(|e| crate::paths::os_err("open", &dest.to_string_lossy(), &e))?; + let (mut done, mut last_log) = (0i64, 0i64); + let mut stream = resp.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| e.to_string())?; + f.write_all(&chunk) + .await + .map_err(|e| crate::paths::os_err("write", &dest.to_string_lossy(), &e))?; + done += chunk.len() as i64; + if done - last_log >= 25 << 20 { + last_log = done; + if total > 0 { + logf(format!( + "⬇ {} / {} Mo ({}%)", + done / 1_000_000, + total / 1_000_000, + done * 100 / total + )); + } else { + logf(format!("⬇ {} Mo", done / 1_000_000)); + } + } + } + f.flush() + .await + .map_err(|e| crate::paths::os_err("write", &dest.to_string_lossy(), &e))?; + Ok(()) +} + +/// `extractArchive` : .zip ou .tar.gz dans `dir`, sans entrée qui +/// s'échapperait du dossier ; les liens des tar posés après coup. +pub fn extract(path: &Path, dir: &Path) -> Result<(), String> { + let dir_s = dir.to_string_lossy().into_owned(); + let safe = |name: &str| -> Result { + let p = crate::paths::go_join(&[&dir_s, name]); + let rel = go_rel(&crate::paths::go_clean(&dir_s), &p); + match rel { + Some(r) if !r.starts_with("..") => Ok(PathBuf::from(p)), + _ => Err(format!("entrée d'archive suspecte : {name}")), + } + }; + let ps = path.to_string_lossy(); + if ps.ends_with(".zip") || ps.ends_with(".zip.part") { + let f = std::fs::File::open(path).map_err(|e| crate::paths::os_err("open", &ps, &e))?; + let mut zr = zip::ZipArchive::new(f).map_err(|e| e.to_string())?; + for i in 0..zr.len() { + let mut e = zr.by_index(i).map_err(|e| e.to_string())?; + let name = e.name().to_string(); + let p = safe(&name)?; + if e.is_dir() { + mkdir_all(&p)?; + continue; + } + if let Some(parent) = p.parent() { + mkdir_all(parent)?; + } + let mut w = std::fs::File::create(&p) + .map_err(|err| crate::paths::os_err("open", &p.to_string_lossy(), &err))?; + std::io::copy(&mut e, &mut w).map_err(|err| err.to_string())?; + } + return Ok(()); + } + let f = std::fs::File::open(path).map_err(|e| crate::paths::os_err("open", &ps, &e))?; + let gz = flate2::read::GzDecoder::new(f); + let mut tr = tar::Archive::new(gz); + let mut links: Vec<(PathBuf, String)> = Vec::new(); + let entries = tr.entries().map_err(|e| e.to_string())?; + for entry in entries { + let mut entry = entry.map_err(|e| e.to_string())?; + let name = String::from_utf8_lossy(&entry.path_bytes()).into_owned(); + let p = safe(&name)?; + let kind = entry.header().entry_type(); + if kind.is_dir() { + mkdir_all(&p)?; + } else if kind.is_file() { + if let Some(parent) = p.parent() { + mkdir_all(parent)?; + } + let mut w = std::fs::File::create(&p) + .map_err(|err| crate::paths::os_err("open", &p.to_string_lossy(), &err))?; + let mut buf = Vec::new(); + entry.read_to_end(&mut buf).map_err(|e| e.to_string())?; + std::io::Write::write_all(&mut w, &buf).map_err(|e| e.to_string())?; + drop(w); + #[cfg(unix)] + if let Ok(mode) = entry.header().mode() { + use std::os::unix::fs::PermissionsExt; + let _ = std::fs::set_permissions(&p, std::fs::Permissions::from_mode(mode & 0o777)); + } + } else if kind.is_symlink() || kind.is_hard_link() { + let target = entry + .link_name_bytes() + .map(|b| String::from_utf8_lossy(&b).into_owned()) + .unwrap_or_default(); + let target = if kind.is_hard_link() { + safe(&target)?.to_string_lossy().into_owned() + } else { + target + }; + links.push((p, target)); + } + } + apply_links(&links) +} + +fn mkdir_all(p: &Path) -> Result<(), String> { + std::fs::create_dir_all(p).map_err(|e| crate::paths::os_err("mkdir", &p.to_string_lossy(), &e)) +} + +/// `applyLinks` : liens symboliques, ou copie de la cible quand le système +/// les refuse. +fn apply_links(links: &[(PathBuf, String)]) -> Result<(), String> { + for (path, target) in links { + let _ = std::fs::remove_file(path); + if let Some(parent) = path.parent() { + mkdir_all(parent)?; + } + #[cfg(unix)] + if std::os::unix::fs::symlink(target, path).is_ok() { + continue; + } + let src = if Path::new(target).is_absolute() { + PathBuf::from(target) + } else { + path.parent().unwrap_or(Path::new(".")).join(target) + }; + let Ok(data) = std::fs::read(&src) else { + continue; + }; + std::fs::write(path, data) + .map_err(|e| crate::paths::os_err("open", &path.to_string_lossy(), &e))?; + } + Ok(()) +} + +/// `filepath.Rel` pour deux chemins nettoyés, `base` absolu : `None` si +/// `targ` n'est pas exprimable relativement (l'un absolu, l'autre non). +fn go_rel(base: &str, targ: &str) -> Option { + if base.starts_with('/') != targ.starts_with('/') { + return None; + } + if base == targ { + return Some(".".into()); + } + let b: Vec<&str> = base.split('/').filter(|s| !s.is_empty()).collect(); + let t: Vec<&str> = targ.split('/').filter(|s| !s.is_empty()).collect(); + let common = b.iter().zip(&t).take_while(|(x, y)| x == y).count(); + let mut parts: Vec<&str> = vec![".."; b.len() - common]; + parts.extend(&t[common..]); + Some(parts.join("/")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rel() { + assert_eq!(go_rel("/a/b", "/a/b/c").as_deref(), Some("c")); + assert_eq!(go_rel("/a/b", "/a/c").as_deref(), Some("../c")); + assert_eq!(go_rel("/a/b", "/a/b").as_deref(), Some(".")); + assert_eq!(go_rel("/a/b", "/a/b..x").as_deref(), Some("../b..x")); + } + + #[test] + fn marqueur_version() { + let tmp = tempfile::tempdir().unwrap(); + let d = dir(tmp.path()); + std::fs::create_dir_all(&d).unwrap(); + for (content, tag, cuda, fmt) in [ + ("b300 fmt2\n", "b300", "", "fmt2"), + ("b300 12.4 fmt2\n", "b300", "12.4", "fmt2"), + ("b300 12.4\n", "b300", "12.4", ""), + ("b300 \n", "b300", "", ""), + ("fmt2\n", "fmt2", "", ""), + ("", "", "", ""), + ] { + std::fs::write(d.join("VERSION"), content).unwrap(); + assert_eq!( + version(tmp.path()), + (tag.into(), cuda.into()), + "{content:?}" + ); + assert_eq!(version_format(tmp.path()), fmt, "{content:?}"); + } + } + + /// ROCm reconnu à son dossier (/opt/rocm), sans hipcc dans le PATH. + #[tokio::test] + async fn rocm_par_son_dossier() { + let root = tempfile::tempdir().unwrap(); + let tools = tempfile::tempdir().unwrap(); + let probe = Probe { + path: Some(vec![tools.path().to_path_buf()]), + root: root.path().to_path_buf(), + }; + let asset = |n: &str| Asset { + name: n.into(), + url: String::new(), + size: 1, + }; + let assets = [ + asset("llama-b1-bin-ubuntu-rocm-7.0-x64.tar.gz"), + asset("llama-b1-bin-ubuntu-x64.tar.gz"), + ]; + let linux = Target { + os: "linux", + arm64: false, + }; + assert_eq!( + pick(&assets, &probe, linux).await.unwrap().label, + "CPU (Linux x64)" + ); + assert_eq!(probe.detect_build_plan().await.backend, "cpu"); + std::fs::create_dir_all(root.path().join("opt/rocm")).unwrap(); + assert_eq!( + pick(&assets, &probe, linux).await.unwrap().label, + "ROCm (Linux x64)" + ); + assert_eq!(probe.detect_build_plan().await.backend, "hip"); + } + + #[test] + fn reco() { + assert_eq!(recommended_mode("cuda", "linux")["mode"], "opt"); + assert_eq!(recommended_mode("cuda", "windows")["mode"], "fast"); + assert_eq!(recommended_mode("vulkan", "linux")["why"], ""); + } +} diff --git a/rust/loki-rs/src/backends/probe.rs b/rust/loki-rs/src/backends/probe.rs new file mode 100644 index 0000000..ccef7f4 --- /dev/null +++ b/rust/loki-rs/src/backends/probe.rs @@ -0,0 +1,428 @@ +//! Sondes de la machine : port de `detectBuildPlan` (le seul plan exposé : +//! backend, architectures CUDA, parallélisme), `findNvcc`, `hasNvidiaGPU`, +//! `detectCudaArch`, `hasTool`, `hasVulkanLib`, `driverCudaVersion` et +//! `detectGPUs` (`backend_build.go`, `backend_prebuilt.go`, `backend_gpu.go`). +//! +//! Les outils sont cherchés dans un PATH et les chemins système sous une +//! racine, tous deux injectables : les tests rejouent une machine sans toucher +//! à l'environnement du processus. + +use std::path::{Path, PathBuf}; +use std::process::Stdio; +use std::sync::LazyLock; +use std::time::Duration; + +use regex::Regex; +use tokio::process::Command; + +/// Délai de `nvidiaSmiGPUQuery` (`nvidiaSmiTimeout`). +const NVIDIA_SMI_TIMEOUT: Duration = Duration::from_secs(10); + +/// `gpuBaseFields` / `gpuLinkFields`. +const GPU_BASE_FIELDS: &str = "index,name,memory.total,memory.used,compute_cap"; +const GPU_LINK_FIELDS: &str = "pci.bus_id,pcie.link.gen.current,pcie.link.gen.max,pcie.link.width.current,pcie.link.width.max,clocks.max.memory"; + +/// La machine telle que les sondes la voient. +#[derive(Clone, Debug, Default)] +pub struct Probe { + /// Dossiers où chercher les outils ; `None` : le PATH du processus, relu + /// à chaque recherche (comme `exec.LookPath`). + pub path: Option>, + /// Racine des chemins système (`/usr/local/cuda`, `/opt/rocm`…) ; vide : + /// la vraie racine. + pub root: PathBuf, +} + +/// Le plan de compilation tel que le statut l'expose (`buildPlan`). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BuildPlan { + pub backend: &'static str, + pub cuda_arch: String, + pub jobs: usize, +} + +/// `gpuInfo` : une carte vue par nvidia-smi. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct GpuInfo { + pub index: i64, + pub name: String, + pub mem_total: String, + pub mem_used: String, + pub cap: String, + pub bus_id: String, + pub link_gen: i64, + pub link_gen_max: i64, + pub link_width: i64, + pub link_width_max: i64, + pub mem_clock_max: i64, +} + +impl Probe { + /// La vraie machine. + pub fn system() -> Self { + Probe::default() + } + + /// Un chemin système sous la racine des sondes. + pub fn sys(&self, p: &str) -> PathBuf { + if self.root.as_os_str().is_empty() { + PathBuf::from(p) + } else { + self.root.join(p.trim_start_matches('/')) + } + } + + fn dirs(&self) -> Vec { + match &self.path { + Some(p) => p.clone(), + None => std::env::var_os("PATH") + .map(|p| std::env::split_paths(&p).collect()) + .unwrap_or_default(), + } + } + + /// `exec.LookPath` dans le PATH des sondes. + pub fn look_path(&self, name: &str) -> Option { + if name.contains('/') { + let p = PathBuf::from(name); + return is_exec(&p).then_some(p); + } + self.dirs() + .into_iter() + .map(|d| { + if d.as_os_str().is_empty() { + PathBuf::from(".").join(name) + } else { + d.join(name) + } + }) + .find(|p| is_exec(p)) + } + + /// `hasTool`. + pub fn has_tool(&self, name: &str) -> bool { + self.look_path(name).is_some() + } + + /// `exec.Command(name, args…).Output()` : la sortie standard si le + /// programme est trouvé et sort en succès. + pub async fn output(&self, name: &str, args: &[&str]) -> Option> { + self.output_in(None, name, args).await + } + + /// [`Probe::output`] lancé dans `dir`. + pub async fn output_in( + &self, + dir: Option<&Path>, + name: &str, + args: &[&str], + ) -> Option> { + let bin = self.look_path(name)?; + let mut c = Command::new(bin); + if let Some(d) = dir { + c.current_dir(d); + } + let out = c + .args(args) + .stdin(Stdio::null()) + .stderr(Stdio::null()) + .kill_on_drop(true) + .output() + .await + .ok()?; + out.status.success().then_some(out.stdout) + } + + /// `findNvcc` (Linux, macOS) : un vrai toolkit avant le PATH. + pub fn find_nvcc(&self) -> Option { + let p = self.sys("/usr/local/cuda/bin/nvcc"); + if is_file(&p) { + return Some(p); + } + let local = self.sys("/usr/local"); + let mut versioned: Vec = std::fs::read_dir(&local) + .map(|rd| { + rd.flatten() + .filter(|e| e.file_name().to_string_lossy().starts_with("cuda-")) + .map(|e| e.path().join("bin").join("nvcc")) + .filter(|p| std::fs::symlink_metadata(p).is_ok()) + .collect() + }) + .unwrap_or_default(); + versioned.sort(); + if let Some(p) = versioned.pop() { + return Some(p); + } + self.look_path("nvcc") + } + + /// `hasNvidiaGPU`. + pub async fn has_nvidia_gpu(&self) -> bool { + if !self.has_tool("nvidia-smi") { + return false; + } + self.output("nvidia-smi", &["-L"]) + .await + .is_some_and(|o| String::from_utf8_lossy(&o).contains("GPU")) + } + + /// `detectCudaArch` : « 8.6 » → « 86 », dédoublonnés, joints par « ; ». + pub async fn detect_cuda_arch(&self) -> String { + let Some(out) = self + .output( + "nvidia-smi", + &["--query-gpu=compute_cap", "--format=csv,noheader"], + ) + .await + else { + return String::new(); + }; + cuda_archs(&String::from_utf8_lossy(&out)) + } + + /// `hasVulkanLib` : le cache de ldconfig, puis des chemins connus. + pub async fn has_vulkan_lib(&self) -> bool { + if let Some(out) = self.output("ldconfig", &["-p"]).await + && String::from_utf8_lossy(&out).contains("libvulkan.so") + { + return true; + } + [ + "/usr/lib/x86_64-linux-gnu/libvulkan.so.1", + "/usr/lib64/libvulkan.so.1", + "/usr/lib/libvulkan.so.1", + "/lib64/libvulkan.so.1", + ] + .iter() + .any(|p| is_file(&self.sys(p))) + } + + /// `detectBuildPlan`, réduit à ce que le statut expose. + pub async fn detect_build_plan(&self) -> BuildPlan { + let mut p = BuildPlan { + backend: "cpu", + cuda_arch: String::new(), + jobs: num_jobs(), + }; + if cfg!(target_os = "macos") { + p.backend = "metal"; + return p; + } + if self.find_nvcc().is_some() && self.has_nvidia_gpu().await { + p.backend = "cuda"; + p.cuda_arch = self.detect_cuda_arch().await; + return p; + } + if self.has_tool("hipcc") || is_dir(&self.sys("/opt/rocm")) { + p.backend = "hip"; + return p; + } + if self.has_tool("glslc") && (self.has_vulkan_lib().await || self.has_tool("vulkaninfo")) { + p.backend = "vulkan"; + } + p + } + + /// `driverCudaVersion` : la version CUDA du bandeau de nvidia-smi, 0 si + /// inconnue. + pub async fn driver_cuda_version(&self) -> f64 { + let Some(out) = self.output("nvidia-smi", &[]).await else { + return 0.0; + }; + static RE: LazyLock = + LazyLock::new(|| Regex::new(r"CUDA Version:\s*([0-9]+\.[0-9]+)").expect("motif")); + RE.captures(&String::from_utf8_lossy(&out)) + .and_then(|m| m[1].parse().ok()) + .unwrap_or(0.0) + } + + /// `nvidiaSmiGPUQuery` : (sortie, code de sortie) ; `None` = pas lancé ou + /// délai dépassé. + async fn smi_query(&self, fields: &str) -> Option<(Vec, i32)> { + let bin = self.look_path("nvidia-smi")?; + let child = Command::new(bin) + .arg(format!("--query-gpu={fields}")) + .arg("--format=csv,noheader,nounits") + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .kill_on_drop(true) + .spawn() + .ok()?; + let out = tokio::time::timeout(NVIDIA_SMI_TIMEOUT, child.wait_with_output()) + .await + .ok()? + .ok()?; + Some((out.stdout, out.status.code().unwrap_or(-1))) + } + + /// `detectGPUs` : les cartes NVIDIA, champs de liaison compris quand le + /// pilote les connaît. + pub async fn detect_gpus(&self) -> Result, String> { + if !self.has_tool("nvidia-smi") { + return Err( + "nvidia-smi introuvable — sélection GPU disponible uniquement sur NVIDIA".into(), + ); + } + let mut res = self + .smi_query(&format!("{GPU_BASE_FIELDS},{GPU_LINK_FIELDS}")) + .await; + if let Some((out, code)) = &res + && *code != 0 + && (String::from_utf8_lossy(out).contains("valid field") || *code == 2) + { + res = self.smi_query(GPU_BASE_FIELDS).await; + } + let out = match res { + Some((out, 0)) => out, + Some((_, code)) => return Err(format!("nvidia-smi a échoué: exit status {code}")), + None => return Err("nvidia-smi a échoué".into()), + }; + let gpus = parse_gpu_query(&String::from_utf8_lossy(&out)); + if gpus.is_empty() { + return Err("aucun GPU NVIDIA détecté".into()); + } + Ok(gpus) + } +} + +/// Les architectures CUDA d'une sortie `compute_cap` (`detectCudaArch`). +pub fn cuda_archs(out: &str) -> String { + let mut archs: Vec = Vec::new(); + for line in out.trim().split('\n') { + let cap = line.trim(); + if cap.is_empty() || cap.to_lowercase().contains("not supported") { + continue; + } + let code = cap.replace('.', ""); + if !code.is_empty() && !archs.contains(&code) { + archs.push(code); + } + } + archs.join(";") +} + +/// `parseGPUQuery`. +pub fn parse_gpu_query(out: &str) -> Vec { + let mut gpus = Vec::new(); + for line in out.trim().split('\n') { + let parts: Vec<&str> = line.split(',').map(str::trim).collect(); + if parts.len() < 5 { + continue; + } + let mut g = GpuInfo { + index: parts[0].parse().unwrap_or(0), + name: parts[1].into(), + mem_total: parts[2].into(), + mem_used: parts[3].into(), + cap: parts[4].into(), + ..GpuInfo::default() + }; + if parts.len() >= 11 { + let b = parts[5]; + if !b.is_empty() && b != "N/A" && !b.starts_with('[') { + g.bus_id = b.into(); + } + g.link_gen = smi_num(parts[6]); + g.link_gen_max = smi_num(parts[7]); + g.link_width = smi_num(parts[8]); + g.link_width_max = smi_num(parts[9]); + g.mem_clock_max = smi_num(parts[10]); + } + gpus.push(g); + } + gpus +} + +/// `smiNum` : « [N/A] », vide ou négatif → 0. +pub fn smi_num(s: &str) -> i64 { + match s.trim().parse::() { + Ok(n) if n >= 0 => n, + _ => 0, + } +} + +/// `numJobs` : `runtime.NumCPU()`, c'est-à-dire les processeurs de +/// l'affinité du processus (sans les quotas de cgroup, que le Go ignore). +pub fn num_jobs() -> usize { + #[cfg(target_os = "linux")] + { + // SAFETY: cpu_set_t est une simple table de bits, initialisée à zéro + // avant que sched_getaffinity ne la remplisse. + unsafe { + let mut set: libc::cpu_set_t = std::mem::zeroed(); + if libc::sched_getaffinity(0, std::mem::size_of::(), &mut set) == 0 { + let n = libc::CPU_COUNT(&set); + if n > 0 { + return n as usize; + } + } + } + } + std::thread::available_parallelism().map_or(1, |n| n.get()) +} + +fn is_exec(p: &Path) -> bool { + std::fs::metadata(p).is_ok_and(|m| { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + m.is_file() && m.permissions().mode() & 0o111 != 0 + } + #[cfg(not(unix))] + { + m.is_file() + } + }) +} + +/// `isFile`. +pub fn is_file(p: &Path) -> bool { + std::fs::metadata(p).is_ok_and(|m| !m.is_dir()) +} + +/// `isDir`. +pub fn is_dir(p: &Path) -> bool { + std::fs::metadata(p).is_ok_and(|m| m.is_dir()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn archs() { + assert_eq!(cuda_archs("8.6\n8.9\n8.6\n"), "86;89"); + assert_eq!(cuda_archs("[Not Supported]\n12.0"), "120"); + assert_eq!(cuda_archs(""), ""); + } + + #[test] + fn requete_gpu() { + let g = parse_gpu_query( + "0, A, 100, 1, 8.6, 00000000:01:00.0, 1, 4, 16, 16, 9751\n1, B, 8, 0, 7.5, [N/A], 2, 3, 8, 16, 7001\n2, C, 8, 0, 7.5, N/A, x, 3, 8, 16, 1\n3, D, 1, 0\n4, E, 2, 1, 6.1", + ); + assert_eq!(g.len(), 4); + assert_eq!(g[0].bus_id, "00000000:01:00.0"); + assert_eq!((g[0].link_gen, g[0].mem_clock_max), (1, 9751)); + assert_eq!(g[1].bus_id, ""); + assert_eq!(g[2].bus_id, ""); + assert_eq!(g[2].link_gen, 0); + assert_eq!( + (g[3].index, g[3].name.as_str(), g[3].bus_id.as_str()), + (4, "E", "") + ); + } + + #[test] + fn smi() { + assert_eq!(smi_num(" 4 "), 4); + assert_eq!(smi_num("[N/A]"), 0); + assert_eq!(smi_num("-1"), 0); + } + + #[test] + fn jobs_positif() { + assert!(num_jobs() >= 1); + } +} diff --git a/rust/loki-rs/src/lib.rs b/rust/loki-rs/src/lib.rs index 56424dc..980da5d 100644 --- a/rust/loki-rs/src/lib.rs +++ b/rust/loki-rs/src/lib.rs @@ -12,6 +12,7 @@ pub mod api; pub mod auth; +pub mod backends; pub mod chat; pub mod chatapi; pub mod chatx; diff --git a/rust/loki-rs/src/main.rs b/rust/loki-rs/src/main.rs index 099d51f..ee1c242 100644 --- a/rust/loki-rs/src/main.rs +++ b/rust/loki-rs/src/main.rs @@ -163,6 +163,10 @@ fn serve() -> ExitCode { // (l'image se met à jour par Docker). let update_rust = held_by_facade("LOKI_UPDATE") && loki_rs::sysupdate::usable(std::env::var("LOKI_CONTAINER").ok().as_deref()); + // LOKI_BACKENDS=rust : les backends llama.cpp (statut, précompilé, + // bascule, GPU) et LE job des moteurs, auquel les jobs du Go + // (compilation, moteur de l'image, Strata) rapportent leurs étapes. + let backends_rust = held_by_facade("LOKI_BACKENDS"); let engine_rust = held_by_facade("LOKI_ENGINE") && match loki_rs::enginectl::usable( std::env::var("LOKI_CONTAINER").ok().as_deref(), @@ -194,6 +198,7 @@ fn serve() -> ExitCode { ("LOKI_PROJECTS", projects_rust), ("LOKI_MCP", mcp_rust), ("LOKI_UPDATE", update_rust), + ("LOKI_BACKENDS", backends_rust), ]; for (var, on) in held { if on { @@ -245,6 +250,21 @@ fn serve() -> ExitCode { std::sync::Arc::new(loki_rs::dictate::Dictation::new(&engine_paths.home)) }); + // Le dernier job connu, repris de la base (un job « en cours » est mort + // avec le processus précédent). + let backends = if backends_rust { + let b = std::sync::Arc::new(loki_rs::backends::Backends::new( + engine_paths.home.clone(), + std::env::var("LOKI_ENGINE_BIN").unwrap_or_default(), + )); + b.jobs + .restore(&loki_rs::store::Store::new(backend, token.clone())) + .await; + Some(b) + } else { + None + }; + let files = if files_rust { Some(start_files(backend, &token).await) } else { @@ -300,6 +320,7 @@ fn serve() -> ExitCode { system: system_rust.then(|| std::sync::Arc::new(loki_rs::system::System::new())), projects: projects_rust, update: update_rust, + backends, mcp: mcp_rust.then(|| std::sync::Arc::new(loki_rs::mcp::Mcp::new(mem_home))), }; let res = proxy::serve(listener, cfg, shutdown_signal()).await; diff --git a/rust/loki-rs/src/proxy.rs b/rust/loki-rs/src/proxy.rs index d014718..8e26eaa 100644 --- a/rust/loki-rs/src/proxy.rs +++ b/rust/loki-rs/src/proxy.rs @@ -93,6 +93,9 @@ pub struct Config { /// Mise à jour de Loki tenue par la façade (`LOKI_UPDATE=rust`, en /// conteneur). pub update: bool, + /// Backends llama.cpp (statut, précompilé, bascule, GPU) et job des + /// moteurs tenus par la façade (`LOKI_BACKENDS=rust`) ; `None` : au Go. + pub backends: Option>, } struct Proxy { @@ -132,6 +135,7 @@ pub async fn serve( projects: cfg.projects, mcp: cfg.mcp, update: cfg.update, + backends: cfg.backends, internal_token: cfg.internal_token.clone(), }, }); @@ -206,6 +210,12 @@ impl Proxy { { return crate::mcp::serve_internal(&self.ctx, m, req).await; } + if from_go + && let Some(b) = &self.ctx.backends + && crate::backends::is_internal(path) + { + return crate::backends::serve_internal(&self.ctx, b, req).await; + } // L'API interne du Go n'est jamais joignable de l'extérieur. if path.starts_with("/internal/") { return plain(StatusCode::NOT_FOUND, "404 page not found"); @@ -230,6 +240,11 @@ impl Proxy { { return chatapi::serve(&self.ctx, chat, req, from_go).await; } + if let Some(b) = &self.ctx.backends + && crate::backends::handles(path) + { + return crate::backends::serve(&self.ctx, b, req, from_go).await; + } if self.ctx.update && crate::sysupdate::handles(path) { return crate::sysupdate::serve(&self.ctx, req, from_go).await; } diff --git a/rust/loki-rs/src/serve/run.rs b/rust/loki-rs/src/serve/run.rs index ed73ac3..d6d38d3 100644 --- a/rust/loki-rs/src/serve/run.rs +++ b/rust/loki-rs/src/serve/run.rs @@ -189,7 +189,7 @@ impl EnginePaths { !p.is_empty() && norm_path(p).starts_with(&(norm_path(&self.engine_dir()) + "/")) } /// `prebuiltServerBin` : le binaire du VERSION, sinon le dernier. - fn prebuilt_server_bin(&self) -> String { + pub fn prebuilt_server_bin(&self) -> String { let mut found = Vec::new(); fn walk(d: &Path, out: &mut Vec) { let Ok(rd) = std::fs::read_dir(d) else { return }; @@ -229,7 +229,7 @@ impl EnginePaths { if cur.is_empty() { bin.into() } else { cur } } /// `providedEngineBin`. - fn provided_engine_bin(&self) -> String { + pub fn provided_engine_bin(&self) -> String { let p = std::env::var("LOKI_ENGINE_BIN").unwrap_or_default(); let p = trim(&p); if p.is_empty() { diff --git a/rust/loki-rs/src/system.rs b/rust/loki-rs/src/system.rs index 018b459..59b1b1a 100644 --- a/rust/loki-rs/src/system.rs +++ b/rust/loki-rs/src/system.rs @@ -171,7 +171,7 @@ pub fn key_hint(key: &str) -> String { /// Octets → texte comme l'encodeur JSON du Go : chaque octet invalide devient /// U+FFFD. -fn go_lossy(mut b: &[u8]) -> String { +pub(crate) fn go_lossy(mut b: &[u8]) -> String { let mut out = String::new(); loop { match std::str::from_utf8(b) { diff --git a/rust/loki-rs/tests/backends.rs b/rust/loki-rs/tests/backends.rs new file mode 100644 index 0000000..f88c412 --- /dev/null +++ b/rust/loki-rs/tests/backends.rs @@ -0,0 +1,786 @@ +//! Lot 22 : backends llama.cpp tenus par la façade (`LOKI_BACKENDS=rust`). +//! +//! Le journal tiré du Go (`internal/loki/parity_backends_test.go` → +//! `tests/parity_backends/backends.json`) est rejoué par une seule façade : +//! statut (dépôt git, précompilé, moteur téléchargé ou de l'image, plan de +//! build et conseil), vérification git, backends custom et désinstallation, +//! bascule fast/opt, dernière release, job des binaires précompilés +//! (extraction avec liens, ménage, VERSION, échecs), GPU vus par un moteur ; +//! puis le plan et la release machine par machine (faux outils dans le PATH), +//! le job pas à pas et sa reprise au démarrage. Le reste — l'API interne par +//! laquelle les jobs du Go rapportent leurs étapes, le service arrêté puis +//! relancé autour de l'installation — est vérifié contre le faux Go. + +mod common; + +use std::collections::BTreeMap; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use bytes::Bytes; +use common::fakego; +use http_body_util::Full; +use hyper::service::service_fn; +use hyper::{Request, Response}; +use hyper_util::rt::TokioIo; +use loki_rs::backends::job::Jobs; +use loki_rs::backends::probe::Probe; +use loki_rs::backends::{Backends, prebuilt}; +use regex::Regex; +use serde_json::{Value, json}; +use tokio::net::TcpListener; + +fn fixture() -> Value { + serde_json::from_str(include_str!("parity_backends/backends.json")).expect("journal") +} + +fn s(v: &Value) -> &str { + v.as_str().unwrap_or("") +} + +const TUNE_BUSY: &str = "optimisation en cours (loki tune) : le moteur est réservé aux essais — attends la fin ou annule-la"; + +/// Le faux GitHub : la release courante (`{status, json, assets}`). +async fn fake_github(rel: Arc>) -> String { + let l = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = l.local_addr().unwrap(); + tokio::spawn(async move { + while let Ok((st, _)) = l.accept().await { + let rel = rel.clone(); + tokio::spawn(async move { + let svc = service_fn(move |req: Request| { + let cur = rel.lock().unwrap().clone(); + async move { + let host = req + .headers() + .get("host") + .and_then(|h| h.to_str().ok()) + .unwrap_or("") + .to_string(); + let path = req.uri().path().to_string(); + let (code, body) = if path == "/latest" { + ( + cur["status"].as_u64().unwrap_or(200) as u16, + s(&cur["json"]) + .replace("{{GH}}", &format!("http://{host}")) + .into_bytes(), + ) + } else { + let name = path.trim_start_matches("/dl/"); + match cur["assets"].get(name).and_then(Value::as_array) { + Some(entries) => (200, tar_gz(entries)), + None => (404, b"404 page not found\n".to_vec()), + } + }; + let mut r = Response::new(Full::new(Bytes::from(body))); + *r.status_mut() = hyper::StatusCode::from_u16(code).unwrap(); + Ok::<_, Infallible>(r) + } + }); + let _ = hyper::server::conn::http1::Builder::new() + .serve_connection(TokioIo::new(st), svc) + .await; + }); + } + }); + format!("http://{addr}") +} + +/// Une archive .tar.gz ; les noms sont écrits tels quels (« ../x » compris). +fn tar_gz(entries: &[Value]) -> Vec { + let gz = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default()); + let mut b = tar::Builder::new(gz); + for e in entries { + let mut h = tar::Header::new_ustar(); + let name = s(&e["name"]).as_bytes(); + h.as_old_mut().name[..name.len()].copy_from_slice(name); + let link = s(&e["link"]).as_bytes(); + h.as_old_mut().linkname[..link.len()].copy_from_slice(link); + h.set_mtime(1_700_000_000); + h.set_mode(e["mode"].as_u64().unwrap_or(0) as u32); + let body = s(&e["body"]).as_bytes().to_vec(); + match s(&e["type"]) { + "dir" => h.set_entry_type(tar::EntryType::Directory), + "symlink" => { + h.set_entry_type(tar::EntryType::Symlink); + h.set_mode(0o777); + } + "hardlink" => h.set_entry_type(tar::EntryType::Link), + _ => { + h.set_entry_type(tar::EntryType::Regular); + h.set_size(body.len() as u64); + } + } + if s(&e["type"]) != "file" { + h.set_size(0); + } + h.set_cksum(); + let data: &[u8] = if s(&e["type"]) == "file" { &body } else { &[] }; + b.append(&h, data).unwrap(); + } + b.into_inner().unwrap().finish().unwrap() +} + +fn write_file(p: &Path, content: &str, mode: u32) { + use std::os::unix::fs::OpenOptionsExt; + let _ = std::fs::remove_file(p); + let mut f = std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .mode(mode) + .open(p) + .unwrap(); + std::io::Write::write_all(&mut f, content.as_bytes()).unwrap(); +} + +fn remove_all(p: &Path) { + match std::fs::symlink_metadata(p) { + Ok(m) if m.is_dir() => std::fs::remove_dir_all(p).unwrap(), + Ok(_) => std::fs::remove_file(p).unwrap(), + Err(_) => {} + } +} + +/// Les fichiers d'une étape (`parityApplyFiles`). +fn apply_files(home: &Path, files: &Value) { + for (n, v) in files.as_object().into_iter().flatten() { + let v = s(v); + let p = home.join(n.trim_end_matches('/')); + match v { + "-" => { + remove_all(&p); + continue; + } + "/" => { + std::fs::create_dir_all(&p).unwrap(); + continue; + } + _ => {} + } + std::fs::create_dir_all(p.parent().unwrap()).unwrap(); + if let Some(target) = v.strip_prefix("-> ") { + let _ = std::fs::remove_file(&p); + std::os::unix::fs::symlink(target, &p).unwrap(); + continue; + } + write_file(&p, v, if v.starts_with("#!") { 0o755 } else { 0o644 }); + } +} + +/// Les opérations git d'une étape (`parityGit`). +fn git_op(home: &Path, op: &str) { + let f: Vec<&str> = op.splitn(4, ' ').collect(); + let git = |dir: &Path, date: &str, args: &[&str]| { + let out = std::process::Command::new("git") + .args(args) + .current_dir(dir) + .env("GIT_CONFIG_GLOBAL", "/dev/null") + .env("GIT_CONFIG_NOSYSTEM", "1") + .env("GIT_AUTHOR_NAME", "Loki") + .env("GIT_AUTHOR_EMAIL", "loki@exemple.fr") + .env("GIT_COMMITTER_NAME", "Loki") + .env("GIT_COMMITTER_EMAIL", "loki@exemple.fr") + .env("GIT_AUTHOR_DATE", date) + .env("GIT_COMMITTER_DATE", date) + .output() + .unwrap(); + assert!(out.status.success(), "git {args:?} : {out:?}"); + }; + match f[0] { + "init" => { + let d = home.join(f[1]); + std::fs::create_dir_all(&d).unwrap(); + git(&d, "", &["init", "-q", "-b", "master"]); + } + "commit" => { + let d = home.join(f[1]); + std::fs::write(d.join("README"), f[3]).unwrap(); + git(&d, f[2], &["add", "README"]); + git(&d, f[2], &["commit", "-q", "-m", f[3]]); + } + "clone" => { + let (src, dst) = (home.join(f[1]), home.join(f[2])); + git( + home, + "", + &[ + "clone", + "-q", + &src.to_string_lossy(), + &dst.to_string_lossy(), + ], + ); + } + "pull" => git(&home.join(f[1]), "", &["pull", "-q", "--ff-only"]), + "detach" => git(&home.join(f[1]), "", &["checkout", "-q", "--detach"]), + "remote-bad" => { + let bad = home.join("nulle-part"); + git( + &home.join(f[1]), + "", + &["remote", "set-url", "origin", &bad.to_string_lossy()], + ); + } + other => panic!("opération git inconnue : {other}"), + } +} + +/// Les outils d'une machine dans le PATH des sondes (git compris). +fn set_machine(tools: &Path, machines: &Value, name: &str) { + for e in std::fs::read_dir(tools).unwrap().flatten() { + std::fs::remove_file(e.path()).unwrap(); + } + let git = loki_rs::paths::look_path("git").expect("git"); + std::os::unix::fs::symlink(git, tools.join("git")).unwrap(); + for (tool, script) in machines[name].as_object().into_iter().flatten() { + write_file(&tools.join(tool), s(script), 0o755); + } +} + +/// `info.Mode().Perm().String()`. +fn perm_string(mode: u32) -> String { + let mut out = String::from("-"); + for shift in [6, 3, 0] { + let b = (mode >> shift) & 7; + out.push(if b & 4 != 0 { 'r' } else { '-' }); + out.push(if b & 2 != 0 { 'w' } else { '-' }); + out.push(if b & 1 != 0 { 'x' } else { '-' }); + } + out +} + +/// `parityTree`. +fn tree(home: &Path) -> Vec { + use std::os::unix::fs::PermissionsExt; + fn walk(home: &Path, p: &Path, out: &mut Vec) { + let Ok(m) = std::fs::symlink_metadata(p) else { + return; + }; + let rel = p.strip_prefix(home).unwrap().to_string_lossy().into_owned(); + if rel.contains("/.git/") || rel.ends_with("/.git") { + return; + } + if m.file_type().is_symlink() { + let t = std::fs::read_link(p).unwrap(); + out.push(format!("l {rel} -> {}", t.to_string_lossy())); + } else if m.is_dir() { + out.push(format!("d {rel}")); + for e in std::fs::read_dir(p).unwrap().flatten() { + walk(home, &e.path(), out); + } + } else { + let b = std::fs::read(p).unwrap(); + out.push(format!( + "f {rel} {} {}", + perm_string(m.permissions().mode() & 0o777), + String::from_utf8_lossy(&b) + )); + } + } + let mut out = Vec::new(); + for root in ["backends", "engine"] { + walk(home, &home.join(root), &mut out); + } + out.sort(); + out +} + +struct Bench { + facade: SocketAddr, + go: Arc, + _stop: tokio::sync::oneshot::Sender<()>, + home: PathBuf, + tools: PathBuf, + b: Arc, + rel: Arc>, + gh: String, + _tmp: Vec, +} + +async fn bench() -> Bench { + let tmp = tempfile::tempdir().unwrap(); + let tools = tempfile::tempdir().unwrap(); + let root = tempfile::tempdir().unwrap(); + let home = tmp.path().to_path_buf(); + let rel = Arc::new(Mutex::new(json!({ "status": 200, "json": "{}" }))); + let gh = fake_github(rel.clone()).await; + let b = Arc::new(Backends::with( + home.clone(), + String::new(), + Probe { + path: Some(vec![tools.path().to_path_buf()]), + root: root.path().to_path_buf(), + }, + format!("{gh}/latest"), + )); + let (facade, go, stop, _) = fakego::start_with( + home.clone(), + fakego::Opts { + backends: Some(b.clone()), + ..Default::default() + }, + ) + .await; + Bench { + facade, + go, + _stop: stop, + home, + tools: tools.path().to_path_buf(), + b, + rel, + gh, + _tmp: vec![tmp, tools, root], + } +} + +impl Bench { + fn mask(&self, v: &str) -> String { + let ts = Regex::new(r#""(started_at|ended_at)":[1-9][0-9]*"#).unwrap(); + let jobs = Regex::new(r#""jobs":[0-9]+"#).unwrap(); + let v = v + .replace(&self.gh, "{{GH}}") + .replace(&self.home.to_string_lossy().into_owned(), "{{HOME}}"); + let v = jobs.replace_all(&v, r#""jobs":"{{JOBS}}""#); + ts.replace_all(&v, r#""$1":"{{T}}""#).into_owned() + } + + fn unmask(&self, v: &str) -> String { + v.replace("{{HOME}}", &self.home.to_string_lossy()) + } + + async fn call(&self, method: &str, path: &str, body: &str) -> (u16, Value) { + let (code, b) = fakego::send(self.facade, method, path, &[], body).await; + let out = serde_json::from_str(&self.mask(&String::from_utf8_lossy(&b))) + .unwrap_or_else(|_| panic!("{path} : corps illisible {b:?}")); + (code.as_u16(), out) + } + + async fn wait_job(&self) { + for _ in 0..1500 { + let (_, v) = self.call("GET", "/api/llamacpp/job", "").await; + if v["running"] != json!(true) { + return; + } + tokio::time::sleep(Duration::from_millis(20)).await; + } + panic!("le job ne finit pas"); + } +} + +#[tokio::test] +async fn parite_des_routes() { + let fx = fixture(); + if (fx["goarch"] == "arm64") != cfg!(target_arch = "aarch64") { + eprintln!("journal tiré sur une autre architecture : rejeu sauté"); + return; + } + let bn = bench().await; + let machines = &fx["machines"]; + set_machine(&bn.tools, machines, "nu"); + for st in fx["steps"].as_array().unwrap() { + let name = s(&st["name"]); + if let Some(m) = st["machine"].as_str() { + set_machine(&bn.tools, machines, m); + } + for g in st["git"].as_array().into_iter().flatten() { + git_op(&bn.home, s(g)); + } + let files: serde_json::Map = st["files"] + .as_object() + .into_iter() + .flatten() + .map(|(k, v)| (k.clone(), Value::String(bn.unmask(s(v))))) + .collect(); + apply_files(&bn.home, &Value::Object(files)); + for (k, v) in st["config"].as_object().into_iter().flatten() { + let v = bn.unmask(s(v)); + if v.is_empty() { + bn.go.del("config", k); + } else { + bn.go.set("config", k, &v); + } + } + if let Some(e) = st["engine_env"].as_str() { + bn.b.set_engine_bin_env(&bn.unmask(e)); + } + if !st["release"].is_null() { + *bn.rel.lock().unwrap() = st["release"].clone(); + } + *bn.go.tune_busy.lock().unwrap() = + (st["tune"].as_bool() == Some(true)).then(|| TUNE_BUSY.to_string()); + let (code, out) = bn + .call(s(&st["method"]), s(&st["path"]), &bn.unmask(s(&st["body"]))) + .await; + *bn.go.tune_busy.lock().unwrap() = None; + assert_eq!(code as i64, st["status"].as_i64().unwrap(), "{name}"); + assert_eq!(out, st["out"], "{name}"); + if st["wait"].as_bool() == Some(true) { + bn.wait_job().await; + let (_, job) = bn.call("GET", "/api/llamacpp/job?from=0", "").await; + assert_eq!(job, st["job"], "{name} : job"); + } + let mut after = BTreeMap::new(); + if let Some(v) = bn.go.get("config", "BIN").filter(|v| !v.is_empty()) { + after.insert("config/BIN".to_string(), Value::String(bn.mask(&v))); + } + if let Some(v) = bn.go.get("state", "build_job").filter(|v| !v.is_empty()) { + after.insert("state/build_job".to_string(), Value::String(bn.mask(&v))); + } + for f in ["loki-build.log", "devices.json"] { + if let Ok(b) = std::fs::read(bn.home.join(f)) { + after.insert( + f.to_string(), + Value::String(bn.mask(&String::from_utf8_lossy(&b))), + ); + } + } + assert_eq!( + Value::Object(after.into_iter().collect()), + st["after"], + "{name} : après" + ); + let t: Vec = tree(&bn.home) + .into_iter() + .map(|l| Value::String(bn.mask(&l))) + .collect(); + // Une liste vide est nil côté Go : null. + let t = if t.is_empty() { + Value::Null + } else { + Value::Array(t) + }; + assert_eq!(t, st["tree"], "{name} : arborescence"); + } + + // Plan, conseil et release, machine par machine. + *bn.rel.lock().unwrap() = fx["plan_release"].clone(); + for p in fx["plans"].as_array().unwrap() { + let m = s(&p["machine"]); + set_machine(&bn.tools, machines, m); + let (_, out) = bn.call("GET", "/api/llamacpp", "").await; + assert_eq!(out["plan"], p["plan"], "{m} : plan"); + assert_eq!(out["reco"], p["reco"], "{m} : conseil"); + let (_, check) = bn.call("POST", "/api/llamacpp/prebuilt/check", "").await; + assert_eq!(check, p["check"], "{m} : release"); + } + for (machine, key) in [ + ("vulkaninfo-seul", "sans_vulkan"), + ("rocm", "rocm_sans_asset"), + ] { + set_machine(&bn.tools, machines, machine); + *bn.rel.lock().unwrap() = fx[key]["release"].clone(); + let (_, check) = bn.call("POST", "/api/llamacpp/prebuilt/check", "").await; + assert_eq!(check, fx[key]["out"], "{key}"); + } +} + +/// `norm` du journal : les instants masqués. +fn norm(v: &Value) -> Value { + let ts = Regex::new(r#""(started_at|ended_at)":[1-9][0-9]*"#).unwrap(); + serde_json::from_str(&ts.replace_all(&v.to_string(), r#""$1":"{{T}}""#)).unwrap() +} + +#[tokio::test] +async fn parite_du_job_pas_a_pas() { + let fx = fixture(); + let bn = bench().await; + let backend = bn.go.backend.lock().unwrap().unwrap(); + let store = loki_rs::store::Store::new(backend, fakego::JETON.into()); + let ts = Regex::new(r#""(started_at|ended_at)":[1-9][0-9]*"#).unwrap(); + let state = || { + ts.replace_all( + &bn.go.get("state", "build_job").unwrap_or_default(), + r#""$1":"{{T}}""#, + ) + .into_owned() + }; + let jobs = Jobs::new(bn.home.clone()); + let job = &fx["job"]; + for o in job["ops"].as_array().unwrap() { + let (op, arg) = (s(&o["op"]), s(&o["arg"])); + let from = o["from"].as_i64().unwrap_or(0); + let got = match op { + "start" => Some(Value::String(match jobs.start(&store, arg).await { + Ok(()) => "ok".into(), + Err(e) => e, + })), + "line" => { + jobs.append(&store, arg).await; + None + } + "lines" => { + for _ in 0..4002 { + jobs.append(&store, &format!("[{arg}] bruit")).await; + } + None + } + "phase" => { + jobs.phase(&store, arg).await; + None + } + "fail" => { + jobs.fail(&store, arg).await; + None + } + "done" => { + jobs.done(&store, arg).await; + None + } + "old" => { + jobs.set_commits(Some(arg), None).await; + None + } + "new" => { + jobs.set_commits(None, Some(arg)).await; + None + } + "end" => { + jobs.end(&store).await; + None + } + "snapshot" => Some(norm(&jobs.snapshot(from, true).await)), + "summary" => { + let mut v = jobs.snapshot(from, true).await; + let lines = v["lines"].as_array().unwrap().clone(); + v["lines"] = json!({ + "n": lines.len(), + "first": lines[0], + "last": lines[lines.len() - 1], + }); + Some(norm(&v)) + } + "head" => Some(norm(&jobs.snapshot(0, false).await)), + "state" => Some(Value::String(state())), + other => panic!("op inconnue {other}"), + }; + assert_eq!(got.unwrap_or(Value::Null), o["out"], "{o}"); + } + let log = std::fs::read_to_string(jobs.log_path()).unwrap(); + assert_eq!( + log.matches('\n').count() as i64, + job["log_lines"].as_i64().unwrap() + ); + + for rc in job["restores"].as_array().unwrap() { + let st = s(&rc["state"]); + if st.is_empty() { + bn.go.del("state", "build_job"); + } else { + bn.go.set("state", "build_job", st); + } + let jobs = Jobs::new(bn.home.clone()); + let _ = std::fs::remove_file(jobs.log_path()); + if let Some(l) = rc["log"].as_str() { + std::fs::write(jobs.log_path(), l).unwrap(); + } + jobs.restore(&store).await; + assert_eq!(norm(&jobs.snapshot(0, true).await), rc["out"], "{rc}"); + assert_eq!(state(), s(&rc["after"]), "{rc} : base"); + } + let jobs = Jobs::new(bn.home.clone()); + bn.go.set( + "state", + "build_job", + r#"{"action":"update","running":false}"#, + ); + std::fs::write(jobs.log_path(), "ligne\n".repeat(4003)).unwrap(); + jobs.restore(&store).await; + assert_eq!(norm(&jobs.snapshot(4000, true).await), job["long_restore"]); +} + +/// Les étapes des jobs du Go, par l'API interne (jeton du Go seulement). +#[tokio::test] +async fn api_interne_du_job() { + let bn = bench().await; + let tok = [("X-Loki-Internal", fakego::JETON)]; + let post = |op: &'static str, body: &'static str| { + let f = bn.facade; + async move { + let (c, b) = fakego::send( + f, + "POST", + &format!("/internal/facade/v1/build-job/{op}"), + &tok, + body, + ) + .await; + (c.as_u16(), String::from_utf8_lossy(&b).into_owned()) + } + }; + // Sans le jeton : l'API interne n'existe pas. + let (c, _) = fakego::send( + bn.facade, + "POST", + "/internal/facade/v1/build-job/start", + &[], + r#"{"action":"engine"}"#, + ) + .await; + assert_eq!(c.as_u16(), 404); + assert_eq!(post("start", r#"{"action":"engine"}"#).await.0, 200); + let (c, b) = post("start", r#"{"action":"strata"}"#).await; + assert_eq!( + (c, b.contains("un job engine est déjà en cours")), + (409, true) + ); + // La route publique refuse aussi un second job (précompilé). + let (c, out) = bn.call("POST", "/api/llamacpp/prebuilt", "").await; + assert_eq!(c, 409); + assert_eq!(out["error"], "un job engine est déjà en cours"); + post("commits", r#"{"old":"aaa"}"#).await; + post( + "phase", + r#"{"phase":"recherche de la dernière version publiée…"}"#, + ) + .await; + post( + "line", + r#"{"line":"[ 50%] Building CXX object a/b/c.cpp.o"}"#, + ) + .await; + post("commits", r#"{"new":"bbb"}"#).await; + post("fail", r#"{"error":"raté"}"#).await; + post("done", r#"{"msg":"rattrapé"}"#).await; + let (_, v) = bn.call("GET", "/api/llamacpp/job?from=1", "").await; + assert_eq!(v["running"], true); + assert_eq!(v["compiled"], 1); + assert_eq!(v["old"], "aaa"); + assert_eq!(v["new"], "bbb"); + assert_eq!( + v["lines"], + json!([ + "[ 50%] Building CXX object a/b/c.cpp.o", + "✗ raté", + "✓ rattrapé" + ]) + ); + // La vue que le Go relaie (statut du moteur de l'image). + let (c, b) = fakego::send( + bn.facade, + "GET", + "/internal/facade/v1/build-job/snapshot?from=0&lines=0", + &tok, + "", + ) + .await; + assert_eq!(c.as_u16(), 200); + let head: Value = serde_json::from_slice(&b).unwrap(); + assert_eq!(head["phase"], "rattrapé"); + assert!(head.get("lines").is_none()); + assert_eq!(post("end", "{}").await.0, 200); + assert_eq!( + bn.call("GET", "/api/llamacpp", "").await.1["job"]["running"], + false + ); + // Méthode et opération. + let (c, _) = fakego::send( + bn.facade, + "GET", + "/internal/facade/v1/build-job/line", + &tok, + "", + ) + .await; + assert_eq!(c.as_u16(), 405); + assert_eq!(post("autre", "{}").await.0, 404); + // L'entête suit en base. + let st: Value = serde_json::from_str(&bn.go.get("state", "build_job").unwrap()).unwrap(); + assert_eq!(st["action"], "engine"); + assert_eq!(st["running"], false); + assert_eq!(st["error"], "raté"); +} + +/// Le moteur tourne : arrêté pendant l'installation, relancé après ; la +/// bascule le relance. +#[tokio::test] +async fn service_arrete_puis_relance() { + let fx = fixture(); + let bn = bench().await; + set_machine(&bn.tools, &fx["machines"], "nu"); + *bn.go.service_active.lock().unwrap() = true; + let ok = fx["steps"] + .as_array() + .unwrap() + .iter() + .find(|s| s["name"] == "installation") + .unwrap(); + *bn.rel.lock().unwrap() = ok["release"].clone(); + assert_eq!(bn.call("POST", "/api/llamacpp/prebuilt", "").await.0, 200); + bn.wait_job().await; + let (_, job) = bn.call("GET", "/api/llamacpp/job", "").await; + let lines: Vec<&str> = job["lines"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap()) + .collect(); + assert_eq!(lines[0], "▶ arrêt du service le temps de l'installation…"); + assert_eq!( + &lines[lines.len() - 3..], + &[ + "BIN mis à jour", + "▶ redémarrage du service…", + "✓ binaires précompilés installés (b300)" + ] + ); + assert_eq!( + *bn.go.service_actions.lock().unwrap(), + vec![("stop".to_string(), true), ("start".to_string(), false)] + ); + bn.go.service_actions.lock().unwrap().clear(); + let (c, out) = bn + .call("POST", "/api/llamacpp/use", r#"{"mode":"fast"}"#) + .await; + assert_eq!((c, out["ok"].clone()), (200, json!(true))); + assert_eq!( + *bn.go.service_actions.lock().unwrap(), + vec![("restart".to_string(), true)] + ); + // Arrêté : rien n'est relancé. + *bn.go.service_active.lock().unwrap() = false; + bn.go.service_actions.lock().unwrap().clear(); + assert_eq!(bn.call("POST", "/api/llamacpp/prebuilt", "").await.0, 200); + bn.wait_job().await; + assert_eq!( + *bn.go.service_actions.lock().unwrap(), + vec![("stop".to_string(), true)] + ); +} + +/// Une archive .zip (Windows) s'extrait aussi, sans évasion possible. +#[test] +fn extraction_zip() { + let tmp = tempfile::tempdir().unwrap(); + let zpath = tmp.path().join("a.zip"); + { + let f = std::fs::File::create(&zpath).unwrap(); + let mut z = zip::ZipWriter::new(f); + let o = zip::write::SimpleFileOptions::default(); + z.add_directory("llama-b1/", o).unwrap(); + z.start_file("llama-b1/llama-server.exe", o).unwrap(); + std::io::Write::write_all(&mut z, b"exe").unwrap(); + z.finish().unwrap(); + } + let out = tmp.path().join("out"); + prebuilt::extract(&zpath, &out).unwrap(); + assert_eq!( + std::fs::read(out.join("llama-b1/llama-server.exe")).unwrap(), + b"exe" + ); + let bad = tmp.path().join("b.zip"); + { + let f = std::fs::File::create(&bad).unwrap(); + let mut z = zip::ZipWriter::new(f); + z.start_file("../evasion", zip::write::SimpleFileOptions::default()) + .unwrap(); + z.finish().unwrap(); + } + assert_eq!( + prebuilt::extract(&bad, &out).unwrap_err(), + "entrée d'archive suspecte : ../evasion" + ); +} diff --git a/rust/loki-rs/tests/common/fakego.rs b/rust/loki-rs/tests/common/fakego.rs index 17f5603..16518e8 100644 --- a/rust/loki-rs/tests/common/fakego.rs +++ b/rust/loki-rs/tests/common/fakego.rs @@ -90,6 +90,8 @@ pub struct FakeGo { pub cdp_shutdowns: Mutex, /// /internal/v1/service/action reçus : (action, if_active). pub service_actions: Mutex>, + /// Le moteur tourne-t-il (`if_active` des actions de service) ? + pub service_active: Mutex, /// Comportement de /internal/v1/crypt/* (préfixe « SCELLE: » par défaut). pub crypt_mode: Mutex, /// Réponse de /internal/v1/conv/workspace (None : 404). @@ -426,10 +428,14 @@ async fn handle(st: Arc, req: Request) -> Response "/internal/v1/service/action" => { let body = req.into_body().collect().await.unwrap().to_bytes(); let v: serde_json::Value = serde_json::from_slice(&body).unwrap_or_default(); - st.service_actions.lock().unwrap().push(( - v["action"].as_str().unwrap_or("").to_string(), - v["if_active"].as_bool().unwrap_or(false), - )); + let if_active = v["if_active"].as_bool().unwrap_or(false); + st.service_actions + .lock() + .unwrap() + .push((v["action"].as_str().unwrap_or("").to_string(), if_active)); + if if_active && !*st.service_active.lock().unwrap() { + return resp(200, r#"{"ran":false,"error":""}"#); + } resp(200, r#"{"ran":true,"error":""}"#) } "/internal/v1/dictate/stop" => { @@ -635,6 +641,7 @@ pub struct Opts { pub projects: bool, pub mcp: Option>, pub update: bool, + pub backends: Option>, } /// Comme [`start`], avec la conversation tenue par la façade @@ -736,6 +743,7 @@ pub async fn start_with( projects: opts.projects, mcp: opts.mcp, update: opts.update, + backends: opts.backends, }; tokio::spawn(loki_rs::proxy::serve(fl, cfg, async move { let _ = rx.await; diff --git a/rust/loki-rs/tests/lot2.rs b/rust/loki-rs/tests/lot2.rs index 26d8c2e..1b4ba15 100644 --- a/rust/loki-rs/tests/lot2.rs +++ b/rust/loki-rs/tests/lot2.rs @@ -106,6 +106,7 @@ async fn banc(cle: Option<&str>) -> Banc { projects: false, mcp: None, update: false, + backends: None, }; tokio::spawn(loki_rs::proxy::serve(l, cfg, async move { let _ = rx.await; diff --git a/rust/loki-rs/tests/parity_backends/backends.json b/rust/loki-rs/tests/parity_backends/backends.json new file mode 100644 index 0000000..3df206f --- /dev/null +++ b/rust/loki-rs/tests/parity_backends/backends.json @@ -0,0 +1,6010 @@ +{ + "goarch": "amd64", + "job": { + "log_lines": 4014, + "long_restore": { + "action": "update", + "compiled": 0, + "ended_at": 0, + "error": "", + "exists": true, + "lines": [ + "ligne", + "ligne", + "ligne" + ], + "new": "", + "next": 4003, + "old": "", + "phase": "", + "running": false, + "started_at": 0 + }, + "ops": [ + { + "op": "head", + "out": { + "exists": false + } + }, + { + "op": "line", + "arg": "avant tout job" + }, + { + "op": "start", + "arg": "update", + "out": "ok" + }, + { + "op": "state", + "out": "{\"action\":\"update\",\"phase\":\"démarrage…\",\"compiled\":0,\"running\":true,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":0,\"old\":\"\",\"new\":\"\"}" + }, + { + "op": "start", + "arg": "engine", + "out": "un job update est déjà en cours" + }, + { + "op": "line", + "arg": "-- The C compiler identification is GNU 13.2.0 avec un très long suffixe é" + }, + { + "op": "head", + "out": { + "action": "update", + "compiled": 0, + "ended_at": 0, + "error": "", + "exists": true, + "new": "", + "old": "", + "phase": "configuration… The C compiler identification is GNU 13.2.0 avec …", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "line", + "arg": "[ 12%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml.cpp.o" + }, + { + "op": "line", + "arg": " Compiling CUDA source file ..\\ggml-cuda\\fattn.cu..." + }, + { + "op": "line", + "arg": "softmax.cuh" + }, + { + "op": "line", + "arg": "[100%] Linking CXX executable bin/llama-server" + }, + { + "op": "line", + "arg": "état : é.cpp" + }, + { + "op": "head", + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "new": "", + "old": "", + "phase": "édition de liens…", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "old", + "arg": "abc1234" + }, + { + "op": "phase", + "arg": "git pull origin/master…" + }, + { + "op": "new" + }, + { + "op": "state", + "out": "{\"action\":\"update\",\"phase\":\"git pull origin/master…\",\"compiled\":3,\"running\":true,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":0,\"old\":\"abc1234\",\"new\":\"\"}" + }, + { + "op": "line", + "arg": "-- Configuring done" + }, + { + "op": "state", + "out": "{\"action\":\"update\",\"phase\":\"git pull origin/master…\",\"compiled\":3,\"running\":true,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":0,\"old\":\"abc1234\",\"new\":\"\"}" + }, + { + "op": "snapshot", + "from": 2, + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": [ + " Compiling CUDA source file ..\\ggml-cuda\\fattn.cu...", + "softmax.cuh", + "[100%] Linking CXX executable bin/llama-server", + "état : é.cpp", + "▶ git pull origin/master…", + "-- Configuring done" + ], + "new": "", + "next": 8, + "old": "abc1234", + "phase": "configuration… Configuring done", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "lines", + "arg": "bloc" + }, + { + "op": "snapshot", + "from": 4005, + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": [ + "[bloc] bruit", + "[bloc] bruit", + "[bloc] bruit", + "[bloc] bruit", + "[bloc] bruit" + ], + "new": "", + "next": 4010, + "old": "abc1234", + "phase": "configuration… Configuring done", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "summary", + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": { + "first": "[bloc] bruit", + "last": "[bloc] bruit", + "n": 4000 + }, + "new": "", + "next": 4010, + "old": "abc1234", + "phase": "configuration… Configuring done", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "summary", + "from": 3, + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": { + "first": "[bloc] bruit", + "last": "[bloc] bruit", + "n": 4000 + }, + "new": "", + "next": 4010, + "old": "abc1234", + "phase": "configuration… Configuring done", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "line", + "arg": "Build files have been written to: /src/build" + }, + { + "op": "summary", + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": { + "first": "[bloc] bruit", + "last": "Build files have been written to: /src/build", + "n": 4000 + }, + "new": "", + "next": 4011, + "old": "abc1234", + "phase": "édition de liens…", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "line", + "arg": "une de plus" + }, + { + "op": "summary", + "out": { + "action": "update", + "compiled": 3, + "ended_at": 0, + "error": "", + "exists": true, + "lines": { + "first": "[bloc] bruit", + "last": "une de plus", + "n": 4000 + }, + "new": "", + "next": 4012, + "old": "abc1234", + "phase": "édition de liens…", + "running": true, + "started_at": "{{T}}" + } + }, + { + "op": "fail", + "arg": "compilation échouée: exit status 2" + }, + { + "op": "done", + "arg": "tout de même" + }, + { + "op": "end" + }, + { + "op": "head", + "out": { + "action": "update", + "compiled": 3, + "ended_at": "{{T}}", + "error": "compilation échouée: exit status 2", + "exists": true, + "new": "", + "old": "abc1234", + "phase": "tout de même", + "running": false, + "started_at": "{{T}}" + } + }, + { + "op": "state", + "out": "{\"action\":\"update\",\"phase\":\"tout de même\",\"compiled\":3,\"running\":false,\"error\":\"compilation échouée: exit status 2\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"abc1234\",\"new\":\"\"}" + } + ], + "restores": [ + { + "state": "", + "log": null, + "out": { + "exists": false + }, + "after": "" + }, + { + "state": "{\"action\":\"\"}", + "log": null, + "out": { + "exists": false + }, + "after": "{\"action\":\"\"}" + }, + { + "state": "{\"action\":\"prebuilt\",\"phase\":\"fini\",\"running\":false,\"started_at\":5,\"ended_at\":6}", + "log": "a\nb\n", + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "a", + "b" + ], + "new": "", + "next": 2, + "old": "", + "phase": "fini", + "running": false, + "started_at": "{{T}}" + }, + "after": "{\"action\":\"prebuilt\",\"phase\":\"fini\",\"running\":false,\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\"}" + }, + { + "state": "{\"action\":\"update\",\"phase\":\"compilation… 3 fichiers\",\"compiled\":3,\"running\":true,\"started_at\":5,\"old\":\"abc\"}", + "log": "x\n", + "out": { + "action": "update", + "compiled": 3, + "ended_at": "{{T}}", + "error": "interrompu : le service a redémarré pendant l'opération — relancez-la", + "exists": true, + "lines": [ + "x", + "✗ interrompu : le service a redémarré (la compilation ne survit pas au redémarrage)" + ], + "new": "", + "next": 2, + "old": "abc", + "phase": "interrompu", + "running": false, + "started_at": "{{T}}" + }, + "after": "{\"action\":\"update\",\"phase\":\"interrompu\",\"compiled\":3,\"running\":false,\"error\":\"interrompu : le service a redémarré pendant l'opération — relancez-la\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"abc\",\"new\":\"\"}" + }, + { + "state": "{\"action\":\"strata\",\"running\":true}", + "log": null, + "out": { + "action": "strata", + "compiled": 0, + "ended_at": "{{T}}", + "error": "interrompu : le service a redémarré pendant l'opération — relancez-la", + "exists": true, + "lines": [ + "✗ interrompu : le service a redémarré (la compilation ne survit pas au redémarrage)" + ], + "new": "", + "next": 1, + "old": "", + "phase": "interrompu", + "running": false, + "started_at": 0 + }, + "after": "{\"action\":\"strata\",\"phase\":\"interrompu\",\"compiled\":0,\"running\":false,\"error\":\"interrompu : le service a redémarré pendant l'opération — relancez-la\",\"started_at\":0,\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + { + "state": "{\"action\":\"engine\",\"running\":false}", + "log": "", + "out": { + "action": "engine", + "compiled": 0, + "ended_at": 0, + "error": "", + "exists": true, + "lines": null, + "new": "", + "next": 0, + "old": "", + "phase": "", + "running": false, + "started_at": 0 + }, + "after": "{\"action\":\"engine\",\"running\":false}" + }, + { + "state": "{\"action\":\"engine\",\"running\":false}", + "log": "\n\n", + "out": { + "action": "engine", + "compiled": 0, + "ended_at": 0, + "error": "", + "exists": true, + "lines": null, + "new": "", + "next": 0, + "old": "", + "phase": "", + "running": false, + "started_at": 0 + }, + "after": "{\"action\":\"engine\",\"running\":false}" + }, + { + "state": "pas du json", + "log": null, + "out": { + "exists": false + }, + "after": "pas du json" + }, + { + "state": "{\"action\":\"engine\",\"compiled\":\"3\"}", + "log": null, + "out": { + "exists": false + }, + "after": "{\"action\":\"engine\",\"compiled\":\"3\"}" + } + ] + }, + "machines": { + "arch-ancienne": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n--query-gpu=index*pci.bus_id*) echo 'Field \"pci.bus_id\" is not a valid field to query.'; exit 2;;\n--query-gpu=*) echo '0, Vieille carte, 4096, 10, 6.1';;\n-L) echo 'GPU 0: Vieille carte';;\nesac\n" + }, + "glslc-ldconfig": { + "glslc": "#!/bin/sh\nexit 0\n", + "ldconfig": "#!/bin/sh\necho '\tlibvulkan.so.1 (libc6,x86-64) => /usr/lib/libvulkan.so.1'\n" + }, + "liaison-partielle": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n--query-gpu=*) echo '0, Carte P, 4096, 1, 8.6, 00000000:02:00.0, [N/A], [N/A], 4, 8, 5001';;\nesac\n" + }, + "nu": {}, + "nvidia": { + "nvcc": "#!/bin/sh\nexit 0\n", + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: NVIDIA GeForce RTX 3090 (UUID: GPU-1)';;\n--query-gpu=compute_cap) printf '8.6\\n8.9\\n8.6\\n';;\n'') echo '| NVIDIA-SMI 570.00 Driver Version: 570.00 CUDA Version: 12.8 |';;\n--query-gpu=*) printf '0, NVIDIA GeForce RTX 3090, 24576, 100, 8.6, 00000000:01:00.0, 1, 4, 16, 16, 9751\\n1, Carte B, 8192, 5, 7.5, [N/A], [N/A], 3, 8, 16, 7001\\n';;\nesac\n" + }, + "nvidia-en-panne": { + "nvcc": "#!/bin/sh\nexit 0\n", + "nvidia-smi": "#!/bin/sh\nexit 9\n" + }, + "nvidia-jumelles": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: Carte B';;\n--query-gpu=*) printf '0, Carte B, 8192, 5, 7.5, [N/A], 1, 3, 8, 16, 7001\\n1, Carte B, 8192, 5, 7.5, [N/A], 1, 3, 8, 16, 7001\\n';;\nesac\n" + }, + "nvidia-muet": { + "nvcc": "#!/bin/sh\nexit 0\n", + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'rien';;\nesac\n" + }, + "nvidia-sans-nvcc": { + "nvidia-smi": "#!/bin/sh\ncase \"$1\" in\n-L) echo 'GPU 0: NVIDIA (UUID: GPU-1)';;\n--query-gpu=compute_cap) echo '12.0';;\nesac\n" + }, + "rocm": { + "hipcc": "#!/bin/sh\nexit 0\n" + }, + "vulkan": { + "glslc": "#!/bin/sh\nexit 0\n", + "vulkaninfo": "#!/bin/sh\nexit 0\n" + }, + "vulkaninfo-seul": { + "vulkaninfo": "#!/bin/sh\nexit 0\n" + } + }, + "plan_release": { + "status": 200, + "json": "{\"tag_name\":\"b400\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}" + }, + "plans": [ + { + "machine": "arch-ancienne", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64) — pas de build CUDA officiel Linux ; compile localement pour du CUDA natif" + } + }, + { + "machine": "glslc-ldconfig", + "plan": { + "arch": "", + "backend": "vulkan", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + } + }, + { + "machine": "liaison-partielle", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + } + }, + { + "machine": "nu", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + } + }, + { + "machine": "nvidia", + "plan": { + "arch": "86;89", + "backend": "cuda", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "opt", + "why": "seule voie vers du CUDA natif : llama.cpp ne publie aucun binaire CUDA pour Linux, le précompilé ne donnerait que du Vulkan. Compte plusieurs minutes de compilation." + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64) — pas de build CUDA officiel Linux ; compile localement pour du CUDA natif" + } + }, + { + "machine": "nvidia-en-panne", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + } + }, + { + "machine": "nvidia-jumelles", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64) — pas de build CUDA officiel Linux ; compile localement pour du CUDA natif" + } + }, + { + "machine": "nvidia-muet", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + } + }, + { + "machine": "nvidia-sans-nvcc", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64) — pas de build CUDA officiel Linux ; compile localement pour du CUDA natif" + } + }, + { + "machine": "rocm", + "plan": { + "arch": "", + "backend": "hip", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "ROCm (Linux x64)" + } + }, + { + "machine": "vulkan", + "plan": { + "arch": "", + "backend": "vulkan", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64)" + } + }, + { + "machine": "vulkaninfo-seul", + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "reco": { + "mode": "fast", + "why": "" + }, + "check": { + "current": "b305", + "latest": "b400", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "Vulkan (Linux x64)" + } + } + ], + "rocm_sans_asset": { + "out": { + "current": "b305", + "latest": "b402", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + }, + "release": { + "status": 200, + "json": "{\"tag_name\":\"b402\",\"assets\":[{\"name\":\"llama-b402-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b402-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b402-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b402-bin-ubuntu-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b402-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b402-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b402-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b402-bin-ubuntu-arm64.tar.gz\",\"size\":2500000}]}" + } + }, + "sans_vulkan": { + "out": { + "current": "b305", + "latest": "b401", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + }, + "release": { + "status": 200, + "json": "{\"tag_name\":\"b401\",\"assets\":[{\"name\":\"llama-b401-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b401-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b401-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b401-bin-ubuntu-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b401-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b401-bin-ubuntu-arm64.tar.gz\",\"size\":2500000}]}" + } + }, + "steps": [ + { + "name": "statut vide", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "", + "config_bin": "", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": {}, + "tree": null + }, + { + "name": "backends vides", + "method": "GET", + "path": "/api/backends", + "status": 200, + "out": [], + "after": {}, + "tree": null + }, + { + "name": "custom vides", + "method": "GET", + "path": "/api/backends/custom", + "status": 200, + "out": [], + "after": {}, + "tree": null + }, + { + "name": "job absent", + "method": "GET", + "path": "/api/llamacpp/job", + "status": 200, + "out": { + "exists": false + }, + "after": {}, + "tree": null + }, + { + "name": "deux versions précompilées", + "files": { + "backends/llama.cpp-prebuilt/VERSION": "b100 12.4 fmt2\n", + "backends/llama.cpp-prebuilt/llama-b100/llama-server": "#!/bin/sh\n", + "backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server": "#!/bin/sh\n" + }, + "config": { + "BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server" + }, + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "", + "config_bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b100/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": true, + "tag": "b100" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b100 12.4 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n" + ] + }, + { + "name": "VERSION absent : la plus récente", + "files": { + "backends/llama.cpp-prebuilt/VERSION": "-" + }, + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "", + "config_bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": true, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n" + ] + }, + { + "name": "BIN précompilé disparu", + "config": { + "BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b050/llama-server" + }, + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "", + "config_bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b050/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": true, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b050/llama-server" + }, + "tree": [ + "d backends", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n" + ] + }, + { + "name": "backends custom", + "files": { + "backends/.cache/llama-server": "x", + "backends/fichier": "x", + "backends/fork-a/CMakeLists.txt": "", + "backends/fork-a/build/bin/llama-server": "#!/bin/sh\n", + "backends/fork-b/bin/llama-server": "#!/bin/sh\n", + "backends/fork-c/build/bin/llama-server": "/", + "backends/fork-c/llama-server.exe": "x", + "backends/lien": "-> fork-b", + "backends/llama.cpp-prebuilt/bin/llama-server": "#!/bin/sh\n", + "backends/vide/": "/" + }, + "config": { + "BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "method": "GET", + "path": "/api/backends", + "status": 200, + "out": [ + { + "name": "fork-a", + "path": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + { + "name": "fork-b", + "path": "{{HOME}}/backends/fork-b/bin/llama-server" + }, + { + "name": "fork-c", + "path": "{{HOME}}/backends/fork-c/llama-server.exe" + }, + { + "name": "lien", + "path": "{{HOME}}/backends/lien/bin/llama-server" + }, + { + "name": "llama.cpp-prebuilt", + "path": "{{HOME}}/backends/llama.cpp-prebuilt/bin/llama-server" + } + ], + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "custom seulement", + "method": "GET", + "path": "/api/backends/custom", + "status": 200, + "out": [ + { + "in_use": true, + "name": "fork-a", + "path": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + { + "in_use": false, + "name": "fork-b", + "path": "{{HOME}}/backends/fork-b/bin/llama-server" + }, + { + "in_use": false, + "name": "fork-c", + "path": "{{HOME}}/backends/fork-c/llama-server.exe" + }, + { + "in_use": false, + "name": "lien", + "path": "{{HOME}}/backends/lien/bin/llama-server" + } + ], + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "statut sur un fork", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/fork-a/build/bin/llama-server", + "config_bin": "{{HOME}}/backends/fork-a/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": true, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/fork-a" + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller le canonique", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"llama.cpp\"}", + "status": 400, + "out": { + "error": "ce moteur se gère depuis les cartes ⚡ / 🔧", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller le précompilé", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\" LLAMA.CPP-prebuilt \"}", + "status": 400, + "out": { + "error": "ce moteur se gère depuis les cartes ⚡ / 🔧", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller sans nom", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"\"}", + "status": 404, + "out": { + "error": "backend introuvable", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller, corps illisible", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{", + "status": 404, + "out": { + "error": "backend introuvable", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller l'actif", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"Fork-A\"}", + "status": 409, + "out": { + "error": "backend utilisé par le modèle actif — bascule d'abord ce modèle sur un autre moteur", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-b", + "d backends/fork-b/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-b/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller par un chemin", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"../fork-b\"}", + "status": 200, + "out": { + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller un absent", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"fork-z\"}", + "status": 404, + "out": { + "error": "backend introuvable", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller un lien", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"lien\"}", + "status": 404, + "out": { + "error": "backend introuvable", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller un fichier", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"fichier\"}", + "status": 404, + "out": { + "error": "backend introuvable", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/vide", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "désinstaller un dossier sans binaire", + "method": "POST", + "path": "/api/llamacpp/uninstall-custom", + "body": "{\"name\":\"vide\"}", + "status": 200, + "out": { + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "dépôt cloné", + "git": [ + "init src", + "commit src 2024-01-02T03:04:05+00:00 premier état", + "clone src backends/llama.cpp" + ], + "files": { + "backends/llama.cpp/build/bin/llama-server": "#!/bin/sh\n" + }, + "config": { + "BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "behind": 0, + "bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "branch": "master", + "commit": "53ac21a", + "commit_date": "2024-01-02 03:04:05 +0000", + "commit_msg": "premier état", + "config_bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": true, + "installed": true, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "f backends/llama.cpp/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "amont avancé, pas encore vu", + "git": [ + "commit src 2024-02-03T04:05:06+00:00 & état" + ], + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "behind": 0, + "bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "branch": "master", + "commit": "53ac21a", + "commit_date": "2024-01-02 03:04:05 +0000", + "commit_msg": "premier état", + "config_bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": true, + "installed": true, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "f backends/llama.cpp/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "vérification git", + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "behind": 1, + "branch": "master", + "has_binary": true, + "local": "53ac21a", + "needs_rebuild": true, + "ok": true, + "remote": "2f78f13", + "remote_date": "2024-02-03 04:05:06 +0000", + "remote_msg": " & état" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "f backends/llama.cpp/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "retard connu", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "behind": 1, + "bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "branch": "master", + "commit": "53ac21a", + "commit_date": "2024-01-02 03:04:05 +0000", + "commit_msg": "premier état", + "config_bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": true, + "installed": true, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "f backends/llama.cpp/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "binaire Release", + "files": { + "backends/llama.cpp/build/bin/Release/llama-server": "#!/bin/sh\n", + "backends/llama.cpp/build/bin/llama-server": "-" + }, + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "behind": 1, + "branch": "master", + "has_binary": true, + "local": "53ac21a", + "needs_rebuild": true, + "ok": true, + "remote": "2f78f13", + "remote_date": "2024-02-03 04:05:06 +0000", + "remote_msg": " & état" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "f backends/llama.cpp/build/bin/Release/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "sans binaire", + "files": { + "backends/llama.cpp/build/bin/Release/llama-server": "-" + }, + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "behind": 1, + "branch": "master", + "has_binary": false, + "local": "53ac21a", + "needs_rebuild": true, + "ok": true, + "remote": "2f78f13", + "remote_date": "2024-02-03 04:05:06 +0000", + "remote_msg": " & état" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- premier état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "à jour, sans binaire", + "git": [ + "pull backends/llama.cpp" + ], + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "behind": 0, + "branch": "master", + "has_binary": false, + "local": "2f78f13", + "needs_rebuild": true, + "ok": true, + "remote": "2f78f13", + "remote_date": "2024-02-03 04:05:06 +0000", + "remote_msg": " & état" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "tête détachée", + "git": [ + "detach backends/llama.cpp" + ], + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "", + "branch": "HEAD", + "commit": "2f78f13", + "commit_date": "2024-02-03 04:05:06 +0000", + "commit_msg": " & état", + "config_bin": "{{HOME}}/backends/llama.cpp/build/bin/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": true, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "vérification, tête détachée", + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "behind": 0, + "branch": "master", + "has_binary": false, + "local": "2f78f13", + "needs_rebuild": true, + "ok": true, + "remote": "2f78f13", + "remote_date": "2024-02-03 04:05:06 +0000", + "remote_msg": " & état" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "origine perdue", + "git": [ + "remote-bad backends/llama.cpp" + ], + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "error": "git fetch a échoué : exit status 128", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "pas de dépôt", + "files": { + "backends/llama.cpp/.git": "-" + }, + "config": { + "BIN": "/nulle/part/llama-server" + }, + "method": "POST", + "path": "/api/llamacpp/check", + "status": 200, + "out": { + "error": "llama.cpp n'est pas installé", + "ok": false + }, + "after": { + "config/BIN": "/nulle/part/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "bascule fast", + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"fast\"}", + "status": 200, + "out": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server", + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "bascule opt sans build", + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"opt\"}", + "status": 400, + "out": { + "error": "cette version n'est pas installée", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "l backends/lien -> fork-b" + ] + }, + { + "name": "bascule opt", + "files": { + "backends/llama.cpp/build/llama-server": "#!/bin/sh\n" + }, + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"opt\"}", + "status": 200, + "out": { + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp/build/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "bascule opt depuis un fork", + "files": { + "backends/fork-a/build/llama-server": "#!/bin/sh\n" + }, + "config": { + "BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"opt\"}", + "status": 200, + "out": { + "bin": "{{HOME}}/backends/fork-a/build/bin/llama-server", + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "mode inconnu", + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"turbo\"}", + "status": 400, + "out": { + "error": "mode inconnu", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "mode absent", + "method": "POST", + "path": "/api/llamacpp/use", + "status": 400, + "out": { + "error": "mode inconnu", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "mode de travers", + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":1}", + "status": 400, + "out": { + "error": "mode inconnu", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "bascule pendant une optimisation", + "tune": true, + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"fast\"}", + "status": 409, + "out": { + "error": "optimisation en cours (loki tune) : le moteur est réservé aux essais — attends la fin ou annule-la", + "ok": false, + "tuning": true + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/bin", + "d backends/llama.cpp-prebuilt/llama-b100", + "d backends/llama.cpp-prebuilt/llama-b200", + "d backends/llama.cpp-prebuilt/llama-b200/build", + "d backends/llama.cpp-prebuilt/llama-b200/build/bin", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b100/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b200/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "fast sans précompilé", + "files": { + "backends/llama.cpp-prebuilt/": "-" + }, + "method": "POST", + "path": "/api/llamacpp/use", + "body": "{\"mode\":\"fast\"}", + "status": 400, + "out": { + "error": "cette version n'est pas installée", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/fork-a/build/bin/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "moteur téléchargé", + "files": { + "engine/server-cuda-b10450/llama-server": "#!/bin/sh\n" + }, + "config": { + "BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/engine/server-cuda-b10450/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": true, + "tag": "server-cuda-b10450" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "moteur de l'image", + "engine_env": " {{HOME}}/engine/server-cuda-b10450/llama-server ", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/engine/server-cuda-b10450/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": true, + "tag": "server-cuda-b10450" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": true, + "provided_bin": "{{HOME}}/engine/server-cuda-b10450/llama-server", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "moteur de l'image absent", + "engine_env": "{{HOME}}/image/llama-server", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/engine/server-cuda-b10450/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": true, + "tag": "server-cuda-b10450" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "moteur de l'image : un dossier", + "engine_env": "{{HOME}}/engine", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/engine/server-cuda-b10450/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": true, + "tag": "server-cuda-b10450" + }, + "in_use": false, + "installed": false, + "job": { + "exists": false + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release : CPU", + "engine_env": "", + "release": { + "status": 200, + "json": "{\"tag_name\":\"b300\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}", + "assets": { + "llama-b300-bin-ubuntu-x64.tar.gz": [ + { + "name": "llama-b300/", + "type": "dir", + "mode": 493 + }, + { + "name": "llama-b300/llama-server", + "type": "file", + "body": "#!/bin/sh\necho serveur\n", + "mode": 488 + }, + { + "name": "llama-b300/libggml.so.1.0", + "type": "file", + "body": "lib", + "mode": 420 + }, + { + "name": "llama-b300/libggml.so.1", + "type": "symlink", + "link": "libggml.so.1.0" + }, + { + "name": "llama-b300/libggml.so", + "type": "symlink", + "link": "absente.so" + }, + { + "name": "llama-b300/llama-cli", + "type": "hardlink", + "link": "llama-b300/llama-server" + }, + { + "name": "llama-b300/sous/doc.txt", + "type": "file", + "body": "doc", + "mode": 384 + } + ] + } + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "current": "", + "latest": "b300", + "ok": true, + "size_mb": 2, + "update": true, + "variant": "CPU (Linux x64)" + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release refusée", + "release": { + "status": 403, + "json": "{\"message\":\"rate limit\"}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "GitHub API : HTTP 403", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release sans tag", + "release": { + "status": 200, + "json": "{\"tag_name\":\"\",\"assets\":[]}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "release invalide (tag vide)", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release illisible", + "release": { + "status": 200, + "json": "{\"tag_name\":" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "unexpected EOF", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release vide", + "release": { + "status": 200, + "json": "" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "EOF", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release, tag de travers", + "release": { + "status": 200, + "json": "{\"tag_name\":5}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "json: cannot unmarshal number into Go struct field .tag_name of type string", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "release sans asset adapté", + "release": { + "status": 200, + "json": "{\"tag_name\":\"b301\",\"assets\":[{\"name\":\"llama-b301-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b301-bin-macos-arm64.zip\",\"size\":2500000}]}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "error": "aucun binaire précompilé adapté à cette machine dans la release officielle", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/engine/server-cuda-b10450/llama-server" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "installation", + "files": { + "backends/llama.cpp-prebuilt/VERSION": "b100 12.4 fmt2\n", + "backends/llama.cpp-prebuilt/autre/llama-server": "#!/bin/sh\n", + "backends/llama.cpp-prebuilt/llama-b100/llama-server": "#!/bin/sh\n", + "backends/llama.cpp-prebuilt/llama-b200/llama-server": "#!/bin/sh\n", + "backends/llama.cpp-prebuilt/llama-b30/llama-server": "#!/bin/sh\n" + }, + "release": { + "status": 200, + "json": "{\"tag_name\":\"b300\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}", + "assets": { + "llama-b300-bin-ubuntu-x64.tar.gz": [ + { + "name": "llama-b300/", + "type": "dir", + "mode": 493 + }, + { + "name": "llama-b300/llama-server", + "type": "file", + "body": "#!/bin/sh\necho serveur\n", + "mode": 488 + }, + { + "name": "llama-b300/libggml.so.1.0", + "type": "file", + "body": "lib", + "mode": 420 + }, + { + "name": "llama-b300/libggml.so.1", + "type": "symlink", + "link": "libggml.so.1.0" + }, + { + "name": "llama-b300/libggml.so", + "type": "symlink", + "link": "absente.so" + }, + { + "name": "llama-b300/llama-cli", + "type": "hardlink", + "link": "llama-b300/llama-server" + }, + { + "name": "llama-b300/sous/doc.txt", + "type": "file", + "body": "doc", + "mode": 384 + } + ] + } + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b300 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "ancienne version supprimée : llama-b100", + "ancienne version supprimée : llama-b200", + "ancienne version supprimée : llama-b30", + "binaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "statut après installation", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "new": "", + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": true, + "tag": "b300" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "release à jour", + "method": "POST", + "path": "/api/llamacpp/prebuilt/check", + "status": 200, + "out": { + "current": "b300", + "latest": "b300", + "ok": true, + "size_mb": 2, + "update": false, + "variant": "CPU (Linux x64)" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "lignes à partir de 3", + "method": "GET", + "path": "/api/llamacpp/job?from=3", + "status": 200, + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "ancienne version supprimée : llama-b100", + "ancienne version supprimée : llama-b200", + "ancienne version supprimée : llama-b30", + "binaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "lignes au-delà", + "method": "GET", + "path": "/api/llamacpp/job?from=99", + "status": 200, + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": null, + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "lignes, from négatif", + "method": "GET", + "path": "/api/llamacpp/job?from=-4", + "status": 200, + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b300 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "ancienne version supprimée : llama-b100", + "ancienne version supprimée : llama-b200", + "ancienne version supprimée : llama-b30", + "binaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "lignes, from illisible", + "method": "GET", + "path": "/api/llamacpp/job?from=abc", + "status": 200, + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b300 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "ancienne version supprimée : llama-b100", + "ancienne version supprimée : llama-b200", + "ancienne version supprimée : llama-b30", + "binaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "lignes, from démesuré", + "method": "GET", + "path": "/api/llamacpp/job?from=99999999999999999999", + "status": 200, + "out": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": null, + "new": "", + "next": 10, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nancienne version supprimée : llama-b100\nancienne version supprimée : llama-b200\nancienne version supprimée : llama-b30\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "déjà à jour", + "files": { + "backends/llama.cpp-prebuilt/llama-b250/x": "" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b300 — variant retenu : CPU (Linux x64)", + "déjà à jour (b300)", + "ancienne version supprimée : llama-b250", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 6, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\ndéjà à jour (b300)\nancienne version supprimée : llama-b250\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "ancien format : réextrait", + "files": { + "backends/llama.cpp-prebuilt/VERSION": "b300 \n" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b300 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "binaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)", + "BIN mis à jour", + "✓ binaires précompilés installés (b300)" + ], + "new": "", + "next": 7, + "old": "", + "phase": "binaires précompilés installés (b300)", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "pendant une optimisation", + "tune": true, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "status": 409, + "out": { + "error": "optimisation en cours (loki tune) : le moteur est réservé aux essais — attends la fin ou annule-la", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b300 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\nbinaire installé : {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server (release b300)\nBIN mis à jour\n✓ binaires précompilés installés (b300)\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"binaires précompilés installés (b300)\",\"compiled\":0,\"running\":false,\"error\":\"\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "GitHub refuse", + "release": { + "status": 403, + "json": "{}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "impossible d'interroger les releases llama.cpp : GitHub API : HTTP 403", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "✗ impossible d'interroger les releases llama.cpp : GitHub API : HTTP 403" + ], + "new": "", + "next": 2, + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\n✗ impossible d'interroger les releases llama.cpp : GitHub API : HTTP 403\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"impossible d'interroger les releases llama.cpp : GitHub API : HTTP 403\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "rien d'adapté", + "release": { + "status": 200, + "json": "{\"tag_name\":\"b302\",\"assets\":[{\"name\":\"llama-b302-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b302-bin-macos-arm64.zip\",\"size\":2500000}]}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "aucun binaire précompilé adapté à cette machine dans la release officielle", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "✗ aucun binaire précompilé adapté à cette machine dans la release officielle" + ], + "new": "", + "next": 2, + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\n✗ aucun binaire précompilé adapté à cette machine dans la release officielle\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"aucun binaire précompilé adapté à cette machine dans la release officielle\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "archive absente", + "release": { + "status": 200, + "json": "{\"tag_name\":\"b303\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}" + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "téléchargement de llama-b300-bin-ubuntu-x64.tar.gz : HTTP 404", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b303 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "✗ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz : HTTP 404" + ], + "new": "", + "next": 4, + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b303 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n✗ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz : HTTP 404\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"téléchargement de llama-b300-bin-ubuntu-x64.tar.gz : HTTP 404\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "archive piégée", + "release": { + "status": 200, + "json": "{\"tag_name\":\"b304\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}", + "assets": { + "llama-b300-bin-ubuntu-x64.tar.gz": [ + { + "name": "llama-b304/ok", + "type": "file", + "body": "x", + "mode": 420 + }, + { + "name": "../evasion", + "type": "file", + "body": "x", + "mode": 420 + } + ] + } + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "extraction de llama-b300-bin-ubuntu-x64.tar.gz : entrée d'archive suspecte : ../evasion", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b304 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "✗ extraction de llama-b300-bin-ubuntu-x64.tar.gz : entrée d'archive suspecte : ../evasion" + ], + "new": "", + "next": 5, + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b304 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ extraction de llama-b300-bin-ubuntu-x64.tar.gz : entrée d'archive suspecte : ../evasion\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"extraction de llama-b300-bin-ubuntu-x64.tar.gz : entrée d'archive suspecte : ../evasion\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/autre", + "d backends/llama.cpp-prebuilt/llama-b300", + "d backends/llama.cpp-prebuilt/llama-b300/sous", + "d backends/llama.cpp-prebuilt/llama-b304", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b300 fmt2\n", + "f backends/llama.cpp-prebuilt/autre/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/llama.cpp-prebuilt/llama-b300/libggml.so.1.0 -rw-r--r-- lib", + "f backends/llama.cpp-prebuilt/llama-b300/llama-server -rwxr-xr-x #!/bin/sh\necho serveur\n", + "f backends/llama.cpp-prebuilt/llama-b300/sous/doc.txt -rw------- doc", + "f backends/llama.cpp-prebuilt/llama-b304/ok -rw-r--r-- x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so -> absente.so", + "l backends/llama.cpp-prebuilt/llama-b300/libggml.so.1 -> libggml.so.1.0", + "l backends/llama.cpp-prebuilt/llama-b300/llama-cli -> {{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server" + ] + }, + { + "name": "archive sans serveur", + "files": { + "backends/llama.cpp-prebuilt/": "-" + }, + "release": { + "status": 200, + "json": "{\"tag_name\":\"b305\",\"assets\":[{\"name\":\"llama-b300-bin-macos-arm64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-macos-arm64.zip\",\"size\":2500000},{\"name\":\"cudart-llama-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/cudart-llama-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-win-cuda-12.4-x64.zip\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-win-cuda-12.4-x64.zip\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-rocm-7.0-x64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-vulkan-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-arm64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-arm64.tar.gz\",\"size\":2500000},{\"name\":\"llama-b300-bin-ubuntu-x64.tar.gz\",\"browser_download_url\":\"{{GH}}/dl/llama-b300-bin-ubuntu-x64.tar.gz\",\"size\":2500000}]}", + "assets": { + "llama-b300-bin-ubuntu-x64.tar.gz": [ + { + "name": "llama-b305/llama-cli", + "type": "file", + "body": "x", + "mode": 493 + } + ] + } + }, + "method": "POST", + "path": "/api/llamacpp/prebuilt", + "wait": true, + "status": 200, + "out": { + "ok": true + }, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt", + "exists": true, + "lines": [ + "▶ récupération de la dernière release llama.cpp…", + "release b305 — variant retenu : CPU (Linux x64)", + "▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…", + "▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…", + "✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt" + ], + "new": "", + "next": 5, + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "statut après échecs", + "method": "GET", + "path": "/api/llamacpp", + "status": 200, + "out": { + "backends_dir": "{{HOME}}/backends", + "bin": "{{HOME}}/backends/llama.cpp/build/llama-server", + "config_bin": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "engine": { + "dir": "{{HOME}}/engine", + "in_use": false, + "tag": "" + }, + "in_use": false, + "installed": false, + "job": { + "action": "prebuilt", + "compiled": 0, + "ended_at": "{{T}}", + "error": "archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt", + "exists": true, + "new": "", + "old": "", + "phase": "échec", + "running": false, + "started_at": "{{T}}" + }, + "plan": { + "arch": "", + "backend": "cpu", + "jobs": "{{JOBS}}" + }, + "prebuilt": { + "bin": "", + "dir": "{{HOME}}/backends/llama.cpp-prebuilt", + "in_use": false, + "tag": "b305" + }, + "provided": false, + "provided_bin": "", + "reco": { + "mode": "fast", + "why": "" + }, + "repo": "{{HOME}}/backends/llama.cpp" + }, + "after": { + "config/BIN": "{{HOME}}/backends/llama.cpp-prebuilt/llama-b300/llama-server", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU sans moteur", + "config": { + "BIN": "" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "error": "moteur introuvable — choisissez d'abord un moteur", + "ok": false + }, + "after": { + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU d'un moteur absent", + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"/nulle/part/llama-server\"}", + "status": 200, + "out": { + "error": "moteur introuvable — choisissez d'abord un moteur", + "ok": false + }, + "after": { + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : pas un llama-server", + "files": { + "outils/autre": "#!/bin/sh\n" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/outils/autre\"}", + "status": 400, + "out": { + "error": "ce chemin n'est pas un llama-server", + "ok": false + }, + "after": { + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU listés", + "machine": "nvidia", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\n[ \"$1\" = --list-devices ] || exit 7\necho 'Available devices:'\necho \" CUDA0: NVIDIA GeForce RTX 3090 (0 MiB, 0 MiB free)\"\necho \" CUDA1: Carte B (8192 MiB, 8000 MiB free)\"\necho \" Vulkan0: NVIDIA GeForce RTX 3090 (24576 MiB, 20000 MiB free)\"\necho \" CUDA2: ordre ${CUDA_DEVICE_ORDER:-aucun} cvd ${CUDA_VISIBLE_DEVICES:-aucun} (1 MiB, 1 MiB free)\" >&2\n" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\" {{HOME}}/gpu/LLAMA-SERVER \"}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "link": { + "gen": 1, + "gen_max": 4, + "mem_clock_mhz": 9751, + "width": 16, + "width_max": 16 + }, + "name": "NVIDIA GeForce RTX 3090", + "total_mib": 24576 + }, + { + "free_mib": 8000, + "id": "CUDA1", + "link": { + "gen": 0, + "gen_max": 3, + "mem_clock_mhz": 7001, + "width": 8, + "width_max": 16 + }, + "name": "Carte B", + "total_mib": 8192 + }, + { + "free_mib": 20000, + "id": "Vulkan0", + "name": "NVIDIA GeForce RTX 3090", + "total_mib": 24576 + }, + { + "free_mib": 1, + "id": "CUDA2", + "name": "ordre aucun cvd aucun", + "total_mib": 1 + } + ], + "ok": true + }, + "after": { + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU en cache", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: changé (1 MiB, 1 MiB free)'\n" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/LLAMA-SERVER\"}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "link": { + "gen": 1, + "gen_max": 4, + "mem_clock_mhz": 9751, + "width": 16, + "width_max": 16 + }, + "name": "NVIDIA GeForce RTX 3090", + "total_mib": 24576 + }, + { + "free_mib": 8000, + "id": "CUDA1", + "link": { + "gen": 0, + "gen_max": 3, + "mem_clock_mhz": 7001, + "width": 8, + "width_max": 16 + }, + "name": "Carte B", + "total_mib": 8192 + }, + { + "free_mib": 20000, + "id": "Vulkan0", + "name": "NVIDIA GeForce RTX 3090", + "total_mib": 24576 + }, + { + "free_mib": 1, + "id": "CUDA2", + "name": "ordre aucun cvd aucun", + "total_mib": 1 + } + ], + "ok": true + }, + "after": { + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU filtrés", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho \" CUDA0: ordre $CUDA_DEVICE_ORDER cvd $CUDA_VISIBLE_DEVICES (10 MiB, 5 MiB free)\"\n" + }, + "config": { + "BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "CUDA_VISIBLE_DEVICES": "1,0" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"\"}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 5, + "id": "CUDA0", + "name": "ordre PCI_BUS_ID cvd 1,0", + "total_mib": 10 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : mémoire nulle non figée", + "machine": "nu", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Saturée (0 MiB, 0 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "0" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "name": "Saturée", + "total_mib": 0 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 0\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : relu, pas en cache", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Saturée (100 MiB, 0 MiB free)'\n" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "name": "Saturée", + "total_mib": 100 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : moteur planté, repli disque", + "files": { + "gpu/llama-server": "#!/bin/sh\necho ' CUDA0: partielle (1 MiB, 1 MiB free)'\nexit 3\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "1,0" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/llama-server\"}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 1, + "id": "CUDA0", + "name": "partielle", + "total_mib": 1 + } + ], + "ok": true, + "stale": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : planté, partiel", + "config": { + "CUDA_VISIBLE_DEVICES": "2" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/llama-server\"}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 1, + "id": "CUDA0", + "name": "partielle", + "total_mib": 1 + } + ], + "ok": true, + "stale": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : planté, rien", + "files": { + "gpu/llama-server": "#!/bin/sh\necho 'CUDA error: out of memory'\nexit 4\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "3" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/llama-server\"}", + "status": 200, + "out": { + "error": "le moteur n'a pas répondu : exit status 4", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : tué", + "files": { + "gpu/llama-server": "#!/bin/sh\nkill -9 $$\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "4" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/llama-server\"}", + "status": 200, + "out": { + "error": "le moteur n'a pas répondu : signal: killed", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : non exécutable", + "files": { + "gpu/llama-server": "pas un script" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "5" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":\"{{HOME}}/gpu/llama-server\"}", + "status": 200, + "out": { + "error": "le moteur n'a pas répondu : fork/exec {{HOME}}/gpu/llama-server: permission denied", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : corps illisible, BIN de la config", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Lue (2 MiB, 1 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "6" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{\"bin\":", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 1, + "id": "CUDA0", + "name": "Lue", + "total_mib": 2 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : pilote ancien", + "machine": "arch-ancienne", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Vieille carte (0 MiB, 0 MiB free)'\necho ' CUDA1: Vieille carte (0 MiB, 0 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "7" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "name": "Vieille carte", + "total_mib": 4096 + }, + { + "free_mib": 0, + "id": "CUDA1", + "name": "Vieille carte", + "total_mib": 4096 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00007\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n },\n {\n \"free_mib\": 0,\n \"id\": \"CUDA1\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : deux cartes de même nom", + "machine": "nvidia", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte B (0 MiB, 0 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "8" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "link": { + "gen": 0, + "gen_max": 3, + "mem_clock_mhz": 7001, + "width": 8, + "width_max": 16 + }, + "name": "Carte B", + "total_mib": 8192 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00007\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n },\n {\n \"free_mib\": 0,\n \"id\": \"CUDA1\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00008\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : lu à vide, gardé sur disque", + "machine": "nu", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Pleine (0 MiB, 0 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "9" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "name": "Pleine", + "total_mib": 0 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00007\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n },\n {\n \"free_mib\": 0,\n \"id\": \"CUDA1\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00008\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00009\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Pleine\",\n \"total_mib\": 0\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : cartes jumelles chez nvidia-smi", + "machine": "nvidia-jumelles", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte B (0 MiB, 0 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "10" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 0, + "id": "CUDA0", + "name": "Carte B", + "total_mib": 0 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u000010\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Carte B\",\n \"total_mib\": 0\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00007\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n },\n {\n \"free_mib\": 0,\n \"id\": \"CUDA1\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00008\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00009\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Pleine\",\n \"total_mib\": 0\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : liaison sans génération connue", + "machine": "liaison-partielle", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: Carte P (4096 MiB, 4000 MiB free)'\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "11" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 4000, + "id": "CUDA0", + "link": { + "gen": 0, + "gen_max": 0, + "mem_clock_mhz": 5001, + "width": 4, + "width_max": 8 + }, + "name": "Carte P", + "total_mib": 4096 + } + ], + "ok": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\n \"{{HOME}}/gpu/LLAMA-SERVER\\u0000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 1,\n \"gen_max\": 4,\n \"mem_clock_mhz\": 9751,\n \"width\": 16,\n \"width_max\": 16\n },\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 8000,\n \"id\": \"CUDA1\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n },\n {\n \"free_mib\": 20000,\n \"id\": \"Vulkan0\",\n \"name\": \"NVIDIA GeForce RTX 3090\",\n \"total_mib\": 24576\n },\n {\n \"free_mib\": 1,\n \"id\": \"CUDA2\",\n \"name\": \"ordre aucun cvd aucun\",\n \"total_mib\": 1\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00000\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Saturée\",\n \"total_mib\": 100\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00001,0\": [\n {\n \"free_mib\": 5,\n \"id\": \"CUDA0\",\n \"name\": \"ordre PCI_BUS_ID cvd 1,0\",\n \"total_mib\": 10\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u000010\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Carte B\",\n \"total_mib\": 0\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u000011\": [\n {\n \"free_mib\": 4000,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 0,\n \"mem_clock_mhz\": 5001,\n \"width\": 4,\n \"width_max\": 8\n },\n \"name\": \"Carte P\",\n \"total_mib\": 4096\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00006\": [\n {\n \"free_mib\": 1,\n \"id\": \"CUDA0\",\n \"name\": \"Lue\",\n \"total_mib\": 2\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00007\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n },\n {\n \"free_mib\": 0,\n \"id\": \"CUDA1\",\n \"name\": \"Vieille carte\",\n \"total_mib\": 4096\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00008\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"link\": {\n \"gen\": 0,\n \"gen_max\": 3,\n \"mem_clock_mhz\": 7001,\n \"width\": 8,\n \"width_max\": 16\n },\n \"name\": \"Carte B\",\n \"total_mib\": 8192\n }\n ],\n \"{{HOME}}/gpu/LLAMA-SERVER\\u00009\": [\n {\n \"free_mib\": 0,\n \"id\": \"CUDA0\",\n \"name\": \"Pleine\",\n \"total_mib\": 0\n }\n ]\n}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : liste vide sur le disque, pas de repli", + "machine": "nu", + "files": { + "devices.json": "{\"{{HOME}}/gpu/LLAMA-SERVER\\u0000vide\": []}", + "gpu/LLAMA-SERVER": "#!/bin/sh\nexit 3\n" + }, + "config": { + "CUDA_VISIBLE_DEVICES": "vide" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "error": "le moteur n'a pas répondu : exit status 3", + "ok": false + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\"{{HOME}}/gpu/LLAMA-SERVER\\u0000vide\": []}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + }, + { + "name": "GPU : planté, repli sur le disque", + "files": { + "gpu/LLAMA-SERVER": "#!/bin/sh\necho ' CUDA0: partielle (1 MiB, 1 MiB free)'\nexit 3\n" + }, + "method": "POST", + "path": "/api/backends/devices", + "body": "{}", + "status": 200, + "out": { + "devices": [ + { + "free_mib": 1, + "id": "CUDA0", + "name": "partielle", + "total_mib": 1 + } + ], + "ok": true, + "stale": true + }, + "after": { + "config/BIN": "{{HOME}}/gpu/LLAMA-SERVER", + "devices.json": "{\"{{HOME}}/gpu/LLAMA-SERVER\\u0000vide\": []}", + "loki-build.log": "▶ récupération de la dernière release llama.cpp…\nrelease b305 — variant retenu : CPU (Linux x64)\n▶ téléchargement de llama-b300-bin-ubuntu-x64.tar.gz (2 Mo)…\n▶ extraction de llama-b300-bin-ubuntu-x64.tar.gz…\n✗ archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\n", + "state/build_job": "{\"action\":\"prebuilt\",\"phase\":\"échec\",\"compiled\":0,\"running\":false,\"error\":\"archives extraites mais llama-server introuvable sous {{HOME}}/backends/llama.cpp-prebuilt\",\"started_at\":\"{{T}}\",\"ended_at\":\"{{T}}\",\"old\":\"\",\"new\":\"\"}" + }, + "tree": [ + "d backends", + "d backends/.cache", + "d backends/fork-a", + "d backends/fork-a/build", + "d backends/fork-a/build/bin", + "d backends/fork-c", + "d backends/fork-c/build", + "d backends/fork-c/build/bin", + "d backends/fork-c/build/bin/llama-server", + "d backends/llama.cpp", + "d backends/llama.cpp-prebuilt", + "d backends/llama.cpp-prebuilt/llama-b305", + "d backends/llama.cpp/build", + "d backends/llama.cpp/build/bin", + "d backends/llama.cpp/build/bin/Release", + "d engine", + "d engine/server-cuda-b10450", + "f backends/.cache/llama-server -rw-r--r-- x", + "f backends/fichier -rw-r--r-- x", + "f backends/fork-a/CMakeLists.txt -rw-r--r-- ", + "f backends/fork-a/build/bin/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-a/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f backends/fork-c/llama-server.exe -rw-r--r-- x", + "f backends/llama.cpp-prebuilt/VERSION -rw-r--r-- b305 fmt2\n", + "f backends/llama.cpp-prebuilt/llama-b305/llama-cli -rwxr-xr-x x", + "f backends/llama.cpp/README -rw-r--r-- & état", + "f backends/llama.cpp/build/llama-server -rwxr-xr-x #!/bin/sh\n", + "f engine/server-cuda-b10450/llama-server -rwxr-xr-x #!/bin/sh\n", + "l backends/lien -> fork-b" + ] + } + ] +} diff --git a/rust/loki-rs/tests/proxy.rs b/rust/loki-rs/tests/proxy.rs index 7ce058c..8fdda9d 100644 --- a/rust/loki-rs/tests/proxy.rs +++ b/rust/loki-rs/tests/proxy.rs @@ -112,6 +112,7 @@ async fn facade(backend: SocketAddr) -> (SocketAddr, oneshot::Sender<()>) { projects: false, mcp: None, update: false, + backends: None, }; tokio::spawn(loki_rs::proxy::serve(l, cfg, async move { let _ = rx.await;