feat(agent): 新增通用 {{.Now}} 提示词变量(每轮实时渲染)

- 各 agent 渲染路径(chat/worker/mainagent/goals/planner)统一提供 Now(nowStr());
  自定义会话 agent 每次触发都会重新 renderSystem,故 {{.Now}} 每轮实时刷新
- server 端 globalPromptVars + withGlobalVars:在保存校验/变量列表/预览/详情放行
  {{.Now}},否则引用它的自定义提示词会被 validateTemplate 拒绝
- 无 DB 迁移(handler 层注入通用变量,不动 agent_prompt_vars 表)
- 用途:配合固定的开始时间戳相减,判断"已运行多久/是否进入最后N小时"
- 新增 agent/prompt_now_test.go:{{.Now}} 渲染实时时间、未知变量安全回退
This commit is contained in:
Autumn-27 committed 2026-08-11 10:45:02 -04:00
1 parent 7afff7e5f5
commit 7064216188
8 files changed
+86 -14

No files matched your search

+18 -3
View File
@@ -303,6 +303,7 @@ func (s *Server) pgGetAgent(w http.ResponseWriter, r *http.Request) {
}
cur, _ := pg.CurrentPrompt(a.ID)
vars, _ := pg.PromptVars(a.ID)
vars = withGlobalVars(vars)
vers, _ := pg.ListPromptVersions(a.ID)
if vers == nil {
vers = []db.PromptVersion{}
@@ -339,7 +340,7 @@ func (s *Server) pgSavePrompt(w http.ResponseWriter, r *http.Request) {
return
}
vars, _ := pg.PromptVars(a.ID)
if bad := validateTemplate(body.Template, vars); bad != "" {
if bad := validateTemplate(body.Template, withGlobalVars(vars)); bad != "" {
writeErr(w, 400, bad)
return
}
@@ -495,7 +496,7 @@ func (s *Server) pgPromptVars(w http.ResponseWriter, r *http.Request) {
writeErr(w, 500, err.Error())
return
}
writeJSON(w, 200, map[string]any{"variables": vars})
writeJSON(w, 200, map[string]any{"variables": withGlobalVars(vars)})
}
func (s *Server) pgPreviewPrompt(w http.ResponseWriter, r *http.Request) {
@@ -512,7 +513,7 @@ func (s *Server) pgPreviewPrompt(w http.ResponseWriter, r *http.Request) {
if body.Template == "" {
body.Template, _ = pg.CurrentPrompt(a.ID)
}
rendered, err := renderPrompt(body.Template, vars, body.Sample)
rendered, err := renderPrompt(body.Template, withGlobalVars(vars), body.Sample)
if err != nil {
writeJSON(w, 200, map[string]any{"rendered": "", "error": err.Error()})
return
@@ -1706,6 +1707,20 @@ func (s *Server) pgListModels(w http.ResponseWriter, r *http.Request) {
// --- prompt template helpers (Go text/template + catalog 白名单) ---
// globalPromptVars are runtime variables available to EVERY agent (built-in and
// custom) regardless of its per-agent catalog. Each agent's render path fills them
// (see agent.nowStr, rendered fresh each turn), so a prompt may always reference
// {{.Now}} — e.g. subtract it from a fixed start stamp to reason about elapsed time.
var globalPromptVars = []db.PromptVar{
{Name: "Now", Description: "服务端当前时间(每次运行实时刷新;可与固定起始时间相减判断已用时长)", Example: "2026-08-11 14:30:00 CST", Source: "runtime"},
}
// withGlobalVars appends the universal runtime vars onto an agent's own catalog,
// so validation / the UI variable list / preview all recognize {{.Now}} etc.
func withGlobalVars(vars []db.PromptVar) []db.PromptVar {
return append(append([]db.PromptVar{}, vars...), globalPromptVars...)
}
// validateTemplate parses the template and rejects any {{.Var}} not in the catalog.
// Returns "" if valid, otherwise an error message.
func validateTemplate(tmpl string, catalog []db.PromptVar) string {