repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

2.8 KB · 108 lines · Go Raw History
  1// The memory overlay's endpoints.
  2//
  3// JSON rather than pages, because this lives in a panel over the conversation
  4// and navigating away from a thread to delete a fact is a worse trade than the
  5// handful of endpoints here.
  6package main
  7
  8import (
  9	"context"
 10	"encoding/json"
 11	"net/http"
 12	"strconv"
 13	"strings"
 14	"time"
 15)
 16
 17type memoryView struct {
 18	Facts   []Fact      `json:"facts"`
 19	Note    string      `json:"note,omitempty"`
 20	Problem string      `json:"problem,omitempty"`
 21	Applied []memChange `json:"applied,omitempty"`
 22}
 23
 24func (s *site) memoryList(w http.ResponseWriter, r *http.Request) {
 25	facts, err := s.store.Facts()
 26	if err != nil {
 27		http.Error(w, err.Error(), 500)
 28		return
 29	}
 30	writeJSON(w, memoryView{Facts: facts})
 31}
 32
 33// memoryTeach is the write path, and the only one. What is typed here is not
 34// stored: it goes to the model with the same rules the automatic pass uses, and
 35// what comes back is what gets written.
 36func (s *site) memoryTeach(w http.ResponseWriter, r *http.Request) {
 37	var body struct {
 38		Said string `json:"said"`
 39	}
 40	_ = json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<20)).Decode(&body)
 41	said := strings.TrimSpace(body.Said)
 42	if said == "" {
 43		s.memoryProblem(w, "Say what should change.")
 44		return
 45	}
 46
 47	ctx, cancel := context.WithTimeout(r.Context(), 2*time.Minute)
 48	defer cancel()
 49
 50	existing, err := s.store.Facts()
 51	if err != nil {
 52		s.memoryProblem(w, err.Error())
 53		return
 54	}
 55	changes, err := s.proposeChanges(ctx, existing,
 56		"Isaac is editing his memory himself and said:\n"+said,
 57		"Do what he asked, following the rules above.")
 58	if err != nil {
 59		s.memoryProblem(w, "the model did not answer: "+err.Error())
 60		return
 61	}
 62	applied := s.applyChanges(changes, existing)
 63	s.store.Checkpoint()
 64
 65	facts, _ := s.store.Facts()
 66	if len(applied) == 0 {
 67		writeJSON(w, memoryView{Facts: facts,
 68			Problem: "Nothing changed. It read that as not worth keeping, or as already known."})
 69		return
 70	}
 71	var parts []string
 72	for _, c := range applied {
 73		switch c.Op {
 74		case "add":
 75			parts = append(parts, "remembered that")
 76		case "replace":
 77			parts = append(parts, "rewrote one")
 78		case "delete":
 79			parts = append(parts, "forgot one")
 80		}
 81	}
 82	writeJSON(w, memoryView{Facts: facts, Applied: applied, Note: strings.Join(parts, ", ") + "."})
 83}
 84
 85func (s *site) memoryProblem(w http.ResponseWriter, msg string) {
 86	facts, _ := s.store.Facts()
 87	writeJSON(w, memoryView{Facts: facts, Problem: msg})
 88}
 89
 90func (s *site) memoryDelete(w http.ResponseWriter, r *http.Request) {
 91	id, _ := strconv.ParseInt(r.PathValue("id"), 10, 64)
 92	if err := s.store.DeleteFact(id); err != nil {
 93		http.Error(w, err.Error(), 500)
 94		return
 95	}
 96	s.store.Checkpoint()
 97	s.memoryList(w, r)
 98}
 99
100func (s *site) memoryForget(w http.ResponseWriter, r *http.Request) {
101	if err := s.store.ForgetEverything(); err != nil {
102		http.Error(w, err.Error(), 500)
103		return
104	}
105	s.store.Checkpoint()
106	s.memoryList(w, r)
107}