Files
sundynix-agentix/sundynix-gateway/internal/store/prompt.go
T
Blizzard 5736ad145e feat(prompts): v2 DB 控制面热切换 —— 版本留存 + 不重启即生效
在 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>
2026-06-30 14:59:52 +08:00

83 lines
3.0 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.
package store
import (
"context"
"gorm.io/gorm"
)
// Prompt 是一条受管系统提示词的某个版本。表名 sundynix_prompt(key,version) 唯一。
// 平台级配置(非按 owner),由管理端维护:建版本 → 激活某版 → 控制面热下发各服务。
type Prompt struct {
BaseModel
Key string `gorm:"size:64;uniqueIndex:idx_prompt_kv;index"` // 受管 prompt 键,如 graph.extract
Version int `gorm:"uniqueIndex:idx_prompt_kv"` // 该 key 下递增版本号
Content string `gorm:"type:text"` // 提示词正文
Active bool `gorm:"index"` // 是否为该 key 当前激活版(每 key 至多一条)
Note string `gorm:"size:200"` // 版本说明
}
func (Prompt) TableName() string { return "sundynix_prompt" }
// ActivePrompts 返回全部激活版的 key→content(控制面下发用)。
func (p *Postgres) ActivePrompts(ctx context.Context) map[string]string {
out := map[string]string{}
if p.db == nil {
return out
}
var rows []Prompt
if err := p.db.WithContext(ctx).Where("active = ?", true).Find(&rows).Error; err != nil {
return out
}
for _, r := range rows {
out[r.Key] = r.Content
}
return out
}
// ListPrompts 返回全部 prompt 版本(按 key、version 排序,供管理端浏览/对比/回滚)。
func (p *Postgres) ListPrompts(ctx context.Context) ([]Prompt, error) {
if p.db == nil {
return nil, nil
}
var rows []Prompt
err := p.db.WithContext(ctx).Order("key asc, version asc").Find(&rows).Error
return rows, err
}
// CreatePromptVersion 为某 key 新建一个版本(version=该 key 现有最大+1,默认不激活),返回新版本号。
func (p *Postgres) CreatePromptVersion(ctx context.Context, key, content, note string) (int, error) {
if p.db == nil {
return 0, nil
}
var maxV struct{ V int }
p.db.WithContext(ctx).Model(&Prompt{}).Select("coalesce(max(version),0) as v").Where("key = ?", key).Scan(&maxV)
v := maxV.V + 1
row := Prompt{Key: key, Version: v, Content: content, Note: note, Active: false}
if err := p.db.WithContext(ctx).Create(&row).Error; err != nil {
return 0, err
}
return v, nil
}
// DeactivatePrompt 撤销某 key 的全部激活(控制面下发后该 key 回退到代码内置默认)。
func (p *Postgres) DeactivatePrompt(ctx context.Context, key string) error {
if p.db == nil {
return nil
}
return p.db.WithContext(ctx).Model(&Prompt{}).Where("key = ?", key).Update("active", false).Error
}
// ActivatePrompt 激活某 key 的指定版本(同 key 其它版本置非激活)。事务保证每 key 至多一个激活版。
func (p *Postgres) ActivatePrompt(ctx context.Context, key string, version int) error {
if p.db == nil {
return nil
}
return p.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&Prompt{}).Where("key = ?", key).Update("active", false).Error; err != nil {
return err
}
return tx.Model(&Prompt{}).Where("key = ? AND version = ?", key, version).Update("active", true).Error
})
}