Files
teexiiiandGitHub 88a5793030 fix(agents): sync IDENTITY.md Name field on agent rename (#582)
## Summary

- Agent rename now updates Name field in IDENTITY.md (agent-level + per-user copies for open agents) via both HTTP and WS paths
- Fixes lossy identity rebuild: previous logic reconstructed IDENTITY.md from only Name/Emoji/Avatar, silently dropping LLM-written fields (Creature, Purpose, Vibe, etc.)
- Uses targeted field replacement (bootstrap.UpdateIdentityField) preserving original formatting
- Adds ListUserContextFilesByName to AgentContextStore (PG + SQLite)
- Fixes LastIndex bug in UpdateIdentityField where values containing colons (e.g. Avatar URLs) would break field replacement
- Removes ~335 lines of dead config.json fallback code (agentStore is always set)
- Adds 9 unit tests for UpdateIdentityField covering plain/markdown formats, URLs, edge cases
2026-03-30 20:56:49 +07:00

47 lines
1.9 KiB
Go

package bootstrap
import "strings"
// UpdateIdentityField replaces a single field line in IDENTITY.md content without
// touching any other fields. Handles both plain format ("Name: value") and the
// LLM-generated markdown format ("- **Name:** value") written during onboarding.
// If no matching line is found, one is inserted after the first heading.
func UpdateIdentityField(content, fieldName, newValue string) string {
if newValue == "" {
return content
}
marker := fieldName + ":"
lines := strings.Split(content, "\n")
for i, line := range lines {
// Strip leading list/bold markdown markers (-, *, #, spaces) to normalize
// both "Name: value" and "- **Name:** value" to the same comparison base.
stripped := strings.TrimSpace(strings.TrimLeft(strings.TrimSpace(line), "-*# \t"))
if strings.HasPrefix(stripped, marker) {
// Find the marker colon in the original line by locating the marker text,
// NOT LastIndex — values may contain colons (e.g. Avatar URLs).
markerIdx := strings.Index(stripped, ":")
// Map back to original line: find where stripped starts in the original.
prefixLen := strings.Index(line, stripped[:markerIdx+1])
colonIdx := prefixLen + markerIdx
// Include any "**" immediately after the colon so ":**" stays intact.
afterColon := line[colonIdx+1:]
starLen := len(afterColon) - len(strings.TrimLeft(afterColon, "*"))
lines[i] = line[:colonIdx+1+starLen] + " " + newValue
return strings.Join(lines, "\n")
}
}
// No existing line for this field — insert after first heading or at top.
insertAt := 0
for i, line := range lines {
if strings.HasPrefix(strings.TrimSpace(line), "#") {
insertAt = i + 1
break
}
}
result := make([]string, 0, len(lines)+1)
result = append(result, lines[:insertAt]...)
result = append(result, fieldName+": "+newValue)
result = append(result, lines[insertAt:]...)
return strings.Join(result, "\n")
}