UpdateSession updates an existing session, or creates it if it doesn't exist (upsert). This enables lazy session persistence - sessions are only stored when they have content. Note: Like SQLite, this only stores metadata. Messages are stored separately via AddMessage.
(_ context.Context, session *Session)
| 207 | // This enables lazy session persistence - sessions are only stored when they have content. |
| 208 | // Note: Like SQLite, this only stores metadata. Messages are stored separately via AddMessage. |
| 209 | func (s *InMemorySessionStore) UpdateSession(_ context.Context, session *Session) error { |
| 210 | if session.ID == "" { |
| 211 | return ErrEmptyID |
| 212 | } |
| 213 | |
| 214 | // Snapshot the input session under its mu so the field copy |
| 215 | // doesn't race with concurrent writers (e.g. the runtime stream |
| 216 | // goroutine updating token counts via SetUsage). |
| 217 | // MAINTENANCE: when adding new persisted fields to Session, add them here too. |
| 218 | session.mu.RLock() |
| 219 | newSession := &Session{ |
| 220 | ID: session.ID, |
| 221 | Title: session.Title, |
| 222 | Evals: session.Evals, |
| 223 | CreatedAt: session.CreatedAt, |
| 224 | ToolsApproved: session.ToolsApproved, |
| 225 | HideToolResults: session.HideToolResults, |
| 226 | WorkingDir: session.WorkingDir, |
| 227 | SendUserMessage: session.SendUserMessage, |
| 228 | MaxIterations: session.MaxIterations, |
| 229 | Starred: session.Starred, |
| 230 | InputTokens: session.InputTokens, |
| 231 | OutputTokens: session.OutputTokens, |
| 232 | Cost: session.Cost, |
| 233 | Permissions: clonePermissionsConfig(session.Permissions), |
| 234 | AgentModelOverrides: cloneStringMap(session.AgentModelOverrides), |
| 235 | CustomModelsUsed: cloneStringSlice(session.CustomModelsUsed), |
| 236 | AttachedFiles: slices.Clone(session.AttachedFiles), |
| 237 | ParentID: session.ParentID, |
| 238 | } |
| 239 | session.mu.RUnlock() |
| 240 | |
| 241 | // Preserve existing messages if session already exists |
| 242 | if existing, exists := s.sessions.Load(session.ID); exists { |
| 243 | existing.mu.RLock() |
| 244 | newSession.Messages = make([]Item, len(existing.Messages)) |
| 245 | copy(newSession.Messages, existing.Messages) |
| 246 | existing.mu.RUnlock() |
| 247 | } |
| 248 | |
| 249 | s.sessions.Store(session.ID, newSession) |
| 250 | return nil |
| 251 | } |
| 252 | |
| 253 | // SetSessionStarred sets the starred status of a session. |
| 254 | func (s *InMemorySessionStore) SetSessionStarred(_ context.Context, id string, starred bool) error { |