mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 14:08:11 +02:00
Ajoute jean link : acces distant via le relais ajean.link
- nouvelle commande `jean link <token>` (link.go) : connexion sortante WebSocket + yamux vers le relais, sert l'UI web Jean ET l'endpoint compatible OpenAI (/v1) a travers le tunnel, avec injection des cles locales, keepalive et reconnexion automatique. - web.go : extraction de newWebMux() pour reutiliser le routeur HTTP cote `jean link` sans repasser par un ecouteur TCP local. - ui/index.html : base d'URL relative (API_BASE) + script marked relatif. - main.go : cablage de la commande `link` + aide. - README : section acces distant (ajean.link) + commande link. - .gitignore : secrets runtime (.web_key/.link_token/.link_machine). Inclut aussi les evolutions en cours du coeur de jean (llm.go, skills.go, tools.go, chat.go).
This commit is contained in:
1 parent
6ea2e91810
commit
e606206d90
12 files changed
+724
-91
No files matched your search
@@ -28,6 +28,34 @@ func cmdWeb(args []string) error {
|
||||
}
|
||||
port = n
|
||||
}
|
||||
mux := newWebMux()
|
||||
addr := fmt.Sprintf("0.0.0.0:%d", port)
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
// Port occupé : on identifie le process qui le tient et on propose de
|
||||
// le terminer pour relancer à sa place.
|
||||
if !resolvePortConflict(port) {
|
||||
return err
|
||||
}
|
||||
if ln, err = net.Listen("tcp", addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fmt.Printf("[jean web] http://%s (Ctrl-C pour arrêter)\n", addr)
|
||||
if readWebKey() == "" {
|
||||
fmt.Printf("%s API de pilotage NON protégée (aucune clé). Avant de l'exposer sur internet :\n", yellow("[!]"))
|
||||
fmt.Printf(" %s\n", bold("jean set-web-key"))
|
||||
} else {
|
||||
fmt.Printf("%s API protégée par clé (Authorization: Bearer …)\n", green("[ok]"))
|
||||
}
|
||||
return http.Serve(ln, mux)
|
||||
}
|
||||
|
||||
// newWebMux construit le routeur HTTP de l'UI web. Extrait de cmdWeb pour être
|
||||
// réutilisé par `jean link`, qui sert ce même mux à travers le tunnel sans
|
||||
// repasser par un écouteur TCP local.
|
||||
func newWebMux() *http.ServeMux {
|
||||
mux := http.NewServeMux()
|
||||
// Pages publiques : le HTML et le JS ne contiennent aucun secret. Toute la
|
||||
// donnée et toutes les actions passent par /api/* qui, lui, exige la clé.
|
||||
@@ -67,27 +95,7 @@ func cmdWeb(args []string) error {
|
||||
api("/api/bench", handleBench)
|
||||
api("/api/bench/last", handleBenchLast)
|
||||
api("/api/chat", handleChat)
|
||||
addr := fmt.Sprintf("0.0.0.0:%d", port)
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
// Port occupé : on identifie le process qui le tient et on propose de
|
||||
// le terminer pour relancer à sa place.
|
||||
if !resolvePortConflict(port) {
|
||||
return err
|
||||
}
|
||||
if ln, err = net.Listen("tcp", addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fmt.Printf("[jean web] http://%s (Ctrl-C pour arrêter)\n", addr)
|
||||
if readWebKey() == "" {
|
||||
fmt.Printf("%s API de pilotage NON protégée (aucune clé). Avant de l'exposer sur internet :\n", yellow("[!]"))
|
||||
fmt.Printf(" %s\n", bold("jean set-web-key"))
|
||||
} else {
|
||||
fmt.Printf("%s API protégée par clé (Authorization: Bearer …)\n", green("[ok]"))
|
||||
}
|
||||
return http.Serve(ln, mux)
|
||||
return mux
|
||||
}
|
||||
|
||||
// resolvePortConflict identifies the process listening on `port`, asks the user
|
||||
@@ -200,11 +208,18 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
if active {
|
||||
health = healthCheck()
|
||||
}
|
||||
ctx := 32768
|
||||
if v := ReadConfig()["CTX"]; v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
||||
ctx = n
|
||||
}
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{
|
||||
"state": state,
|
||||
"active": active,
|
||||
"health": health,
|
||||
"port": LLMPort(),
|
||||
"ctx": ctx,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -584,7 +599,7 @@ func handleChat(w http.ResponseWriter, r *http.Request) {
|
||||
return true
|
||||
}
|
||||
if ev.ToolUsed != nil {
|
||||
emit(map[string]any{"tool_used": map[string]any{"name": ev.ToolUsed.Name, "label": ev.ToolUsed.Label}})
|
||||
emit(map[string]any{"tool_used": map[string]any{"name": ev.ToolUsed.Name, "label": ev.ToolUsed.Label, "result": ev.ToolUsed.Result, "done": ev.ToolUsed.Done, "typing": ev.ToolUsed.Typing}})
|
||||
return true
|
||||
}
|
||||
if ev.Stats != nil {
|
||||
|
||||
Reference in new issue
Block a user