v0.2.2 : mise a jour de securite — boite noire E2E & relais aveugle

- Chiffrement E2E du chat navigateur<->agent (e2e.go) : le relais ne voit
  que de l'opaque, ancre par empreinte X25519 confirmee au `jean link`.
- `jean link` refuse desormais tout chat en clair via le tunnel (403) ;
  seul /api/e2e/chat porte du contenu. Endpoint OpenAI clair desactive par
  defaut (JEAN_LINK_ALLOW_OAI=1 pour le reactiver).
- Le portail web n'est plus servi par le relais : code livre par une origine
  hors de son controle, le relais devient un pur tube aveugle.
This commit is contained in:
nathaninline committed 2026-06-23 19:45:17 +02:00
1 parent ca5d3f9197
commit a8a016c1b8
11 files changed
+403 -62

No files matched your search

+35 -14
View File
@@ -3,6 +3,7 @@ package main
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
@@ -81,17 +82,37 @@ func runShellTool() Tool {
}
}
// InjectSkills prepends context system messages to msgs: the machine briefing
// (when machine access is enabled) and the lightweight skills directory (when
// skills are enabled). Merges with an existing system message if present.
func InjectSkills(msgs []Message) []Message {
// Caps are the per-request capabilities (tool access) for a chat turn. They let
// a caller (e.g. an ajean.link agent with its own tools/skills toggles) scope
// what the model can do for this conversation, instead of always inheriting the
// machine's global config. Use globalCaps() to fall back to the global config.
type Caps struct {
Tools bool
Skills bool
}
// globalCaps reads the machine-wide config — the default when a request doesn't
// specify its own capabilities.
func globalCaps() Caps {
return Caps{Tools: toolsEnabled(), Skills: skillsEnabled()}
}
// InjectSkills prepends context system messages to msgs: the decisive-agent
// preamble + machine briefing (when tools are enabled) and the lightweight
// skills directory (when skills are enabled). Merges with an existing system
// message if present.
func InjectSkills(msgs []Message, caps Caps) []Message {
var parts []string
// Always-on decisive-agent preamble (anti-loop). See baseSystemPrompt.
parts = append(parts, baseSystemPrompt())
if mp := machineSystemPrompt(); mp != "" {
// Decisive-agent preamble (anti-loop) — only when the model actually has
// tools, otherwise it nudges a plain chat model to "call tools" it doesn't
// have, which leaks malformed tool-call text into the answer.
if bp := baseSystemPrompt(caps); bp != "" {
parts = append(parts, bp)
}
if mp := machineSystemPrompt(caps); mp != "" {
parts = append(parts, mp)
}
if sp := skillsSystemPrompt(); sp != "" {
if sp := skillsSystemPrompt(caps); sp != "" {
parts = append(parts, sp)
}
if len(parts) == 0 {
@@ -107,12 +128,12 @@ func InjectSkills(msgs []Message) []Message {
}
// EnabledTools returns the tools to advertise on the next inference call.
func EnabledTools() []Tool {
func EnabledTools(caps Caps) []Tool {
tools := []Tool{}
if skillsEnabled() {
if caps.Skills {
tools = append(tools, skillTool())
}
if toolsEnabled() {
if caps.Tools {
tools = append(tools, runShellTool())
}
return tools
@@ -223,8 +244,8 @@ type streamChunk struct {
// and call /v1/chat/completions again — up to 8 iterations as a safety cap.
const thinkClose = "</think>"
func runChat(messages []Message, temperature float64, cb ChatCallback) error {
tools := EnabledTools()
func runChat(ctx context.Context, messages []Message, temperature float64, caps Caps, cb ChatCallback) error {
tools := EnabledTools(caps)
// Some backends (vanilla llama.cpp builds) don't populate `reasoning_content`
// in streaming mode: the model's <think> block (opened by the chat template)
// arrives inline in `content`, terminated by a literal </think>. When
@@ -257,7 +278,7 @@ func runChat(messages []Message, temperature float64, cb ChatCallback) error {
}
body, _ := json.Marshal(payload)
url := fmt.Sprintf("http://localhost:%d/v1/chat/completions", LLMPort())
req, err := http.NewRequest("POST", url, bytes.NewReader(body))
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
if err != nil {
return err
}