Skip to content

Commit eac671d

Browse files
authored
Merge pull request #710 from 1024XEngineer/fennoai/issue-709-1780675838
简化 context builder 的防御性兼容逻辑
2 parents b622b51 + 56ba6bb commit eac671d

2 files changed

Lines changed: 37 additions & 39 deletions

File tree

internal/context/builder.go

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,18 @@ import (
88
type DefaultBuilder struct {
99
stablePromptSources []promptSectionSource
1010
dynamicPromptSources []promptSectionSource
11-
promptSources []promptSectionSource
1211
trimPolicy messageTrimPolicy
1312
}
1413

1514
// newStablePromptSources 返回稳定提示词来源列表,适合作为缓存前缀。
16-
// extra 中的非 nil SectionSource 也会追加到 stable 中(如 memo 持久记忆索引)。
15+
// extra 会追加到 stable 中(如 memo 持久记忆索引)。
1716
func newStablePromptSources(extra ...SectionSource) []promptSectionSource {
1817
sources := []promptSectionSource{
1918
corePromptSource{},
2019
newRulesPromptSource(nil),
2120
}
2221
for _, src := range extra {
23-
if src != nil {
24-
sources = append(sources, src)
25-
}
22+
sources = append(sources, src)
2623
}
2724
return sources
2825
}
@@ -41,7 +38,6 @@ func newDynamicPromptSources() []promptSectionSource {
4138
}
4239

4340
// NewConfiguredBuilder 基于可选 SectionSource 列表构建上下文构建器,是推荐的统一构造入口。
44-
// sources 中 nil 元素会被跳过。
4541
func NewConfiguredBuilder(sources ...SectionSource) Builder {
4642
return &DefaultBuilder{
4743
stablePromptSources: newStablePromptSources(sources...),
@@ -74,29 +70,17 @@ func (b *DefaultBuilder) Build(ctx context.Context, input BuildInput) (BuildResu
7470
return BuildResult{}, err
7571
}
7672

77-
stableSources := b.stablePromptSources
78-
dynamicSources := b.dynamicPromptSources
79-
80-
// 兼容旧构造方式:如果新字段未设置但旧 promptSources 有内容,回退到旧单列表。
81-
if len(stableSources) == 0 && len(dynamicSources) == 0 && len(b.promptSources) > 0 {
82-
stableSources = b.promptSources
73+
stableSections, err := collectPromptSections(ctx, input, b.stablePromptSources)
74+
if err != nil {
75+
return BuildResult{}, err
8376
}
77+
stablePrompt := composeSystemPrompt(stableSections...)
8478

85-
var stablePrompt, dynamicPrompt string
86-
if stableSources != nil {
87-
stableSections, err := collectPromptSections(ctx, input, stableSources)
88-
if err != nil {
89-
return BuildResult{}, err
90-
}
91-
stablePrompt = composeSystemPrompt(stableSections...)
92-
}
93-
if dynamicSources != nil {
94-
dynamicSections, err := collectPromptSections(ctx, input, dynamicSources)
95-
if err != nil {
96-
return BuildResult{}, err
97-
}
98-
dynamicPrompt = composeSystemPrompt(dynamicSections...)
79+
dynamicSections, err := collectPromptSections(ctx, input, b.dynamicPromptSources)
80+
if err != nil {
81+
return BuildResult{}, err
9982
}
83+
dynamicPrompt := composeSystemPrompt(dynamicSections...)
10084

10185
systemPrompt := joinSystemPromptParts(stablePrompt, dynamicPrompt)
10286

internal/context/builder_test.go

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,12 @@ func TestDefaultBuilderBuildPlacesRulesBeforeMemo(t *testing.T) {
263263
}
264264

265265
builder := &DefaultBuilder{
266-
promptSources: []promptSectionSource{
266+
stablePromptSources: []promptSectionSource{
267267
corePromptSource{},
268268
newRulesPromptSource(rules.NewLoader(baseDir)),
269269
stubPromptSectionSource{sections: []promptSection{{Title: "Memo", Content: "remember this"}}},
270+
},
271+
dynamicPromptSources: []promptSectionSource{
270272
&systemStateSource{},
271273
},
272274
}
@@ -312,7 +314,7 @@ func TestDefaultBuilderBuildUsesSpanTrimPolicyWhenTrimPolicyIsUnset(t *testing.T
312314
}
313315

314316
builder := &DefaultBuilder{
315-
promptSources: []promptSectionSource{
317+
stablePromptSources: []promptSectionSource{
316318
stubPromptSectionSource{sections: []promptSection{{Title: "Stub", Content: "body"}}},
317319
},
318320
}
@@ -337,7 +339,7 @@ func TestDefaultBuilderBuildReturnsPromptSourceError(t *testing.T) {
337339
t.Parallel()
338340

339341
builder := &DefaultBuilder{
340-
promptSources: []promptSectionSource{
342+
stablePromptSources: []promptSectionSource{
341343
stubPromptSectionSource{err: fmt.Errorf("source failed")},
342344
},
343345
}
@@ -643,10 +645,12 @@ func TestNewConfiguredBuilder(t *testing.T) {
643645
}
644646
})
645647

646-
t.Run("nil section sources are skipped", func(t *testing.T) {
647-
builder := NewConfiguredBuilder(nil, stubPromptSectionSource{
648+
t.Run("multiple extra section sources are appended", func(t *testing.T) {
649+
builder := NewConfiguredBuilder(stubPromptSectionSource{
650+
sections: []promptSection{{Title: "First", Content: "first body"}},
651+
}, stubPromptSectionSource{
648652
sections: []promptSection{{Title: "Extra", Content: "extra body"}},
649-
}, nil)
653+
})
650654
input := BuildInput{
651655
Messages: []providertypes.Message{{Role: "user", Parts: []providertypes.ContentPart{providertypes.NewTextPart("hello")}}},
652656
Metadata: testMetadata(t.TempDir()),
@@ -658,6 +662,9 @@ func TestNewConfiguredBuilder(t *testing.T) {
658662
if !strings.Contains(result.SystemPrompt, "## Extra") {
659663
t.Errorf("expected Extra section in system prompt")
660664
}
665+
if !strings.Contains(result.SystemPrompt, "## First") {
666+
t.Errorf("expected First section in system prompt")
667+
}
661668
})
662669
}
663670

@@ -895,23 +902,30 @@ func TestDefaultBuilderBuildMemoIsStable(t *testing.T) {
895902
}
896903
}
897904

898-
func TestDefaultBuilderBuildStableAndDynamicPreservesBackwardCompat(t *testing.T) {
905+
func TestDefaultBuilderBuildStableAndDynamicFields(t *testing.T) {
899906
t.Parallel()
900907

901908
builder := &DefaultBuilder{
902-
promptSources: []promptSectionSource{
903-
stubPromptSectionSource{sections: []promptSection{{Title: "Old", Content: "old style"}}},
909+
stablePromptSources: []promptSectionSource{
910+
stubPromptSectionSource{sections: []promptSection{{Title: "Stable", Content: "stable style"}}},
904911
},
912+
dynamicPromptSources: []promptSectionSource{
913+
stubPromptSectionSource{sections: []promptSection{{Title: "Dynamic", Content: "dynamic style"}}},
914+
},
915+
trimPolicy: spanMessageTrimPolicy{},
905916
}
906917

907918
result, err := builder.Build(stdcontext.Background(), BuildInput{})
908919
if err != nil {
909920
t.Fatalf("Build() error = %v", err)
910921
}
911-
if !strings.Contains(result.SystemPrompt, "old style") {
912-
t.Fatalf("expected old style content in system prompt, got %q", result.SystemPrompt)
922+
if !strings.Contains(result.SystemPrompt, "stable style") || !strings.Contains(result.SystemPrompt, "dynamic style") {
923+
t.Fatalf("expected stable and dynamic content in system prompt, got %q", result.SystemPrompt)
924+
}
925+
if !strings.Contains(result.StableSystemPrompt, "stable style") {
926+
t.Fatalf("expected stable content in StableSystemPrompt, got %q", result.StableSystemPrompt)
913927
}
914-
if !strings.Contains(result.StableSystemPrompt, "old style") {
915-
t.Fatalf("expected old style content in StableSystemPrompt, got %q", result.StableSystemPrompt)
928+
if !strings.Contains(result.DynamicSystemPrompt, "dynamic style") {
929+
t.Fatalf("expected dynamic content in DynamicSystemPrompt, got %q", result.DynamicSystemPrompt)
916930
}
917931
}

0 commit comments

Comments
 (0)