package runtime import ( "crypto/sha256" "encoding/hex" "encoding/json" "os" "sort" core "agent-system-core" ) // seedMeta 是会话转录旁的播种状态:.seed.json。 // Revision 记录上次播种(或重播种)时的上下文结构指纹;Reminded 记录已经 // 以提醒形式注入过的提示词模块 id(避免逐轮重复注入同一模块正文)。 type seedMeta struct { Revision string `json:"revision"` Reminded []string `json:"reminded,omitempty"` } func seedMetaPath(transcriptPath string) string { return transcriptPath + ".seed.json" } func readSeedMeta(transcriptPath string) *seedMeta { raw, err := os.ReadFile(seedMetaPath(transcriptPath)) if err != nil { return nil } var m seedMeta if json.Unmarshal(raw, &m) != nil || m.Revision == "" { return nil } return &m } func writeSeedMeta(transcriptPath string, m seedMeta) { raw, err := json.Marshal(m) if err != nil { return } _ = os.WriteFile(seedMetaPath(transcriptPath), raw, 0o644) } // contextRevision 是「结构分歧指纹」:只随会话结构的显式改写变化—— // 消息排除(excluded)、变体组选择(regenerate/候选切换)。正常的追加 // (新的一轮)不改变指纹。指纹变化 ⇒ 转录与消息库已分歧 ⇒ 重播种转录。 func contextRevision(history []core.Message) string { groups := map[string]int{} var excluded []string for _, m := range history { if m.Excluded { excluded = append(excluded, string(m.ID)) } if m.VariantGroup != "" && !m.Excluded && m.VariantIndex > groups[m.VariantGroup] { groups[m.VariantGroup] = m.VariantIndex } } sort.Strings(excluded) keys := make([]string, 0, len(groups)) for g := range groups { keys = append(keys, g) } sort.Strings(keys) h := sha256.New() for _, id := range excluded { h.Write([]byte("x" + id + ";")) } for _, g := range keys { h.Write([]byte(g + "=" + string(rune('0'+groups[g])) + ";")) } return hex.EncodeToString(h.Sum(nil))[:16] } // resetTranscript 丢弃现有转录(分歧重播种)。Store 是无状态句柄 // (每次操作按路径开文件),删除文件即可;旁挂 meta 一并清理。 func resetTranscript(transcriptPath string) error { if err := os.Remove(transcriptPath); err != nil && !os.IsNotExist(err) { return err } _ = os.Remove(transcriptPath + ".meta.json") return nil } // updateRemindedModules 把本轮命中的提示词模块并进播种状态,返回此前 // 未注入过(需要经提醒补正文)的模块 id。播种轮的模块正文已在系统段里, // 只登记不注入。 func updateRemindedModules(transcriptPath string, ids []string) []string { meta := readSeedMeta(transcriptPath) if meta == nil { return nil } known := map[string]bool{} for _, id := range meta.Reminded { known[id] = true } var fresh []string for _, id := range ids { if !known[id] { fresh = append(fresh, id) meta.Reminded = append(meta.Reminded, id) } } if len(fresh) > 0 { writeSeedMeta(transcriptPath, *meta) } return fresh }