mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 22:48:11 +02:00
Lot 34 : bloc projet figé (PROJ_SNAPSHOT) dans le tour de la façade
PROJ_SNAPSHOT était le dernier réglage qui gardait la conversation au Go : la façade la tient désormais dans tous les cas (LOKI_CHAT=go reste la porte de sortie). facadeChatBlocker et la décision prise une fois par processus disparaissent. Go (facade_projsnap.go) : - /internal/v1/turn/view, avec la clé et l'agent : tête du tour portant le bloc figé (ou le vivant à rafraîchir), préambule sans date ni dossier, et la décision projsnap (rafraîchir, mise à jour à poser, instantané à ranger, clé et système du tour) ; dry pour le préchauffage ; - /internal/v1/turn/projsnap/refresh : bloc vivant et instantané qu'il devient, pour une compaction en plein tour. Rust : - ChatService::assemble_turn, partagé par le tour et la relance du builder : instantané rangé avec la discussion, mise à jour posée en tête du dernier message utilisateur (prependCtxUpdate), historique nettoyé au rafraîchissement ; - TurnHost::project_refresh après une compaction ou une réduction en plein tour (replaceProjectHead) ; l'instantané posé devient celui de la discussion ; - le préchauffage demande la vue en dry et garde les mises à jour tant que le bloc n'est pas rafraîchi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
19 files changed
+1063
-171
No files matched your search
@@ -0,0 +1,94 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// facade_projsnap.go — PROJ_SNAPSHOT pour le tour tenu par la façade (lot 34
|
||||
// de la migration). La façade range l'instantané avec la discussion (il est
|
||||
// persisté avec elle, champ proj_snap) et pose les <context_update> dans son
|
||||
// historique ; le Go, qui lit le contexte du projet (description, index
|
||||
// mémoire, trackers, consignes du dépôt, date et dossier de travail), décide :
|
||||
//
|
||||
// - /internal/v1/turn/view, avec la clé et l'agent : la tête du tour porte
|
||||
// le bloc figé (ou le vivant s'il faut rafraîchir), et projsnap dit quoi
|
||||
// faire de la discussion — rafraîchir (instantané neuf, blocs retirés de
|
||||
// l'historique) ou poser une mise à jour en tête du dernier message
|
||||
// utilisateur. dry : la même décision pour le préchauffage, sans rien
|
||||
// rendre à ranger ;
|
||||
// - /internal/v1/turn/projsnap/refresh : une compaction ou une réduction
|
||||
// réécrit l'historique en plein tour, le bloc vivant remplace le figé et
|
||||
// devient l'instantané du tour suivant.
|
||||
|
||||
// projSnapView : les pièces de turnView avec la clé (assembleTurn, chemin
|
||||
// PROJ_SNAPSHOT). snap : l'instantané de la discussion (nil : aucun).
|
||||
func projSnapView(caps Caps, snap *projSnapshot, dry bool) map[string]any {
|
||||
cfg := ReadConfig()
|
||||
// Date et dossier de travail : dans le bloc, plus dans le système.
|
||||
caps.envInCtx = true
|
||||
asOf := projSnapNow()
|
||||
live := projSnapCapture(caps, asOf)
|
||||
key := projSnapKey(caps, cfg)
|
||||
tools := EnabledTools(caps)
|
||||
if tools == nil {
|
||||
tools = []Tool{}
|
||||
}
|
||||
head := []Message{}
|
||||
if sp := readSysPrompt(); sp != "" {
|
||||
head = append(head, Message{Role: "system", Content: sp})
|
||||
}
|
||||
sysHash := projSnapSysHash(InjectSkills(append([]Message(nil), head...), caps, tools), tools)
|
||||
refresh, delta, tok := projSnapDecide(snap, live, key, sysHash, asOf)
|
||||
block := live.msgs
|
||||
if !refresh {
|
||||
block = snap.Msgs
|
||||
}
|
||||
out := map[string]any{"refresh": refresh, "key": key, "sys_hash": sysHash}
|
||||
if !dry {
|
||||
switch {
|
||||
case refresh:
|
||||
out["snap"] = newProjSnapshot(live, key, sysHash)
|
||||
case delta != "":
|
||||
// Rangé par la façade seulement si la mise à jour a trouvé un
|
||||
// message utilisateur où se poser (projSnapApplyLocked).
|
||||
next := *snap
|
||||
next.State = live.state
|
||||
next.DeltaTok += tok
|
||||
out["snap"] = &next
|
||||
out["delta"] = delta
|
||||
default:
|
||||
out["snap"] = snap
|
||||
}
|
||||
}
|
||||
return map[string]any{
|
||||
"head": append(head, block...),
|
||||
"prefix": injectPrefix(caps, tools),
|
||||
"tools": tools,
|
||||
"projsnap": out,
|
||||
}
|
||||
}
|
||||
|
||||
// handleInternalTurnProjSnapRefresh : POST {"caps","key","sys_hash"} →
|
||||
// {"block":[…],"snap":{…}} — le bloc vivant et l'instantané qu'il devient
|
||||
// (projSnapTurn.refresh).
|
||||
func handleInternalTurnProjSnapRefresh(w http.ResponseWriter, r *http.Request) {
|
||||
var in struct {
|
||||
Caps Caps `json:"caps"`
|
||||
Key string `json:"key"`
|
||||
SysHash string `json:"sys_hash"`
|
||||
}
|
||||
if !readInternalJSON(w, r, &in) {
|
||||
return
|
||||
}
|
||||
caps := in.Caps
|
||||
caps.envInCtx = true
|
||||
live := projSnapCapture(caps, projSnapNow())
|
||||
block := live.msgs
|
||||
if block == nil {
|
||||
block = []Message{}
|
||||
}
|
||||
sendJSON(w, http.StatusOK, map[string]any{
|
||||
"block": block,
|
||||
"snap": newProjSnapshot(live, in.Key, in.SysHash),
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user