Added code for backend glue

This commit is contained in:
2025-10-13 19:20:24 -04:00
parent 692b069b5b
commit 29a451ab58
25 changed files with 1063 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
package glue
import (
"context"
"mind/internal/models"
)
type ForkReq struct { ConversationID int64; Name string; HeadNodeID int64 }
func (g *Glue) ForkBranch(ctx context.Context, fr ForkReq) (models.Branch, error) {
return g.repo.CreateOrGetBranch(ctx, fr.ConversationID, fr.Name, fr.HeadNodeID)
}

View File

@@ -0,0 +1,39 @@
package glue
import (
"context"
)
type CompletionReq struct {
ConversationID int64 `json:"conversation_id"`
BranchName string `json:"branch"`
Prompt string `json:"prompt"`
}
type CompletionResp struct {
PromptNodeID int64 `json:"prompt_node_id"`
AnswerNodeID int64 `json:"answer_node_id"`
Answer string `json:"answer"`
}
// For v0 we stub the answer as a simple echo with a prefix.
func (g *Glue) AppendCompletion(ctx context.Context, req CompletionReq) (CompletionResp, error) {
b, err := g.repo.GetBranch(ctx, req.ConversationID, req.BranchName)
if err != nil { return CompletionResp{}, err }
// 1) create user prompt node
promptID, err := g.repo.CreateNode(ctx, req.ConversationID, "user", req.Prompt)
if err != nil { return CompletionResp{}, err }
if err := g.repo.Link(ctx, b.HeadNodeID, promptID); err != nil { return CompletionResp{}, err }
// 2) create assistant answer node (stub)
answerText := "(stub) You said: " + req.Prompt
answerID, err := g.repo.CreateNode(ctx, req.ConversationID, "assistant", answerText)
if err != nil { return CompletionResp{}, err }
if err := g.repo.Link(ctx, promptID, answerID); err != nil { return CompletionResp{}, err }
// 3) move branch head
if err := g.repo.MoveBranchHead(ctx, b.ID, answerID); err != nil { return CompletionResp{}, err }
return CompletionResp{PromptNodeID: promptID, AnswerNodeID: answerID, Answer: answerText}, nil
}

View File

@@ -0,0 +1,19 @@
package glue
import (
"context"
"mind/internal/db"
"mind/internal/models"
)
type Glue struct { repo *db.Repo }
func NewGlue(r *db.Repo) *Glue { return &Glue{repo: r} }
func (g *Glue) CreateConversation(ctx context.Context, ownerID int64, title string) (int64, error) {
return g.repo.CreateConversation(ctx, ownerID, title)
}
func (g *Glue) ListConversations(ctx context.Context, ownerID int64) ([]models.Conversation, error) {
return g.repo.ListConversations(ctx, ownerID)
}

View File

@@ -0,0 +1,41 @@
package glue
import (
"context"
"mind/internal/models"
)
type Linearized struct {
Nodes []models.Node `json:"nodes"`
Text string `json:"text"`
}
func (g *Glue) LinearizeByBranch(ctx context.Context, convID int64, branchName string) (Linearized, error) {
b, err := g.repo.GetBranch(ctx, convID, branchName)
if err != nil { return Linearized{}, err }
return g.linearizeFromHead(ctx, b.HeadNodeID)
}
func (g *Glue) linearizeFromHead(ctx context.Context, head int64) (Linearized, error) {
var seq []models.Node
// Walk parents by latest-created parent until none
curID := head
for {
n, err := g.repo.GetNode(ctx, curID)
if err != nil { return Linearized{}, err }
seq = append(seq, n)
p, ok, err := g.repo.LatestParent(ctx, curID)
if err != nil { return Linearized{}, err }
if !ok { break }
curID = p.ID
}
// Reverse seq to root→head, and stitch text
for i, j := 0, len(seq)-1; i < j; i, j = i+1, j-1 { seq[i], seq[j] = seq[j], seq[i] }
var txt string
for _, n := range seq {
role := "[user]"
if n.AuthorKind == "assistant" { role = "[assistant]" }
txt += role + "\n" + n.Content + "\n\n"
}
return Linearized{Nodes: seq, Text: txt}, nil
}