Skip to content

Commit 275f066

Browse files
refactor(prompt): route templates through unified context
1 parent 7165855 commit 275f066

17 files changed

Lines changed: 182 additions & 32 deletions

internal/prompt/prompt_body_templates.go

Lines changed: 140 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,150 @@ var promptTemplates = template.Must(template.New("prompt-templates").ParseFS(
146146
"templates/*.md.gotmpl",
147147
))
148148

149+
func markdownSectionFromView(view *markdownSectionView) *MarkdownSection {
150+
if view == nil {
151+
return nil
152+
}
153+
return &MarkdownSection{Heading: view.Heading, Body: view.Body}
154+
}
155+
156+
func reviewCommentsFromView(views []reviewCommentView) []ReviewCommentTemplateContext {
157+
comments := make([]ReviewCommentTemplateContext, 0, len(views))
158+
for _, view := range views {
159+
comments = append(comments, ReviewCommentTemplateContext(view))
160+
}
161+
return comments
162+
}
163+
164+
func previousReviewsFromView(views []previousReviewView) []PreviousReviewTemplateContext {
165+
reviews := make([]PreviousReviewTemplateContext, 0, len(views))
166+
for _, view := range views {
167+
reviews = append(reviews, PreviousReviewTemplateContext{
168+
Commit: view.Commit,
169+
Output: view.Output,
170+
Comments: reviewCommentsFromView(view.Comments),
171+
Available: view.Available,
172+
})
173+
}
174+
return reviews
175+
}
176+
177+
func reviewAttemptsFromView(views []reviewAttemptView) []ReviewAttemptTemplateContext {
178+
attempts := make([]ReviewAttemptTemplateContext, 0, len(views))
179+
for _, view := range views {
180+
attempts = append(attempts, ReviewAttemptTemplateContext{
181+
Label: view.Label,
182+
Agent: view.Agent,
183+
When: view.When,
184+
Output: view.Output,
185+
Comments: reviewCommentsFromView(view.Comments),
186+
})
187+
}
188+
return attempts
189+
}
190+
191+
func reviewOptionalContextFromView(view optionalSectionsView) ReviewOptionalContext {
192+
return ReviewOptionalContext{
193+
ProjectGuidelines: markdownSectionFromView(view.ProjectGuidelines),
194+
AdditionalContext: view.AdditionalContext,
195+
PreviousReviews: previousReviewsFromView(view.PreviousReviews),
196+
PreviousAttempts: reviewAttemptsFromView(view.PreviousAttempts),
197+
}
198+
}
199+
200+
func fallbackContextFromDiffSection(view diffSectionView) FallbackContext {
201+
if view.Fallback == "" {
202+
return FallbackContext{}
203+
}
204+
return FallbackContext{Mode: FallbackModeGeneric, Text: view.Fallback}
205+
}
206+
207+
func templateContextFromSingleView(view singlePromptView) TemplateContext {
208+
return TemplateContext{
209+
Review: &ReviewTemplateContext{
210+
Kind: ReviewKindSingle,
211+
Optional: reviewOptionalContextFromView(view.Optional),
212+
Subject: SubjectContext{Single: &SingleSubjectContext{
213+
Commit: view.Current.Commit,
214+
Subject: view.Current.Subject,
215+
Author: view.Current.Author,
216+
Message: view.Current.Message,
217+
}},
218+
Diff: DiffContext{Heading: view.Diff.Heading, Body: view.Diff.Body},
219+
Fallback: fallbackContextFromDiffSection(view.Diff),
220+
},
221+
}
222+
}
223+
224+
func templateContextFromRangeView(view rangePromptView) TemplateContext {
225+
entries := make([]RangeEntryContext, 0, len(view.Current.Entries))
226+
for _, entry := range view.Current.Entries {
227+
entries = append(entries, RangeEntryContext(entry))
228+
}
229+
return TemplateContext{
230+
Review: &ReviewTemplateContext{
231+
Kind: ReviewKindRange,
232+
Optional: reviewOptionalContextFromView(view.Optional),
233+
Subject: SubjectContext{Range: &RangeSubjectContext{Count: view.Current.Count, Entries: entries}},
234+
Diff: DiffContext{Heading: view.Diff.Heading, Body: view.Diff.Body},
235+
Fallback: fallbackContextFromDiffSection(view.Diff),
236+
},
237+
}
238+
}
239+
240+
func templateContextFromDirtyView(view dirtyPromptView) TemplateContext {
241+
fallback := fallbackContextFromDiffSection(view.Diff)
242+
if fallback.Text != "" {
243+
fallback.Mode = FallbackModeDirty
244+
fallback.Dirty = &DirtyFallbackContext{Body: fallback.Text}
245+
fallback.Text = ""
246+
}
247+
return TemplateContext{
248+
Review: &ReviewTemplateContext{
249+
Kind: ReviewKindDirty,
250+
Optional: reviewOptionalContextFromView(view.Optional),
251+
Subject: SubjectContext{Dirty: &DirtySubjectContext{Description: view.Current.Description}},
252+
Diff: DiffContext{Heading: view.Diff.Heading, Body: view.Diff.Body},
253+
Fallback: fallback,
254+
},
255+
}
256+
}
257+
258+
func templateContextFromAddressView(view addressPromptView) TemplateContext {
259+
attempts := make([]AddressAttemptTemplateContext, 0, len(view.PreviousAttempts))
260+
for _, attempt := range view.PreviousAttempts {
261+
attempts = append(attempts, AddressAttemptTemplateContext(attempt))
262+
}
263+
return TemplateContext{
264+
Address: &AddressTemplateContext{
265+
ProjectGuidelines: markdownSectionFromView(view.ProjectGuidelines),
266+
PreviousAttempts: attempts,
267+
SeverityFilter: view.SeverityFilter,
268+
ReviewFindings: view.ReviewFindings,
269+
OriginalDiff: view.OriginalDiff,
270+
JobID: view.JobID,
271+
},
272+
}
273+
}
274+
275+
func templateContextFromSystemView(view systemPromptView) TemplateContext {
276+
return TemplateContext{System: &SystemTemplateContext{NoSkillsInstruction: view.NoSkillsInstruction, CurrentDate: view.CurrentDate}}
277+
}
278+
149279
func renderSinglePrompt(view singlePromptView) (string, error) {
150-
return executePromptTemplate("assembled_single.md.gotmpl", view)
280+
return executePromptTemplate("assembled_single.md.gotmpl", templateContextFromSingleView(view))
151281
}
152282

