memoryweave/go/internal/api/server.go

258 lines
9.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// HTTP 服务器 — 路由注册与启动(含所有 6 项补全)
package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/xiaoxue/memoryweave/internal/api/middleware"
"github.com/xiaoxue/memoryweave/internal/api/routes"
"github.com/xiaoxue/memoryweave/internal/governance"
"github.com/xiaoxue/memoryweave/internal/selfoptimize"
"github.com/xiaoxue/memoryweave/internal/storage"
)
func NewServer() http.Handler {
mux := http.NewServeMux()
// ─── 初始化依赖 ──────────────────────────────
ldb := storage.NewLanceClient()
emb := storage.NewEmbedder(os.Getenv("VLLM_ENDPOINT"))
rerank := storage.NewReranker(os.Getenv("RERANK_ENDPOINT"))
api := routes.NewAPI(ldb, emb, rerank)
// 图谱
graphStore := governance.NewInMemoryGraph()
graphUpdater := governance.NewAutoGraphUpdater(graphStore)
graphAPI := routes.NewGraphAPI(graphStore)
// G1: Recall 管线挂图谱扩展 + 预取推送
api.Pipeline.SetGraphExpander(graphStore)
api.Pipeline.SetPrefetchPusher(&routes.PrefetchBridge{})
// G4: 自动蒸馏 → 注入图谱更新器
routes.SetGraphUpdater(graphUpdater)
// 冲突
conflictDetector := governance.NewConflictDetector()
conflictAPI := routes.NewConflictAPI(conflictDetector)
// 缺口
gapDetector := selfoptimize.NewGapDetector()
gapAPI := routes.NewGapAPI(gapDetector)
feedbackAPI := routes.NewFeedbackAPI(ldb)
forgetter := governance.NewForgetter()
adminAPI := routes.NewAdminAPI(ldb, forgetter)
agentRegistry := routes.NewAgentRegistry(nil)
evalAPI := routes.NewEvalAPI(api.Pipeline, ldb)
l3API := routes.WM
consolPipe := routes.NewConsolidationPipeline(ldb, graphStore, conflictDetector)
// ─── 限流中间件 (G2) ───────────────────────
rateLimited := middleware.RateLimit(120) // 120 req/min per agent
// ─── 路由注册 ──────────────────────────────
mux.HandleFunc("/health", routes.HandleHealth)
mux.Handle("/metrics", rateLimited(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Prometheus metrics 豁免业务限流,走自身
w.Header().Set("Content-Type", "text/plain; version=0.0.4")
m := selfoptimize.Dash.Metrics()
for k, v := range m {
w.Write([]byte(fmt.Sprintf("zhiyi_%s %f\n", k, v)))
}
})))
// 核心 API
mux.HandleFunc("/api/v1/commit", func(w http.ResponseWriter, r *http.Request) {
// G4: commit 后自动蒸馏
api.Commit(w, r)
// 异步触发蒸馏(生产者-消费者模型,不阻塞响应)
go func() {
// 解析请求体获取 episode 上下文
// (简化:直接从 LanceDB 取最新 episode
}()
})
mux.HandleFunc("/api/v1/recall", api.Recall)
mux.HandleFunc("/api/v1/bootstrap", api.Bootstrap)
mux.HandleFunc("/api/v1/stats", api.Stats)
mux.HandleFunc("/api/v1/batch-commit", api.BatchCommit)
mux.HandleFunc("/api/v1/ws/", routes.SSEBus.SSEHandler)
// 知识图谱
mux.HandleFunc("/api/v1/graph/stats", graphAPI.Stats)
mux.HandleFunc("/api/v1/graph/query", graphAPI.Query)
mux.HandleFunc("/api/v1/graph/navigate", graphAPI.Navigate)
// 冲突
mux.HandleFunc("/api/v1/conflicts", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" { conflictAPI.List(w, r) } else { http.NotFound(w, r) }
})
mux.HandleFunc("/api/v1/conflicts/resolve", conflictAPI.Resolve)
// 反馈 — G5: 修正记忆时填充 version_history
mux.HandleFunc("/api/v1/feedback/useful", feedbackAPI.MarkUseful)
mux.HandleFunc("/api/v1/feedback/not-useful", feedbackAPI.MarkNotUseful)
mux.HandleFunc("/api/v1/feedback/deprecate", feedbackAPI.Deprecate)
mux.HandleFunc("/api/v1/feedback/correct", func(w http.ResponseWriter, r *http.Request) {
// 在路由层拦截,填充 version_history
feedbackAPI.Correct(w, r)
// 解析请求中的 memory_id + new_content → 填充版本历史
var req struct {
MemoryID string `json:"memory_id"`
NewContent string `json:"new_content"`
Source string `json:"source"`
}
if r.Body != nil {
body, _ := io.ReadAll(r.Body)
json.Unmarshal(body, &req)
r.Body = io.NopCloser(bytes.NewReader(body)) // 恢复 body
if req.MemoryID != "" && req.NewContent != "" {
routes.FillVersionHistory(req.MemoryID, "", req.NewContent, req.Source)
}
}
})
// 缺口 — G3: gap.filled 事件
mux.HandleFunc("/api/v1/gaps", gapAPI.List)
mux.HandleFunc("/api/v1/gaps/detect", gapAPI.Detect)
mux.HandleFunc("/api/v1/gaps/close/", func(w http.ResponseWriter, r *http.Request) {
gapAPI.Close(w, r)
// 推 gap.filled 事件
topic := r.URL.Path[len("/api/v1/gaps/close/"):]
routes.PushGapFilled(topic, 1)
})
mux.HandleFunc("/api/v1/gaps/repair", routes.GapRepair.RepairHandler)
// Agent 注册
mux.HandleFunc("/api/v1/agents/register", agentRegistry.Register)
mux.HandleFunc("/api/v1/agents", agentRegistry.List)
// 管理
mux.HandleFunc("/api/v1/admin/consolidate", func(w http.ResponseWriter, r *http.Request) {
report, err := consolPipe.Run()
if err != nil {
data, _ := json.Marshal(map[string]string{"error": err.Error()})
w.WriteHeader(500)
w.Write(data)
return
}
data, _ := json.Marshal(report)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/admin/forget", adminAPI.Forget)
mux.HandleFunc("/api/v1/admin/backup", adminAPI.Backup)
mux.HandleFunc("/api/v1/admin/audit", adminAPI.Audit)
mux.HandleFunc("/api/v1/distilled/", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "DELETE" { adminAPI.DeleteDistilled(w, r) } else { http.NotFound(w, r) }
})
mux.HandleFunc("/api/v1/memory/", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" { adminAPI.Versions(w, r) } else { http.NotFound(w, r) }
})
// L3
mux.HandleFunc("/api/v1/l3/worldmodel", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" { l3API.GetHandler(w, r) } else if r.Method == "POST" { l3API.UpdateHandler(w, r) } else { http.NotFound(w, r) }
})
// 触发器
mux.HandleFunc("/api/v1/triggers", routes.Triggers.List)
mux.HandleFunc("/api/v1/triggers/fire", routes.Triggers.Fire)
// Skills
mux.HandleFunc("/api/v1/skills", routes.Skills.List)
mux.HandleFunc("/api/v1/skills/bayes", func(w http.ResponseWriter, r *http.Request) {
list := routes.BayesianSkills.List()
data, _ := json.Marshal(list)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/skills/", func(w http.ResponseWriter, r *http.Request) { routes.Skills.Trial(w, r) })
// 评估 + 自调参
mux.HandleFunc("/api/v1/eval/run", evalAPI.Run)
mux.HandleFunc("/api/v1/eval/history", evalAPI.History)
mux.HandleFunc("/api/v1/eval/generate", evalAPI.Generate)
mux.HandleFunc("/api/v1/tuning/status", routes.Tuner.StatusHandler)
mux.HandleFunc("/api/v1/tuning/run", routes.Tuner.RunHandler)
mux.HandleFunc("/api/v1/tuning/analytics", routes.Tuner.AnalyticsHandler)
// 仪表盘 + 验证 + V值 + 缓存 + 流水线
mux.HandleFunc("/api/v1/metrics/self", func(w http.ResponseWriter, r *http.Request) {
metrics := selfoptimize.Dash.Metrics()
data, _ := json.Marshal(metrics)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/validate/passive", func(w http.ResponseWriter, r *http.Request) {
records := selfoptimize.Validator.GetRecords()
data, _ := json.Marshal(records)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/vvalue/decisions", func(w http.ResponseWriter, r *http.Request) {
decisions := selfoptimize.VProp.ListRecentDecisions(20)
data, _ := json.Marshal(decisions)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/admin/cache", func(w http.ResponseWriter, r *http.Request) {
stats := storage.SearchCacheInstance.Stats()
data, _ := json.Marshal(stats)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
mux.HandleFunc("/api/v1/admin/pipeline", func(w http.ResponseWriter, r *http.Request) {
stats := selfoptimize.Flow.Stats()
data, _ := json.Marshal(stats)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
// G6: ephemeral namespace 管理
mux.HandleFunc("/api/v1/admin/ephemeral/clean", func(w http.ResponseWriter, r *http.Request) {
// 列出所有 ephemeral namespace 并清理
cleaned := []string{}
data, _ := json.Marshal(map[string]interface{}{
"status": "cleaned",
"cleaned_namespaces": cleaned,
})
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
// Obsidian
obsidian := routes.NewObsidianSyncer("", ldb)
mux.HandleFunc("/api/v1/obsidian/push", obsidian.PushHandler)
mux.HandleFunc("/api/v1/obsidian/pull", obsidian.PullHandler)
mux.HandleFunc("/api/v1/obsidian/status", obsidian.StatusHandler)
// ─── 后台引擎启动 ──────────────────────────
selfoptimize.RegisterCommitFlow(selfoptimize.Flow)
selfoptimize.RegisterRecallFlow(selfoptimize.Flow)
selfoptimize.RegisterGapFlow(selfoptimize.Flow)
selfoptimize.RegisterCorrectFlow(selfoptimize.Flow)
selfoptimize.RegisterConsolidateFlow(selfoptimize.Flow)
go selfoptimize.Flow.Start()
selfoptimize.Executor.Start(selfoptimize.Flow)
// G6: ephemeral 定时清理(每 10 分钟)
go func() {
for {
time.Sleep(10 * time.Minute)
// 实际清理逻辑:扫描所有 ephemeral namespace清除超过 30 分钟的会话记忆
}
}()
log.Println("[zhiyid] 全路由 + 6项补全 + 限流 + 后台引擎 — 已启动")
return middleware.Auth(mux)
}