-
Notifications
You must be signed in to change notification settings - Fork 7
refactor(context): system prompt section 化重构 #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,23 +2,83 @@ package context | |
|
|
||
| import "strings" | ||
|
|
||
| func defaultSystemPrompt() string { | ||
| return `You are NeoCode, a local coding agent. | ||
| type promptSection struct { | ||
| title string | ||
| content string | ||
| } | ||
|
|
||
| var defaultPromptSections = []promptSection{ | ||
| { | ||
| title: "Agent Identity", | ||
| content: "You are NeoCode, a local coding agent focused on completing the current task end-to-end.\n" + | ||
| "Preserve the main loop of user input, agent reasoning, tool execution, result observation, and UI feedback.", | ||
| }, | ||
| { | ||
| title: "Tool Usage", | ||
| content: "- Use tools when they reduce uncertainty or are required to complete the task safely.\n" + | ||
| "- Inspect tool failures, explain the relevant error, and continue with the safest useful next step.\n" + | ||
| "- Do not claim work is done unless the needed files, commands, or verification actually succeeded.", | ||
| }, | ||
| { | ||
| title: "Workspace Safety", | ||
| content: "- Stay within the current workspace unless the user clearly asks for something else.\n" + | ||
| "- Avoid destructive actions such as deleting files, rewriting unrelated work, or changing history unless explicitly requested.\n" + | ||
| "- Respect project rules and local constraints before making changes.", | ||
| }, | ||
| { | ||
| title: "Code Changes", | ||
| content: "- Prefer minimal, testable changes that keep module boundaries clear.\n" + | ||
| "- Follow the existing architecture and keep provider, runtime, tools, config, and TUI responsibilities separated.\n" + | ||
| "- When behavior changes, update the relevant tests or documentation needed to keep the implementation verifiable.", | ||
| }, | ||
| { | ||
| title: "Failure Recovery", | ||
| content: "- If blocked, identify the concrete blocker and try the next reasonable path before giving up.\n" + | ||
| "- Surface risky assumptions, partial progress, or missing verification instead of hiding them.\n" + | ||
| "- When constraints prevent completion, return the best safe result and explain what remains.", | ||
| }, | ||
| { | ||
| title: "Response Style", | ||
| content: "- Be concise, accurate, and collaborative.\n" + | ||
| "- Keep updates focused on useful progress, decisions, and verification.\n" + | ||
| "- Base claims on the current workspace state instead of generic advice.", | ||
| }, | ||
| } | ||
|
|
||
| Be concise and accurate. | ||
| Use tools when necessary. | ||
| When a tool fails, inspect the error and continue safely. | ||
| Stay within the workspace and avoid destructive behavior unless clearly requested.` | ||
| func defaultSystemPromptSections() []promptSection { | ||
| return defaultPromptSections | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Performance: Repeated Allocations This function allocates a new 6-element slice and calls Suggestion: Cache the result as a package-level variable: var defaultSections = []promptSection{
{id: "agent-identity", title: "Agent Identity", content: "..."},
// ... other sections (already trimmed)
}
func defaultSystemPromptSections() []promptSection {
return defaultSections
}This eliminates 6 string allocations and 6 TrimSpace operations per Build() call.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 已处理。这次把默认 section 提升为包级缓存, |
||
|
|
||
| func composeSystemPrompt(parts ...string) string { | ||
| sections := make([]string, 0, len(parts)) | ||
| for _, part := range parts { | ||
| part = strings.TrimSpace(part) | ||
| func composeSystemPrompt(sections ...promptSection) string { | ||
| rendered := make([]string, 0, len(sections)) | ||
| for _, section := range sections { | ||
| part := renderPromptSection(section) | ||
| if part == "" { | ||
| continue | ||
| } | ||
| sections = append(sections, part) | ||
| rendered = append(rendered, part) | ||
| } | ||
| return strings.Join(rendered, "\n\n") | ||
| } | ||
|
|
||
| func renderPromptSection(section promptSection) string { | ||
| title := strings.TrimSpace(section.title) | ||
| content := strings.TrimSpace(section.content) | ||
|
|
||
| switch { | ||
| case title == "" && content == "": | ||
| return "" | ||
| case title == "": | ||
| return content | ||
| case content == "": | ||
| return "" | ||
| default: | ||
| var builder strings.Builder | ||
| builder.Grow(len(title) + len(content) + len("## \n\n")) | ||
| builder.WriteString("## ") | ||
| builder.WriteString(title) | ||
| builder.WriteString("\n\n") | ||
| builder.WriteString(content) | ||
| return builder.String() | ||
| } | ||
| return strings.Join(sections, "\n\n") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| package context | ||
|
|
||
| import "testing" | ||
|
|
||
| func TestDefaultSystemPromptSectionsReturnsCachedSections(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| sections := defaultSystemPromptSections() | ||
| if len(sections) != len(defaultPromptSections) { | ||
| t.Fatalf("expected %d default sections, got %d", len(defaultPromptSections), len(sections)) | ||
| } | ||
| if len(sections) == 0 { | ||
| t.Fatalf("expected non-empty default sections") | ||
| } | ||
| if sections[0].title != "Agent Identity" { | ||
| t.Fatalf("expected first default section title, got %q", sections[0].title) | ||
| } | ||
| } | ||
|
|
||
| func TestRenderPromptSectionBranches(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| section promptSection | ||
| want string | ||
| }{ | ||
| { | ||
| name: "empty title and content renders empty", | ||
| section: promptSection{}, | ||
| want: "", | ||
| }, | ||
| { | ||
| name: "content only renders content", | ||
| section: promptSection{ | ||
| content: "content only", | ||
| }, | ||
| want: "content only", | ||
| }, | ||
| { | ||
| name: "title only renders empty", | ||
| section: promptSection{ | ||
| title: "Title Only", | ||
| }, | ||
| want: "", | ||
| }, | ||
| { | ||
| name: "title and content render heading", | ||
| section: promptSection{ | ||
| title: "Section", | ||
| content: "body", | ||
| }, | ||
| want: "## Section\n\nbody", | ||
| }, | ||
| { | ||
| name: "title and content are trimmed before rendering", | ||
| section: promptSection{ | ||
| title: " Section ", | ||
| content: "\nbody\n", | ||
| }, | ||
| want: "## Section\n\nbody", | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| tt := tt | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| got := renderPromptSection(tt.section) | ||
| if got != tt.want { | ||
| t.Fatalf("renderPromptSection() = %q, want %q", got, tt.want) | ||
| } | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Quality: Unused Field
The
idfield is set throughout the codebase but never used anywhere. This adds cognitive overhead without providing value.Suggestion: Either remove the unused field, or add documentation explaining its reserved purpose for future use (e.g., section deduplication, lookup, or ordering).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
已处理。考虑到当前实现还没有 section 去重或查找场景,这里直接删除了未使用的
id字段,先保持结构最小化。