Skip to content

Commit 6254886

Browse files
committed
feat: enhance code reusability in summarization
1 parent 28537fa commit 6254886

5 files changed

Lines changed: 114 additions & 413 deletions

File tree

adk/middlewares/summarization/consts.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ const (
2525
)
2626

2727
const (
28-
extraKeyContentType = "_eino_summarization_content_type"
28+
extraKeyContentType = "_eino_summarization_content_type"
29+
preserveUserMsgsMaxTokens = 30000
2930
)
3031

3132
type summarizationContentType string

adk/middlewares/summarization/finalizer_builder.go

Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -28,84 +28,24 @@ import (
2828
"github.com/cloudwego/eino/schema"
2929
)
3030

31-
type DefaultFinalizerConfig[M adk.MessageType] struct {
32-
// PreserveUserMessages controls whether to preserve original user messages in the summary.
33-
// When enabled, replaces the <all_user_messages>...</all_user_messages> section in the
34-
// model-generated summary with recent original user messages from the conversation.
35-
// Optional. Enabled by default when config is nil or Enabled is true.
36-
PreserveUserMessages *TypedPreserveUserMessages[M]
37-
38-
// TranscriptFilePath is the path to the file containing the full conversation history.
39-
// When set, appends a note to the summary indicating where to find the original context.
40-
// Optional.
41-
TranscriptFilePath string
42-
}
43-
44-
// DefaultFinalizer is the default TypedFinalizeFunc implementation, providing the same
45-
// summary post-processing as the middleware does.
46-
// e.g. replacing user messages in the summary.
47-
func DefaultFinalizer[M adk.MessageType](cfg *DefaultFinalizerConfig[M]) (TypedFinalizeFunc[M], error) {
48-
const defaultPreserveUserMessagesMaxTokens = 30000
49-
50-
if cfg == nil {
51-
cfg = &DefaultFinalizerConfig[M]{}
52-
}
53-
54-
preserveEnabled := cfg.PreserveUserMessages == nil || cfg.PreserveUserMessages.Enabled
55-
preserveCfg := cfg.PreserveUserMessages
56-
transcriptPath := cfg.TranscriptFilePath
57-
58-
if preserveCfg != nil && preserveCfg.MaxTokens < 0 {
59-
return nil, fmt.Errorf("preserveUserMessages.MaxTokens must be non-negative")
31+
// DefaultFinalize is the default TypedFinalizeFunc implementation, providing the same
32+
// summary post-processing as the middleware does internally:
33+
// 1. Replaces the <all_user_messages>...</all_user_messages> section in the model-generated
34+
// summary with recent original user messages from the conversation (up to ~30k tokens).
35+
// 2. Adds a preamble and a postamble around the summary content.
36+
// 3. Converts the summary into a user message, prepended with the original system messages.
37+
func DefaultFinalize[M adk.MessageType](ctx context.Context, originalMessages []M, summary M) ([]M, error) {
38+
systemMsgs, contextMsgs := splitSystemAndContextMsgs(originalMessages)
39+
40+
processed, err := postProcessSummary(ctx, &postProcessSummaryParams[M]{
41+
contextMsgs: contextMsgs,
42+
summaryContent: getAssistantTextContent(summary),
43+
})
44+
if err != nil {
45+
return nil, err
6046
}
6147

62-
return func(ctx context.Context, originalMessages []M, summary M) ([]M, error) {
63-
var systemMsgs []M
64-
var contextMsgs []M
65-
for i, msg := range originalMessages {
66-
if !isSystemRole(msg) {
67-
systemMsgs = originalMessages[:i]
68-
contextMsgs = originalMessages[i:]
69-
break
70-
}
71-
}
72-
73-
content := getUserMsgTextContent(summary)
74-
75-
if preserveEnabled && len(contextMsgs) > 0 {
76-
maxTokens := defaultPreserveUserMessagesMaxTokens
77-
if preserveCfg != nil && preserveCfg.MaxTokens > 0 {
78-
maxTokens = preserveCfg.MaxTokens
79-
}
80-
81-
var filter TypedUserMessageFilterFunc[M]
82-
if preserveCfg != nil {
83-
filter = preserveCfg.Filter
84-
}
85-
86-
newContent, err := replaceUserMessagesInSummary(ctx, &replaceUserMessagesInSummaryParams[M]{
87-
contextMsgs: contextMsgs,
88-
summaryText: content,
89-
maxTokens: maxTokens,
90-
filter: filter,
91-
tokenCounter: nil,
92-
})
93-
if err != nil {
94-
return nil, err
95-
}
96-
content = newContent
97-
}
98-
99-
if transcriptPath != "" {
100-
content = appendSection(content, fmt.Sprintf(getTranscriptPathInstruction(), transcriptPath))
101-
}
102-
103-
content = appendSection(getSummaryPreamble(), content)
104-
105-
newSummary := overwriteMsgContent(summary, content, getContinueInstruction())
106-
107-
return append(systemMsgs, newSummary), nil
108-
}, nil
48+
return append(systemMsgs, processed), nil
10949
}
11050

11151
// TypedFinalizerBuilder builds a TypedFinalizeFunc by chaining handlers

adk/middlewares/summarization/prompt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ const summaryPreambleZh = `此会话延续自此前一段因上下文耗尽而
301301

302302
const continueInstruction = `Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening, do not preface with "I'll continue" or similar. Pick up the last task as if the break never happened.`
303303

304-
const continueInstructionZh = `从对话中断的地方继续,不要再问用户任何问题。直接继续——不要回应摘要,不要复述之前的经过,不要以"我会继续"之类的话作为开场白。就像中断从未发生过一样,继续上次的任务。`
304+
const continueInstructionZh = `从对话中断的地方继续,不要再问用户任何问题。直接继续——不要提及总结,不要复述之前的经过,不要以"我会继续"之类的话作为开场白。就像中断从未发生过一样,继续上次的任务。`
305305

306306
const transcriptPathInstruction = `If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: %s`
307307

0 commit comments

Comments
 (0)