From 4ffdb92e2c4d06880ee4b7dffe3a0ce06035a6ad Mon Sep 17 00:00:00 2001 From: Djordje Lukic Date: Thu, 12 Mar 2026 11:38:05 +0100 Subject: [PATCH] Remove unused branch metadata and split_diff_view from sessions Remove BranchParentSessionID, BranchParentPosition, and BranchCreatedAt fields from the Session struct and Summary struct. These were stored and persisted but never read for any logic or UI display. The branching mechanism itself (BranchSession) remains functional - only the provenance metadata that nothing consumed is removed. Also drops the split_diff_view column which was already ignored in code. Adds migration 019 to drop the columns and index from SQLite. --- pkg/session/branch.go | 6 -- pkg/session/branch_test.go | 5 - pkg/session/migrations.go | 12 +++ pkg/session/session.go | 10 -- pkg/session/store.go | 207 ++++++++++++------------------------- pkg/session/store_test.go | 8 -- 6 files changed, 78 insertions(+), 170 deletions(-) diff --git a/pkg/session/branch.go b/pkg/session/branch.go index 1ab0189b2..2baf7ea83 100644 --- a/pkg/session/branch.go +++ b/pkg/session/branch.go @@ -6,7 +6,6 @@ import ( "maps" "slices" "strings" - "time" "github.com/docker/docker-agent/pkg/chat" ) @@ -24,11 +23,6 @@ func BranchSession(parent *Session, branchAtPosition int) (*Session, error) { branched := New() copySessionMetadata(branched, parent, generateBranchTitle(parent.Title)) - now := time.Now() - branched.BranchParentSessionID = parent.ID - branched.BranchParentPosition = &branchAtPosition - branched.BranchCreatedAt = &now - branched.Messages = make([]Item, 0, branchAtPosition) for i := range branchAtPosition { cloned, err := cloneSessionItem(parent.Messages[i]) diff --git a/pkg/session/branch_test.go b/pkg/session/branch_test.go index d7bf5a6de..cae770bb8 100644 --- a/pkg/session/branch_test.go +++ b/pkg/session/branch_test.go @@ -135,11 +135,6 @@ func TestBranchSession(t *testing.T) { assert.NotEqual(t, parent.ID, branched.ID) assert.Equal(t, "Parent Title (branched)", branched.Title) - assert.Equal(t, parent.ID, branched.BranchParentSessionID) - assert.NotNil(t, branched.BranchParentPosition) - assert.Equal(t, 2, *branched.BranchParentPosition) - assert.NotNil(t, branched.BranchCreatedAt) - assert.Len(t, branched.Messages, 2) assert.Equal(t, "msg1", branched.Messages[0].Message.Message.Content) assert.Equal(t, "msg2", branched.Messages[1].Message.Message.Content) diff --git a/pkg/session/migrations.go b/pkg/session/migrations.go index 4a5311354..7c64a5822 100644 --- a/pkg/session/migrations.go +++ b/pkg/session/migrations.go @@ -332,6 +332,18 @@ func getAllMigrations() []Migration { Description: "Add index on session_items(session_id, item_type) to speed up session summary message counts", UpSQL: `CREATE INDEX IF NOT EXISTS idx_session_items_session_type ON session_items(session_id, item_type)`, }, + { + ID: 19, + Name: "019_drop_branch_and_split_diff_columns", + Description: "Drop unused branch metadata columns and split_diff_view column", + UpSQL: ` + DROP INDEX IF EXISTS idx_sessions_branch_parent; + ALTER TABLE sessions DROP COLUMN branch_parent_session_id; + ALTER TABLE sessions DROP COLUMN branch_parent_position; + ALTER TABLE sessions DROP COLUMN branch_created_at; + ALTER TABLE sessions DROP COLUMN split_diff_view; + `, + }, } } diff --git a/pkg/session/session.go b/pkg/session/session.go index 9e6782b5a..ef871b8c8 100644 --- a/pkg/session/session.go +++ b/pkg/session/session.go @@ -113,16 +113,6 @@ type Session struct { // These are shown in the model picker for easy re-selection. CustomModelsUsed []string `json:"custom_models_used,omitempty"` - // BranchParentSessionID indicates this session was branched from another session. - BranchParentSessionID string `json:"branch_parent_session_id,omitempty"` - - // BranchParentPosition is the parent session item position where this branch occurred. - // Only set when BranchParentSessionID is non-empty. - BranchParentPosition *int `json:"branch_parent_position,omitempty"` - - // BranchCreatedAt is the time when this branch session was created. - BranchCreatedAt *time.Time `json:"branch_created_at,omitempty"` - // AgentName, when set, tells RunStream which agent to use for this session // instead of reading from the shared runtime currentAgent field. This is // required for background agent tasks where multiple sessions may run diff --git a/pkg/session/store.go b/pkg/session/store.go index 545213027..1b08838ca 100644 --- a/pkg/session/store.go +++ b/pkg/session/store.go @@ -66,12 +66,11 @@ func ResolveSessionID(ctx context.Context, store Store, ref string) (string, err // Summary contains lightweight session metadata for listing purposes. // This is used instead of loading full Session objects with all messages. type Summary struct { - ID string - Title string - CreatedAt time.Time - Starred bool - BranchParentSessionID string - NumMessages int + ID string + Title string + CreatedAt time.Time + Starred bool + NumMessages int } // Store defines the interface for session storage @@ -160,12 +159,11 @@ func (s *InMemorySessionStore) GetSessionSummaries(_ context.Context) ([]Summary return true } summaries = append(summaries, Summary{ - ID: value.ID, - Title: value.Title, - CreatedAt: value.CreatedAt, - Starred: value.Starred, - BranchParentSessionID: value.BranchParentSessionID, - NumMessages: value.MessageCount(), + ID: value.ID, + Title: value.Title, + CreatedAt: value.CreatedAt, + Starred: value.Starred, + NumMessages: value.MessageCount(), }) return true }) @@ -199,27 +197,24 @@ func (s *InMemorySessionStore) UpdateSession(_ context.Context, session *Session // Messages are stored separately via AddMessage. // MAINTENANCE: when adding new persisted fields to Session, add them here too. newSession := &Session{ - ID: session.ID, - Title: session.Title, - Evals: session.Evals, - CreatedAt: session.CreatedAt, - ToolsApproved: session.ToolsApproved, - Thinking: session.Thinking, - HideToolResults: session.HideToolResults, - WorkingDir: session.WorkingDir, - SendUserMessage: session.SendUserMessage, - MaxIterations: session.MaxIterations, - Starred: session.Starred, - InputTokens: session.InputTokens, - OutputTokens: session.OutputTokens, - Cost: session.Cost, - Permissions: session.Permissions, - AgentModelOverrides: session.AgentModelOverrides, - CustomModelsUsed: session.CustomModelsUsed, - BranchParentSessionID: session.BranchParentSessionID, - BranchParentPosition: session.BranchParentPosition, - BranchCreatedAt: session.BranchCreatedAt, - ParentID: session.ParentID, + ID: session.ID, + Title: session.Title, + Evals: session.Evals, + CreatedAt: session.CreatedAt, + ToolsApproved: session.ToolsApproved, + Thinking: session.Thinking, + HideToolResults: session.HideToolResults, + WorkingDir: session.WorkingDir, + SendUserMessage: session.SendUserMessage, + MaxIterations: session.MaxIterations, + Starred: session.Starred, + InputTokens: session.InputTokens, + OutputTokens: session.OutputTokens, + Cost: session.Cost, + Permissions: session.Permissions, + AgentModelOverrides: session.AgentModelOverrides, + CustomModelsUsed: session.CustomModelsUsed, + ParentID: session.ParentID, } // Preserve existing messages if session already exists @@ -527,19 +522,6 @@ func (s *SQLiteSessionStore) AddSession(ctx context.Context, session *Session) e if session.ParentID != "" { parentID = session.ParentID } - var branchParentID any - if session.BranchParentSessionID != "" { - branchParentID = session.BranchParentSessionID - } - var branchParentPosition any - if session.BranchParentPosition != nil { - branchParentPosition = *session.BranchParentPosition - } - var branchCreatedAt any - if session.BranchCreatedAt != nil { - branchCreatedAt = session.BranchCreatedAt.Format(time.RFC3339) - } - // Use a transaction to insert session and its items tx, err := s.db.BeginTx(ctx, nil) if err != nil { @@ -551,13 +533,12 @@ func (s *SQLiteSessionStore) AddSession(ctx context.Context, session *Session) e `INSERT INTO sessions ( id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, permissions, agent_model_overrides, - custom_models_used, thinking, parent_id, branch_parent_session_id, - branch_parent_position, branch_created_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + custom_models_used, thinking, parent_id + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, session.ID, session.ToolsApproved, session.InputTokens, session.OutputTokens, session.Title, session.Cost, session.SendUserMessage, session.MaxIterations, session.WorkingDir, session.CreatedAt.Format(time.RFC3339), permissionsJSON, agentModelOverridesJSON, - customModelsUsedJSON, session.Thinking, parentID, branchParentID, branchParentPosition, branchCreatedAt) + customModelsUsedJSON, session.Thinking, parentID) if err != nil { return err } @@ -583,12 +564,7 @@ func scanSession(scanner interface { var workingDir sql.NullString var permissionsJSON sql.NullString var parentID sql.NullString - var branchParentID sql.NullString - var branchParentPosition sql.NullInt64 - var branchCreatedAt sql.NullString - var splitDiffView sql.NullBool // column kept for backward compat, value ignored - - err := scanner.Scan(&sessionID, &toolsApprovedStr, &inputTokensStr, &outputTokensStr, &titleStr, &costStr, &sendUserMessageStr, &maxIterationsStr, &workingDir, &createdAtStr, &starredStr, &permissionsJSON, &agentModelOverridesJSON, &customModelsUsedJSON, &thinkingStr, &parentID, &branchParentID, &branchParentPosition, &branchCreatedAt, &splitDiffView) + err := scanner.Scan(&sessionID, &toolsApprovedStr, &inputTokensStr, &outputTokensStr, &titleStr, &costStr, &sendUserMessageStr, &maxIterationsStr, &workingDir, &createdAtStr, &starredStr, &permissionsJSON, &agentModelOverridesJSON, &customModelsUsedJSON, &thinkingStr, &parentID) if err != nil { return nil, err } @@ -663,42 +639,24 @@ func scanSession(scanner interface { } } - var branchParentPositionPtr *int - if branchParentPosition.Valid { - pos := int(branchParentPosition.Int64) - branchParentPositionPtr = &pos - } - - var branchCreatedAtPtr *time.Time - if branchCreatedAt.Valid && branchCreatedAt.String != "" { - parsed, err := time.Parse(time.RFC3339, branchCreatedAt.String) - if err != nil { - return nil, err - } - branchCreatedAtPtr = &parsed - } - return &Session{ - ID: sessionID, - Title: titleStr, - Messages: nil, // Loaded separately from session_items - ToolsApproved: toolsApproved, - Thinking: thinking, - InputTokens: inputTokens, - OutputTokens: outputTokens, - Cost: cost, - SendUserMessage: sendUserMessage, - MaxIterations: maxIterations, - CreatedAt: createdAt, - WorkingDir: workingDir.String, - Starred: starred, - Permissions: permissions, - AgentModelOverrides: agentModelOverrides, - CustomModelsUsed: customModelsUsed, - BranchParentSessionID: branchParentID.String, - BranchParentPosition: branchParentPositionPtr, - BranchCreatedAt: branchCreatedAtPtr, - ParentID: parentID.String, + ID: sessionID, + Title: titleStr, + Messages: nil, // Loaded separately from session_items + ToolsApproved: toolsApproved, + Thinking: thinking, + InputTokens: inputTokens, + OutputTokens: outputTokens, + Cost: cost, + SendUserMessage: sendUserMessage, + MaxIterations: maxIterations, + CreatedAt: createdAt, + WorkingDir: workingDir.String, + Starred: starred, + Permissions: permissions, + AgentModelOverrides: agentModelOverrides, + CustomModelsUsed: customModelsUsed, + ParentID: parentID.String, }, nil } @@ -709,7 +667,7 @@ func (s *SQLiteSessionStore) GetSession(ctx context.Context, id string) (*Sessio } row := s.db.QueryRowContext(ctx, - "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id, branch_parent_session_id, branch_parent_position, branch_created_at, split_diff_view FROM sessions WHERE id = ?", id) + "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id FROM sessions WHERE id = ?", id) sess, err := scanSession(row) if err != nil { @@ -825,7 +783,7 @@ func (s *SQLiteSessionStore) loadSessionItemsWith(ctx context.Context, q querier // loadSessionWith loads a session using the provided querier. func (s *SQLiteSessionStore) loadSessionWith(ctx context.Context, q querier, id string) (*Session, error) { row := q.QueryRowContext(ctx, - "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id, branch_parent_session_id, branch_parent_position, branch_created_at, split_diff_view FROM sessions WHERE id = ?", id) + "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id FROM sessions WHERE id = ?", id) sess, err := scanSession(row) if err != nil { @@ -880,7 +838,7 @@ func (s *SQLiteSessionStore) loadMessagesFromLegacyColumn(ctx context.Context, s // GetSessions retrieves all root sessions (excludes sub-sessions) func (s *SQLiteSessionStore) GetSessions(ctx context.Context) ([]*Session, error) { rows, err := s.db.QueryContext(ctx, - "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id, branch_parent_session_id, branch_parent_position, branch_created_at, split_diff_view FROM sessions WHERE parent_id IS NULL OR parent_id = '' ORDER BY created_at DESC") + "SELECT id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, custom_models_used, thinking, parent_id FROM sessions WHERE parent_id IS NULL OR parent_id = '' ORDER BY created_at DESC") if err != nil { return nil, err } @@ -915,7 +873,7 @@ func (s *SQLiteSessionStore) GetSessions(ctx context.Context) ([]*Session, error // This is much faster than GetSessions as it doesn't load message content. func (s *SQLiteSessionStore) GetSessionSummaries(ctx context.Context) ([]Summary, error) { rows, err := s.db.QueryContext(ctx, - `SELECT s.id, s.title, s.created_at, s.starred, s.branch_parent_session_id, + `SELECT s.id, s.title, s.created_at, s.starred, (SELECT COUNT(*) FROM session_items si WHERE si.session_id = s.id AND si.item_type = 'message') FROM sessions s WHERE s.parent_id IS NULL OR s.parent_id = '' @@ -928,9 +886,8 @@ func (s *SQLiteSessionStore) GetSessionSummaries(ctx context.Context) ([]Summary var summaries []Summary for rows.Next() { var id, title, createdAtStr, starredStr string - var branchParentID sql.NullString var numMessages int - if err := rows.Scan(&id, &title, &createdAtStr, &starredStr, &branchParentID, &numMessages); err != nil { + if err := rows.Scan(&id, &title, &createdAtStr, &starredStr, &numMessages); err != nil { return nil, err } createdAt, err := time.Parse(time.RFC3339, createdAtStr) @@ -942,12 +899,11 @@ func (s *SQLiteSessionStore) GetSessionSummaries(ctx context.Context) ([]Summary return nil, err } summaries = append(summaries, Summary{ - ID: id, - Title: title, - CreatedAt: createdAt, - Starred: starred, - BranchParentSessionID: branchParentID.String, - NumMessages: numMessages, + ID: id, + Title: title, + CreatedAt: createdAt, + Starred: starred, + NumMessages: numMessages, }) } @@ -1023,19 +979,6 @@ func (s *SQLiteSessionStore) UpdateSession(ctx context.Context, session *Session if session.ParentID != "" { parentID = session.ParentID } - var branchParentID any - if session.BranchParentSessionID != "" { - branchParentID = session.BranchParentSessionID - } - var branchParentPosition any - if session.BranchParentPosition != nil { - branchParentPosition = *session.BranchParentPosition - } - var branchCreatedAt any - if session.BranchCreatedAt != nil { - branchCreatedAt = session.BranchCreatedAt.Format(time.RFC3339) - } - // Use a transaction tx, err := s.db.BeginTx(ctx, nil) if err != nil { @@ -1048,10 +991,9 @@ func (s *SQLiteSessionStore) UpdateSession(ctx context.Context, session *Session `INSERT INTO sessions ( id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, - custom_models_used, thinking, parent_id, branch_parent_session_id, - branch_parent_position, branch_created_at + custom_models_used, thinking, parent_id ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET title = excluded.title, tools_approved = excluded.tools_approved, @@ -1066,14 +1008,11 @@ func (s *SQLiteSessionStore) UpdateSession(ctx context.Context, session *Session agent_model_overrides = excluded.agent_model_overrides, custom_models_used = excluded.custom_models_used, thinking = excluded.thinking, - parent_id = excluded.parent_id, - branch_parent_session_id = excluded.branch_parent_session_id, - branch_parent_position = excluded.branch_parent_position, - branch_created_at = excluded.branch_created_at`, + parent_id = excluded.parent_id`, session.ID, session.ToolsApproved, session.InputTokens, session.OutputTokens, session.Title, session.Cost, session.SendUserMessage, session.MaxIterations, session.WorkingDir, session.CreatedAt.Format(time.RFC3339), session.Starred, permissionsJSON, agentModelOverridesJSON, - customModelsUsedJSON, session.Thinking, parentID, branchParentID, branchParentPosition, branchCreatedAt) + customModelsUsedJSON, session.Thinking, parentID) if err != nil { return err } @@ -1265,32 +1204,18 @@ func (s *SQLiteSessionStore) addSessionTx(ctx context.Context, tx *sql.Tx, sessi if session.ParentID != "" { parentID = session.ParentID } - var branchParentID any - if session.BranchParentSessionID != "" { - branchParentID = session.BranchParentSessionID - } - var branchParentPosition any - if session.BranchParentPosition != nil { - branchParentPosition = *session.BranchParentPosition - } - var branchCreatedAt any - if session.BranchCreatedAt != nil { - branchCreatedAt = session.BranchCreatedAt.Format(time.RFC3339) - } - _, err := tx.ExecContext(ctx, `INSERT INTO sessions ( id, tools_approved, input_tokens, output_tokens, title, cost, send_user_message, max_iterations, working_dir, created_at, starred, permissions, agent_model_overrides, - custom_models_used, thinking, parent_id, branch_parent_session_id, - branch_parent_position, branch_created_at + custom_models_used, thinking, parent_id ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, session.ID, session.ToolsApproved, session.InputTokens, session.OutputTokens, session.Title, session.Cost, session.SendUserMessage, session.MaxIterations, session.WorkingDir, session.CreatedAt.Format(time.RFC3339), session.Starred, permissionsJSON, agentModelOverridesJSON, customModelsUsedJSON, session.Thinking, - parentID, branchParentID, branchParentPosition, branchCreatedAt) + parentID) return err } diff --git a/pkg/session/store_test.go b/pkg/session/store_test.go index ba0719e97..a82ca2a1a 100644 --- a/pkg/session/store_test.go +++ b/pkg/session/store_test.go @@ -253,17 +253,9 @@ func TestBranchSessionCopiesPrefix(t *testing.T) { require.NoError(t, err) require.NoError(t, store.AddSession(t.Context(), branched)) - require.NotNil(t, branched.BranchParentPosition) - assert.Equal(t, parent.ID, branched.BranchParentSessionID) - assert.Equal(t, 2, *branched.BranchParentPosition) - require.NotNil(t, branched.BranchCreatedAt) loaded, err := store.GetSession(t.Context(), branched.ID) require.NoError(t, err) - require.NotNil(t, loaded.BranchParentPosition) - assert.Equal(t, parent.ID, loaded.BranchParentSessionID) - assert.Equal(t, 2, *loaded.BranchParentPosition) - require.NotNil(t, loaded.BranchCreatedAt) require.Len(t, loaded.Messages, 2) assert.Equal(t, "Hello", loaded.Messages[0].Message.Message.Content)