Skip to content

Commit 3e42475

Browse files
Improve summary to keep context (#159)
* improve summary to keep context * improve loop * remove debug msg
1 parent 4f0c1c6 commit 3e42475

File tree

13 files changed

+105
-54
lines changed

13 files changed

+105
-54
lines changed

internal/db/db.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/db/files.sql.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/db/messages.sql.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
ALTER TABLE sessions ADD COLUMN summary_message_id TEXT;
4+
-- +goose StatementEnd
5+
6+
-- +goose Down
7+
-- +goose StatementBegin
8+
ALTER TABLE sessions DROP COLUMN summary_message_id;
9+
-- +goose StatementEnd

internal/db/models.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/db/querier.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/db/sessions.sql.go

Lines changed: 19 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/db/sql/sessions.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ INSERT INTO sessions (
77
prompt_tokens,
88
completion_tokens,
99
cost,
10+
summary_message_id,
1011
updated_at,
1112
created_at
1213
) VALUES (
@@ -17,6 +18,7 @@ INSERT INTO sessions (
1718
?,
1819
?,
1920
?,
21+
null,
2022
strftime('%s', 'now'),
2123
strftime('%s', 'now')
2224
) RETURNING *;
@@ -38,6 +40,7 @@ SET
3840
title = ?,
3941
prompt_tokens = ?,
4042
completion_tokens = ?,
43+
summary_message_id = ?,
4144
cost = ?
4245
WHERE id = ?
4346
RETURNING *;

internal/llm/agent/agent.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"strings"
88
"sync"
9+
"time"
910

1011
"github.com/opencode-ai/opencode/internal/config"
1112
"github.com/opencode-ai/opencode/internal/llm/models"
@@ -245,6 +246,23 @@ func (a *agent) processGeneration(ctx context.Context, sessionID, content string
245246
}
246247
}()
247248
}
249+
session, err := a.sessions.Get(ctx, sessionID)
250+
if err != nil {
251+
return a.err(fmt.Errorf("failed to get session: %w", err))
252+
}
253+
if session.SummaryMessageID != "" {
254+
summaryMsgInex := -1
255+
for i, msg := range msgs {
256+
if msg.ID == session.SummaryMessageID {
257+
summaryMsgInex = i
258+
break
259+
}
260+
}
261+
if summaryMsgInex != -1 {
262+
msgs = msgs[summaryMsgInex:]
263+
msgs[0].Role = message.User
264+
}
265+
}
248266