153283
func renderRangePrompt(view rangePromptView) (string, error) {
154-
return executePromptTemplate("assembled_range.md.gotmpl", view)
284+
return executePromptTemplate("assembled_range.md.gotmpl", templateContextFromRangeView(view))
155285
}
156286

157287
func renderDirtyPrompt(view dirtyPromptView) (string, error) {
158-
return executePromptTemplate("assembled_dirty.md.gotmpl", view)
288+
return executePromptTemplate("assembled_dirty.md.gotmpl", templateContextFromDirtyView(view))
159289
}
160290

161291
func renderAddressPrompt(view addressPromptView) (string, error) {
162-
return executePromptTemplate("assembled_address.md.gotmpl", view)
292+
return executePromptTemplate("assembled_address.md.gotmpl", templateContextFromAddressView(view))
163293
}
164294

165295
func fitSinglePrompt(limit int, view singlePromptView) (string, error) {
@@ -313,7 +443,7 @@ func trimOptionalSections(view *optionalSectionsView) bool {
313443
}
314444

315445
func renderSystemPrompt(name string, view systemPromptView) (string, error) {
316-
return executePromptTemplate(name, view)
446+
return executePromptTemplate(name, templateContextFromSystemView(view))
317447
}
318448

319449
func renderAddressPromptFromSections(view addressPromptView) (string, error) {
@@ -357,7 +487,11 @@ func renderDirtyChangesSection(view dirtyChangesSectionView) (string, error) {
357487
}
358488

359489
func renderDiffBlock(view diffSectionView) (string, error) {
360-
return executePromptTemplate("diff_block", view)
490+
ctx := ReviewTemplateContext{
491+
Diff: DiffContext{Heading: view.Heading, Body: view.Body},
492+
Fallback: fallbackContextFromDiffSection(view),
493+
}
494+
return executePromptTemplate("diff_block", ctx)
361495
}
362496

363497
func renderInlineDiff(body string) (string, error) {

internal/prompt/template_context.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ const (
227227

228228
type FallbackContext struct {
229229
Mode FallbackMode
230+
Text string
230231
Commit *CommitFallbackContext
231232
Range *RangeFallbackContext
232233
Dirty *DirtyFallbackContext
@@ -255,7 +256,22 @@ func (f FallbackContext) Clone() FallbackContext {
255256
}
256257

257258
func (f FallbackContext) IsEmpty() bool {
258-
return f.Mode == FallbackModeNone && f.Commit == nil && f.Range == nil && f.Dirty == nil && f.Generic == nil
259+
return f.Mode == FallbackModeNone && f.Text == "" && f.Commit == nil && f.Range == nil && f.Dirty == nil && f.Generic == nil
260+
}
261+
262+
func (f FallbackContext) HasContent() bool {
263+
return !f.IsEmpty()
264+
}
265+
266+
func (f FallbackContext) Rendered() string {
267+
switch {
268+
case f.Text != "":
269+
return f.Text
270+
case f.Dirty != nil:
271+
return f.Dirty.Body
272+
default:
273+
return ""
274+
}
259275
}
260276

261277
type CommitFallbackContext struct {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{template "project_guidelines" .}}{{template "address_attempts" .}}{{template "address_findings" .}}
1+
{{template "project_guidelines" .Address}}{{template "address_attempts" .Address}}{{template "address_findings" .Address}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{template "optional_sections" .Optional}}{{template "dirty_changes" .Current}}{{template "diff_block" .Diff}}
1+
{{template "optional_sections" .Review.Optional}}{{template "dirty_changes" .Review.Subject.Dirty}}{{template "diff_block" .Review}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{template "optional_sections" .Optional}}{{template "commit_range" .Current}}{{template "diff_block" .Diff}}
1+
{{template "optional_sections" .Review.Optional}}{{template "commit_range" .Review.Subject.Range}}{{template "diff_block" .Review}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{template "optional_sections" .Optional}}{{template "current_commit" .Current}}{{template "diff_block" .Diff}}
1+
{{template "optional_sections" .Review.Optional}}{{template "current_commit" .Review.Subject.Single}}{{template "diff_block" .Review}}

internal/prompt/templates/claude-code_review.md.gotmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ Do not include any front matter such as "Reviewing the diff..." or "I'm checking
2424
4. **Regressions**: Changes that might break existing functionality.
2525
5. **Code quality**: Duplication, overly complex logic, unclear naming.
2626

27-
Do not review the commit message. Focus only on the code changes in the diff.{{.NoSkillsInstruction}}
27+
Do not review the commit message. Focus only on the code changes in the diff.{{.System.NoSkillsInstruction}}
2828

29-
Current date: {{.CurrentDate}} (UTC)
29+
Current date: {{.System.CurrentDate}} (UTC)

internal/prompt/templates/codex_review.md.gotmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ Do not include any front matter such as "Reviewing the diff..." or "I'm checking
2424
4. **Regressions**: Changes that might break existing functionality.
2525
5. **Code quality**: Duplication, overly complex logic, unclear naming.
2626

27-
Do not review the commit message. Focus only on the code changes in the diff.{{.NoSkillsInstruction}}
27+
Do not review the commit message. Focus only on the code changes in the diff.{{.System.NoSkillsInstruction}}
2828

29-
Current date: {{.CurrentDate}} (UTC)
29+
Current date: {{.System.CurrentDate}} (UTC)

internal/prompt/templates/default_address.md.gotmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ Changes:
2424
- <second change>
2525
...
2626

27-
Keep the summary concise (under 10 bullet points). Put the most important changes first.{{.NoSkillsInstruction}}
27+
Keep the summary concise (under 10 bullet points). Put the most important changes first.{{.System.NoSkillsInstruction}}
2828

29-
Current date: {{.CurrentDate}} (UTC)
29+
Current date: {{.System.CurrentDate}} (UTC)

internal/prompt/templates/default_design_review.md.gotmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ After reviewing, provide:
2020
4. Any missing considerations not covered by the design
2121
5. A verdict: Pass or Fail with brief justification
2222

23-
If you find no issues, state "No issues found." after the summary.{{.NoSkillsInstruction}}
23+
If you find no issues, state "No issues found." after the summary.{{.System.NoSkillsInstruction}}
2424

25-
Current date: {{.CurrentDate}} (UTC)
25+
Current date: {{.System.CurrentDate}} (UTC)

0 commit comments

Comments
 (0)