on main help sign in
Merge pull request #75 from charmbracelet/chore/modernize

follow gofmt + gopls + staticcheck reqs for modernizing

commit431a6c49f6f52b03b738f32b7895de4f2de84690 authorKujtim Hoxha <kujtimii.h@gmail.com> dateFri 27 Jun 2025, 14:05 (1 year ago) parent21e25d567d5af1
8 files changed+31−65
internal/format/format.go+5−5 internal/llm/agent/agent.go+1−1 internal/llm/provider/anthropic.go+3−2 internal/llm/provider/gemini.go+13−16 internal/llm/provider/openai.go+1−1 internal/llm/tools/bash_test.go+6−35 internal/permission/permission.go+1−4 internal/tui/components/chat/messages/renderer.go+1−1
internal/format/format.go+5−5
@@ -86,11 +86,11 @@ func formatAsJSON(content string) string {
8686 jsonBytes, err := json.MarshalIndent(response, "", " ")
8787 if err != nil {
8888 // In case of an error, return a manually formatted JSON
89− jsonEscaped := strings.Replace(content, "\\", "\\\\", -1)
90− jsonEscaped = strings.Replace(jsonEscaped, "\"", "\\\"", -1)
91− jsonEscaped = strings.Replace(jsonEscaped, "\n", "\\n", -1)
92− jsonEscaped = strings.Replace(jsonEscaped, "\r", "\\r", -1)
93− jsonEscaped = strings.Replace(jsonEscaped, "\t", "\\t", -1)
89+ jsonEscaped := strings.ReplaceAll(content, "\\", "\\\\")
90+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\"", "\\\"")
91+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\n", "\\n")
92+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\r", "\\r")
93+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\t", "\\t")
9494
9595 return fmt.Sprintf("{\n \"response\": \"%s\"\n}", jsonEscaped)
9696 }
internal/llm/agent/agent.go+1−1
@@ -135,7 +135,7 @@ func (a *agent) Cancel(sessionID string) {
135135
136136func (a *agent) IsBusy() bool {
137137 busy := false
138− a.activeRequests.Range(func(key, value interface{}) bool {
138+ a.activeRequests.Range(func(key, value any) bool {
139139 if cancelFunc, ok := value.(context.CancelFunc); ok {
140140 if cancelFunc != nil {
141141 busy = true
internal/llm/provider/anthropic.go+3−2
@@ -273,9 +273,10 @@ func (a *anthropicClient) stream(ctx context.Context, messages []message.Message
273273
274274 switch event := event.AsAny().(type) {
275275 case anthropic.ContentBlockStartEvent:
276− if event.ContentBlock.Type == "text" {
276+ switch event.ContentBlock.Type {
277+ case "text":
277278 eventChan <- ProviderEvent{Type: EventContentStart}
278− } else if event.ContentBlock.Type == "tool_use" {
279+ case "tool_use":
279280 currentToolCallID = event.ContentBlock.ID
280281 eventChan <- ProviderEvent{
281282 Type: EventToolUseStart,
internal/llm/provider/gemini.go+13−16
@@ -96,7 +96,7 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont
9696
9797 case message.Tool:
9898 for _, result := range msg.ToolResults() {
99− response := map[string]interface{}{"result": result.Content}
99+ response := map[string]any{"result": result.Content}
100100 parsed, err := parseJsonToMap(result.Content)
101101 if err == nil {
102102 response = parsed
@@ -155,10 +155,10 @@ func (g *geminiClient) convertTools(tools []tools.BaseTool) []*genai.Tool {
155155}
156156
157157func (g *geminiClient) finishReason(reason genai.FinishReason) message.FinishReason {
158− switch {
159− case reason == genai.FinishReasonStop:
158+ switch reason {
159+ case genai.FinishReasonStop:
160160 return message.FinishReasonEndTurn
161− case reason == genai.FinishReasonMaxTokens:
161+ case genai.FinishReasonMaxTokens:
162162 return message.FinishReasonMaxTokens
163163 default:
164164 return message.FinishReasonUnknown
@@ -402,12 +402,9 @@ func (g *geminiClient) shouldRetry(attempts int, err error) (bool, int64, error)
402402 }
403403
404404 errMsg := err.Error()
405− isRateLimit := false
405+ isRateLimit := contains(errMsg, "rate limit", "quota exceeded", "too many requests")
406406
407407 // Check for common rate limit error messages
408− if contains(errMsg, "rate limit", "quota exceeded", "too many requests") {
409− isRateLimit = true
410− }
411408
412409 if !isRateLimit {
413410 return false, 0, err
@@ -462,13 +459,13 @@ func WithGeminiDisableCache() GeminiOption {
462459}
463460
464461// Helper functions
465−func parseJsonToMap(jsonStr string) (map[string]interface{}, error) {
466− var result map[string]interface{}
462+func parseJsonToMap(jsonStr string) (map[string]any, error) {
463+ var result map[string]any
467464 err := json.Unmarshal([]byte(jsonStr), &result)
468465 return result, err
469466}
470467
471−func convertSchemaProperties(parameters map[string]interface{}) map[string]*genai.Schema {
468+func convertSchemaProperties(parameters map[string]any) map[string]*genai.Schema {
472469 properties := make(map[string]*genai.Schema)
473470
474471 for name, param := range parameters {
@@ -478,10 +475,10 @@ func convertSchemaProperties(parameters map[string]interface{}) map[string]*gena
478475 return properties
479476}
480477
481−func convertToSchema(param interface{}) *genai.Schema {
478+func convertToSchema(param any) *genai.Schema {
482479 schema := &genai.Schema{Type: genai.TypeString}
483480
484− paramMap, ok := param.(map[string]interface{})
481+ paramMap, ok := param.(map[string]any)
485482 if !ok {
486483 return schema
487484 }
@@ -506,7 +503,7 @@ func convertToSchema(param interface{}) *genai.Schema {
506503 case "array":
507504 schema.Items = processArrayItems(paramMap)
508505 case "object":
509− if props, ok := paramMap["properties"].(map[string]interface{}); ok {
506+ if props, ok := paramMap["properties"].(map[string]any); ok {
510507 schema.Properties = convertSchemaProperties(props)
511508 }
512509 }
@@ -514,8 +511,8 @@ func convertToSchema(param interface{}) *genai.Schema {
514511 return schema
515512}
516513
517−func processArrayItems(paramMap map[string]interface{}) *genai.Schema {
518− items, ok := paramMap["items"].(map[string]interface{})
514+func processArrayItems(paramMap map[string]any) *genai.Schema {
515+ items, ok := paramMap["items"].(map[string]any)
519516 if !ok {
520517 return nil
521518 }
internal/llm/provider/openai.go+1−1
@@ -284,7 +284,7 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t
284284 if err == nil || errors.Is(err, io.EOF) {
285285 // Stream completed successfully
286286 finishReason := o.finishReason(string(acc.ChatCompletion.Choices[0].FinishReason))
287− if len(acc.ChatCompletion.Choices[0].Message.ToolCalls) > 0 {
287+ if len(acc.Choices[0].Message.ToolCalls) > 0 {
288288 toolCalls = append(toolCalls, o.toolCalls(acc.ChatCompletion)...)
289289 }
290290 if len(toolCalls) > 0 {
internal/llm/tools/bash_test.go+6−35
@@ -2,6 +2,7 @@ package tools
22
33import (
44 "runtime"
5+ "slices"
56 "testing"
67)
78
@@ -16,13 +17,7 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
1617 // Check for cross-platform commands that should always be present
1718 crossPlatformCommands := []string{"echo", "hostname", "whoami", "git status", "go version"}
1819 for _, cmd := range crossPlatformCommands {
19− found := false
20− for _, safeCmd := range commands {
21− if safeCmd == cmd {
22− found = true
23− break
24− }
25− }
20+ found := slices.Contains(commands, cmd)
2621 if !found {
2722 t.Errorf("Expected cross-platform command %q to be in safe commands", cmd)
2823 }
@@ -32,13 +27,7 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
3227 // Check for Windows-specific commands
3328 windowsCommands := []string{"dir", "type", "Get-Process"}
3429 for _, cmd := range windowsCommands {
35− found := false
36− for _, safeCmd := range commands {
37− if safeCmd == cmd {
38− found = true
39− break
40− }
41− }
30+ found := slices.Contains(commands, cmd)
4231 if !found {
4332 t.Errorf("Expected Windows command %q to be in safe commands on Windows", cmd)
4433 }
@@ -47,13 +36,7 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
4736 // Check that Unix commands are NOT present on Windows
4837 unixCommands := []string{"ls", "pwd", "ps"}
4938 for _, cmd := range unixCommands {
50− found := false
51− for _, safeCmd := range commands {
52− if safeCmd == cmd {
53− found = true
54− break
55− }
56− }
39+ found := slices.Contains(commands, cmd)
5740 if found {
5841 t.Errorf("Unix command %q should not be in safe commands on Windows", cmd)
5942 }
@@ -62,13 +45,7 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
6245 // Check for Unix-specific commands
6346 unixCommands := []string{"ls", "pwd", "ps"}
6447 for _, cmd := range unixCommands {
65− found := false
66− for _, safeCmd := range commands {
67− if safeCmd == cmd {
68− found = true
69− break
70− }
71− }
48+ found := slices.Contains(commands, cmd)
7249 if !found {
7350 t.Errorf("Expected Unix command %q to be in safe commands on Unix", cmd)
7451 }
@@ -77,13 +54,7 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
7754 // Check that Windows-specific commands are NOT present on Unix
7855 windowsOnlyCommands := []string{"dir", "Get-Process", "systeminfo"}
7956 for _, cmd := range windowsOnlyCommands {
80− found := false
81− for _, safeCmd := range commands {
82− if safeCmd == cmd {
83− found = true
84− break
85− }
86− }
57+ found := slices.Contains(commands, cmd)
8758 if found {
8859 t.Errorf("Windows-only command %q should not be in safe commands on Unix", cmd)
8960 }
internal/permission/permission.go+1−4
@@ -116,10 +116,7 @@ func (s *permissionService) Request(opts CreatePermissionRequest) bool {
116116 s.Publish(pubsub.CreatedEvent, permission)
117117
118118 // Wait for the response indefinitely
119− select {
120− case resp := <-respCh:
121− return resp
122− }
119+ return <-respCh
123120}
124121
125122func (s *permissionService) AutoApproveSession(sessionID string) {
internal/tui/components/chat/messages/renderer.go+1−1
@@ -112,7 +112,7 @@ func (br baseRenderer) unmarshalParams(input string, target any) error {
112112}
113113
114114// makeHeader builds the tool call header with status icon and parameters for a nested tool call.
115−func (br baseRenderer) makeNestedHeader(v *toolCallCmp, tool string, width int, params ...string) string {
115+func (br baseRenderer) makeNestedHeader(_ *toolCallCmp, tool string, width int, params ...string) string {
116116 t := styles.CurrentTheme()
117117 tool = t.S().Base.Foreground(t.FgHalfMuted).Render(tool) + " "
118118 return tool + renderParamList(true, width-lipgloss.Width(tool), params...)