5736ad145e
在 v1(注册表+文件覆盖)上加 DB 管理层与热切换,镜像 model-config 控制面: - store: sundynix_prompt 表(key/version/content/active) + ActivePrompts/ListPrompts/ CreateVersion/Activate/Deactivate - 控制面: ServePrompts/RequestActivePrompts(+Retry)/PublishPromptsUpdated/SubscribePromptsUpdated; prompts.ApplyOverrides 整体替换覆盖集(DB 激活集为权威) - gateway API: GET/POST /api/v1/prompts、version/activate/deactivate;激活/撤销即广播 - dispatcher/mcp-go: 启动拉激活集 + 订阅热更新(不重启) - live: 建版本→激活→mcp-go 图谱抽取 2→0→回滚 2(全程不重启);deactivate 回退代码默认;版本可回溯 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
3.0 KiB
Go
82 lines
3.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/sundynix/sundynix-shared/prompts"
|
|
)
|
|
|
|
// PromptList: GET /api/v1/prompts —— 列出受管 prompt 的全部版本 + 可配键(管理端浏览/对比/回滚)。
|
|
func (h *Handler) PromptList(c *gin.Context) {
|
|
rows, err := h.db.ListPrompts(c.Request.Context())
|
|
if err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
out := make([]gin.H, 0, len(rows))
|
|
for _, r := range rows {
|
|
out = append(out, gin.H{"key": r.Key, "version": r.Version, "active": r.Active, "note": r.Note, "content": r.Content})
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"keys": prompts.Known, "versions": out})
|
|
}
|
|
|
|
// PromptCreateVersion: POST /api/v1/prompts/version {key, content, note} —— 为某 key 建新版本(不自动激活)。
|
|
func (h *Handler) PromptCreateVersion(c *gin.Context) {
|
|
var body struct {
|
|
Key string `json:"key"`
|
|
Content string `json:"content"`
|
|
Note string `json:"note"`
|
|
}
|
|
if err := c.ShouldBindJSON(&body); err != nil || body.Key == "" || body.Content == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "key/content required"})
|
|
return
|
|
}
|
|
v, err := h.db.CreatePromptVersion(c.Request.Context(), body.Key, body.Content, body.Note)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"key": body.Key, "version": v})
|
|
}
|
|
|
|
// PromptActivate: POST /api/v1/prompts/activate {key, version} —— 激活某版本 → 经控制面热下发各服务(不重启即生效)。
|
|
func (h *Handler) PromptActivate(c *gin.Context) {
|
|
var body struct {
|
|
Key string `json:"key"`
|
|
Version int `json:"version"`
|
|
}
|
|
if err := c.ShouldBindJSON(&body); err != nil || body.Key == "" || body.Version <= 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "key/version required"})
|
|
return
|
|
}
|
|
if err := h.db.ActivatePrompt(c.Request.Context(), body.Key, body.Version); err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
// 广播最新激活集 → dispatcher/mcp-go 热更新覆盖。
|
|
if err := h.bus.PublishPromptsUpdated(h.db.ActivePrompts(c.Request.Context())); err != nil {
|
|
c.JSON(http.StatusOK, gin.H{"key": body.Key, "version": body.Version, "warn": "已激活但广播失败: " + err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"key": body.Key, "version": body.Version, "activated": true})
|
|
}
|
|
|
|
// PromptDeactivate: POST /api/v1/prompts/deactivate {key} —— 撤销某 key 激活,回退代码内置默认(热下发)。
|
|
func (h *Handler) PromptDeactivate(c *gin.Context) {
|
|
var body struct {
|
|
Key string `json:"key"`
|
|
}
|
|
if err := c.ShouldBindJSON(&body); err != nil || body.Key == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "key required"})
|
|
return
|
|
}
|
|
if err := h.db.DeactivatePrompt(c.Request.Context(), body.Key); err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
_ = h.bus.PublishPromptsUpdated(h.db.ActivePrompts(c.Request.Context()))
|
|
c.JSON(http.StatusOK, gin.H{"key": body.Key, "deactivated": true})
|
|
}
|