249267
userMsg, err := a.createUserMessage(ctx, sessionID, content, attachmentParts)
250268
if err != nil {
@@ -614,37 +632,51 @@ func (a *agent) Summarize(ctx context.Context, sessionID string) error {
614632
a.Publish(pubsub.CreatedEvent, event)
615633
return
616634
}
617-
// Create a new session with the summary
618-
newSession, err := a.sessions.Create(summarizeCtx, oldSession.Title+" - Continuation")
635+
// Create a message in the new session with the summary
636+
msg, err := a.messages.Create(summarizeCtx, oldSession.ID, message.CreateMessageParams{
637+
Role: message.Assistant,
638+
Parts: []message.ContentPart{
639+
message.TextContent{Text: summary},
640+
message.Finish{
641+
Reason: message.FinishReasonEndTurn,
642+
Time: time.Now().Unix(),
643+
},
644+
},
645+
Model: a.summarizeProvider.Model().ID,
646+
})
619647
if err != nil {
620648
event = AgentEvent{
621649
Type: AgentEventTypeError,
622-
Error: fmt.Errorf("failed to create new session: %w", err),
650+
Error: fmt.Errorf("failed to create summary message: %w", err),
623651
Done: true,
624652
}
653+
625654
a.Publish(pubsub.CreatedEvent, event)
626655
return
627656
}
628-
629-
// Create a message in the new session with the summary
630-
_, err = a.messages.Create(summarizeCtx, newSession.ID, message.CreateMessageParams{
631-
Role: message.Assistant,
632-
Parts: []message.ContentPart{message.TextContent{Text: summary}},
633-
Model: a.summarizeProvider.Model().ID,
634-
})
657+
oldSession.SummaryMessageID = msg.ID
658+
oldSession.CompletionTokens = response.Usage.OutputTokens
659+
oldSession.PromptTokens = 0
660+
model := a.summarizeProvider.Model()
661+
usage := response.Usage
662+
cost := model.CostPer1MInCached/1e6*float64(usage.CacheCreationTokens) +
663+
model.CostPer1MOutCached/1e6*float64(usage.CacheReadTokens) +
664+
model.CostPer1MIn/1e6*float64(usage.InputTokens) +
665+
model.CostPer1MOut/1e6*float64(usage.OutputTokens)
666+
oldSession.Cost += cost
667+
_, err = a.sessions.Save(summarizeCtx, oldSession)
635668
if err != nil {
636669
event = AgentEvent{
637670
Type: AgentEventTypeError,
638-
Error: fmt.Errorf("failed to create summary message: %w", err),
671+
Error: fmt.Errorf("failed to save session: %w", err),
639672
Done: true,
640673
}
641-
642674
a.Publish(pubsub.CreatedEvent, event)
643-
return
644675
}
676+
645677
event = AgentEvent{
646678
Type: AgentEventTypeSummarize,
647-
SessionID: newSession.ID,
679+
SessionID: oldSession.ID,
648680
Progress: "Summary complete",
649681
Done: true,
650682
}

internal/session/session.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Session struct {
1616
MessageCount int64
1717
PromptTokens int64
1818
CompletionTokens int64
19+
SummaryMessageID string
1920
Cost float64
2021
CreatedAt int64
2122
UpdatedAt int64
@@ -105,7 +106,11 @@ func (s *service) Save(ctx context.Context, session Session) (Session, error) {
105106
Title: session.Title,
106107
PromptTokens: session.PromptTokens,
107108
CompletionTokens: session.CompletionTokens,
108-
Cost: session.Cost,
109+
SummaryMessageID: sql.NullString{
110+
String: session.SummaryMessageID,
111+
Valid: session.SummaryMessageID != "",
112+
},
113+
Cost: session.Cost,
109114
})
110115
if err != nil {
111116
return Session{}, err
@@ -135,6 +140,7 @@ func (s service) fromDBItem(item db.Session) Session {
135140
MessageCount: item.MessageCount,
136141
PromptTokens: item.PromptTokens,
137142
CompletionTokens: item.CompletionTokens,
143+
SummaryMessageID: item.SummaryMessageID.String,
138144
Cost: item.Cost,
139145
CreatedAt: item.CreatedAt,
140146
UpdatedAt: item.UpdatedAt,

internal/tui/components/chat/list.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9999
case renderFinishedMsg:
100100
m.rendering = false
101101
m.viewport.GotoBottom()
102+
case pubsub.Event[session.Session]:
103+
if msg.Type == pubsub.UpdatedEvent && msg.Payload.ID == m.session.ID {
104+
m.session = msg.Payload
105+
if m.session.SummaryMessageID == m.currentMsgID {
106+
delete(m.cachedContent, m.currentMsgID)
107+
m.renderView()
108+
}
109+
}
102110
case pubsub.Event[message.Message]:
103111
needsRerender := false
104112
if msg.Type == pubsub.CreatedEvent {
@@ -208,12 +216,15 @@ func (m *messagesCmp) renderView() {
208216
m.uiMessages = append(m.uiMessages, cache.content...)
209217
continue
210218
}
219+
isSummary := m.session.SummaryMessageID == msg.ID
220+
211221
assistantMessages := renderAssistantMessage(
212222
msg,
213223
inx,
214224
m.messages,
215225
m.app.Messages,
216226
m.currentMsgID,
227+
isSummary,
217228
m.width,
218229
pos,
219230
)

internal/tui/components/chat/message.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ func renderAssistantMessage(
120120
allMessages []message.Message, // we need this to get tool results and the user message
121121
messagesService message.Service, // We need this to get the task tool messages
122122
focusedUIMessageId string,
123+
isSummary bool,
123124
width int,
124125
position int,
125126
) []uiMessage {
@@ -168,6 +169,9 @@ func renderAssistantMessage(
168169
if content == "" {
169170
content = "*Finished without output*"
170171
}
172+
if isSummary {
173+
info = append(info, baseStyle.Width(width-1).Foreground(t.TextMuted()).Render(" (summary)"))
174+
}
171175

172176
content = renderMessage(content, false, true, width, info...)
173177
messages = append(messages, uiMessage{

internal/tui/tui.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -331,30 +331,6 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
331331

332332
if payload.Done && payload.Type == agent.AgentEventTypeSummarize {
333333
a.isCompacting = false
334-
335-
if payload.SessionID != "" {
336-
// Switch to the new session
337-
return a, func() tea.Msg {
338-
sessions, err := a.app.Sessions.List(context.Background())
339-
if err != nil {
340-
return util.InfoMsg{
341-
Type: util.InfoTypeError,
342-
Msg: "Failed to list sessions: " + err.Error(),
343-
}
344-
}
345-
346-
for _, s := range sessions {
347-
if s.ID == payload.SessionID {
348-
return dialog.SessionSelectedMsg{Session: s}
349-
}
350-
}
351-
352-
return util.InfoMsg{
353-
Type: util.InfoTypeError,
354-
Msg: "Failed to find new session",
355-
}
356-
}
357-
}
358334
return a, util.ReportInfo("Session summarization complete")
359335
} else if payload.Done && payload.Type == agent.AgentEventTypeResponse && a.selectedSession.ID != "" {
360336
model := a.app.CoderAgent.Model()

0 commit comments

Comments
 (0)