cache.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package chat
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "fmt"
  6. "sync"
  7. "github.com/sst/opencode/pkg/client"
  8. )
  9. // MessageCache caches rendered messages to avoid re-rendering
  10. type MessageCache struct {
  11. mu sync.RWMutex
  12. cache map[string]string
  13. }
  14. // NewMessageCache creates a new message cache
  15. func NewMessageCache() *MessageCache {
  16. return &MessageCache{
  17. cache: make(map[string]string),
  18. }
  19. }
  20. // generateKey creates a unique key for a message based on its content and rendering parameters
  21. func (c *MessageCache) generateKey(msg client.MessageInfo, width int, showToolMessages bool, appInfo client.AppInfo) string {
  22. // Create a hash of the message content and rendering parameters
  23. h := sha256.New()
  24. // Include message ID and role
  25. h.Write(fmt.Appendf(nil, "%s:%s", msg.Id, msg.Role))
  26. // Include timestamp
  27. h.Write(fmt.Appendf(nil, ":%f", msg.Metadata.Time.Created))
  28. // Include width and showToolMessages flag
  29. h.Write(fmt.Appendf(nil, ":%d:%t", width, showToolMessages))
  30. // Include app path for relative path calculations
  31. h.Write([]byte(appInfo.Path.Root))
  32. // Include message parts
  33. for _, part := range msg.Parts {
  34. h.Write(fmt.Appendf(nil, ":%v", part))
  35. }
  36. // Include tool metadata if present
  37. for toolID, metadata := range msg.Metadata.Tool {
  38. h.Write(fmt.Appendf(nil, ":%s:%v", toolID, metadata))
  39. }
  40. return hex.EncodeToString(h.Sum(nil))
  41. }
  42. // Get retrieves a cached rendered message
  43. func (c *MessageCache) Get(msg client.MessageInfo, width int, showToolMessages bool, appInfo client.AppInfo) (string, bool) {
  44. c.mu.RLock()
  45. defer c.mu.RUnlock()
  46. key := c.generateKey(msg, width, showToolMessages, appInfo)
  47. content, exists := c.cache[key]
  48. return content, exists
  49. }
  50. // Set stores a rendered message in the cache
  51. func (c *MessageCache) Set(msg client.MessageInfo, width int, showToolMessages bool, appInfo client.AppInfo, content string) {
  52. c.mu.Lock()
  53. defer c.mu.Unlock()
  54. key := c.generateKey(msg, width, showToolMessages, appInfo)
  55. c.cache[key] = content
  56. }
  57. // Clear removes all entries from the cache
  58. func (c *MessageCache) Clear() {
  59. c.mu.Lock()
  60. defer c.mu.Unlock()
  61. c.cache = make(map[string]string)
  62. }
  63. // Size returns the number of cached entries
  64. func (c *MessageCache) Size() int {
  65. c.mu.RLock()
  66. defer c.mu.RUnlock()
  67. return len(c.cache)
  68. }