nub/internal/session/node.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

67 lines
1.8 KiB
Go

// Package session enthält das Baum-Modell der Konversation (E-03) und dessen
// Persistenz als Append-only JSONL (Abschnitt 4.5).
package session
import (
"time"
"github.com/oklog/ulid/v2"
"nub/internal/llm"
)
type NodeKind string
const (
NodeMessage NodeKind = "message"
NodeSummary NodeKind = "summary"
)
type Node struct {
ID string `json:"id"`
ParentID string `json:"parent_id"` // "" = Wurzel
Kind NodeKind `json:"kind"`
Message llm.Message `json:"message"`
Replaces []string `json:"replaces,omitempty"` // nur bei NodeSummary
Meta NodeMeta `json:"meta"`
}
type NodeMeta struct {
Model string `json:"model,omitempty"`
Usage llm.Usage `json:"usage"`
CreatedAt time.Time `json:"created_at"`
Label string `json:"label,omitempty"`
Bookmark bool `json:"bookmark,omitempty"`
}
// NewNode erzeugt einen neuen Message-Node mit frischer ULID. parentID ist
// typischerweise der aktuelle Head.
func NewNode(parentID string, msg llm.Message, meta NodeMeta) *Node {
if meta.CreatedAt.IsZero() {
meta.CreatedAt = time.Now()
}
return &Node{
ID: ulid.Make().String(),
ParentID: parentID,
Kind: NodeMessage,
Message: msg,
Meta: meta,
}
}
// NewSummaryNode erzeugt einen Summary-Node, der die Nodes in replaces aus
// dem aktiven Kontext ersetzt (E-08). Die ersetzten Nodes bleiben im Baum
// erhalten — kein destruktives Löschen, Rewind auf sie funktioniert weiter.
func NewSummaryNode(parentID, text string, replaces []string, meta NodeMeta) *Node {
if meta.CreatedAt.IsZero() {
meta.CreatedAt = time.Now()
}
return &Node{
ID: ulid.Make().String(),
ParentID: parentID,
Kind: NodeSummary,
Message: llm.Message{Role: llm.RoleUser, Content: []llm.Block{{Kind: llm.KindText, Text: text}}},
Replaces: replaces,
Meta: meta,
}
}