Detailed changes
@@ -86,11 +86,11 @@ func formatAsJSON(content string) string {
jsonBytes, err := json.MarshalIndent(response, "", " ")
if err != nil {
// In case of an error, return a manually formatted JSON
- jsonEscaped := strings.Replace(content, "\\", "\\\\", -1)
- jsonEscaped = strings.Replace(jsonEscaped, "\"", "\\\"", -1)
- jsonEscaped = strings.Replace(jsonEscaped, "\n", "\\n", -1)
- jsonEscaped = strings.Replace(jsonEscaped, "\r", "\\r", -1)
- jsonEscaped = strings.Replace(jsonEscaped, "\t", "\\t", -1)
+ jsonEscaped := strings.ReplaceAll(content, "\\", "\\\\")
+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\"", "\\\"")
+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\n", "\\n")
+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\r", "\\r")
+ jsonEscaped = strings.ReplaceAll(jsonEscaped, "\t", "\\t")
return fmt.Sprintf("{\n \"response\": \"%s\"\n}", jsonEscaped)
}
@@ -135,7 +135,7 @@ func (a *agent) Cancel(sessionID string) {
func (a *agent) IsBusy() bool {
busy := false
- a.activeRequests.Range(func(key, value interface{}) bool {
+ a.activeRequests.Range(func(key, value any) bool {
if cancelFunc, ok := value.(context.CancelFunc); ok {
if cancelFunc != nil {
busy = true
@@ -273,9 +273,10 @@ func (a *anthropicClient) stream(ctx context.Context, messages []message.Message
switch event := event.AsAny().(type) {
case anthropic.ContentBlockStartEvent:
- if event.ContentBlock.Type == "text" {
+ switch event.ContentBlock.Type {
+ case "text":
eventChan <- ProviderEvent{Type: EventContentStart}
- } else if event.ContentBlock.Type == "tool_use" {
+ case "tool_use":
currentToolCallID = event.ContentBlock.ID
eventChan <- ProviderEvent{
Type: EventToolUseStart,
@@ -96,7 +96,7 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont
case message.Tool:
for _, result := range msg.ToolResults() {
- response := map[string]interface{}{"result": result.Content}
+ response := map[string]any{"result": result.Content}
parsed, err := parseJsonToMap(result.Content)
if err == nil {
response = parsed
@@ -155,10 +155,10 @@ func (g *geminiClient) convertTools(tools []tools.BaseTool) []*genai.Tool {
}
func (g *geminiClient) finishReason(reason genai.FinishReason) message.FinishReason {
- switch {
- case reason == genai.FinishReasonStop:
+ switch reason {
+ case genai.FinishReasonStop:
return message.FinishReasonEndTurn
- case reason == genai.FinishReasonMaxTokens:
+ case genai.FinishReasonMaxTokens:
return message.FinishReasonMaxTokens
default:
return message.FinishReasonUnknown
@@ -402,12 +402,9 @@ func (g *geminiClient) shouldRetry(attempts int, err error) (bool, int64, error)
}
errMsg := err.Error()
- isRateLimit := false
+ isRateLimit := contains(errMsg, "rate limit", "quota exceeded", "too many requests")
// Check for common rate limit error messages
- if contains(errMsg, "rate limit", "quota exceeded", "too many requests") {
- isRateLimit = true
- }
if !isRateLimit {
return false, 0, err
@@ -462,13 +459,13 @@ func WithGeminiDisableCache() GeminiOption {
}
// Helper functions
-func parseJsonToMap(jsonStr string) (map[string]interface{}, error) {
- var result map[string]interface{}
+func parseJsonToMap(jsonStr string) (map[string]any, error) {
+ var result map[string]any
err := json.Unmarshal([]byte(jsonStr), &result)
return result, err
}
-func convertSchemaProperties(parameters map[string]interface{}) map[string]*genai.Schema {
+func convertSchemaProperties(parameters map[string]any) map[string]*genai.Schema {
properties := make(map[string]*genai.Schema)
for name, param := range parameters {
@@ -478,10 +475,10 @@ func convertSchemaProperties(parameters map[string]interface{}) map[string]*gena
return properties
}
-func convertToSchema(param interface{}) *genai.Schema {
+func convertToSchema(param any) *genai.Schema {
schema := &genai.Schema{Type: genai.TypeString}
- paramMap, ok := param.(map[string]interface{})
+ paramMap, ok := param.(map[string]any)
if !ok {
return schema
}
@@ -506,7 +503,7 @@ func convertToSchema(param interface{}) *genai.Schema {
case "array":
schema.Items = processArrayItems(paramMap)
case "object":
- if props, ok := paramMap["properties"].(map[string]interface{}); ok {
+ if props, ok := paramMap["properties"].(map[string]any); ok {
schema.Properties = convertSchemaProperties(props)
}
}
@@ -514,8 +511,8 @@ func convertToSchema(param interface{}) *genai.Schema {
return schema
}
-func processArrayItems(paramMap map[string]interface{}) *genai.Schema {
- items, ok := paramMap["items"].(map[string]interface{})
+func processArrayItems(paramMap map[string]any) *genai.Schema {
+ items, ok := paramMap["items"].(map[string]any)
if !ok {
return nil
}
@@ -284,7 +284,7 @@ func (o *openaiClient) stream(ctx context.Context, messages []message.Message, t
if err == nil || errors.Is(err, io.EOF) {
// Stream completed successfully
finishReason := o.finishReason(string(acc.ChatCompletion.Choices[0].FinishReason))
- if len(acc.ChatCompletion.Choices[0].Message.ToolCalls) > 0 {
+ if len(acc.Choices[0].Message.ToolCalls) > 0 {
toolCalls = append(toolCalls, o.toolCalls(acc.ChatCompletion)...)
}
if len(toolCalls) > 0 {
@@ -2,58 +2,41 @@ package tools
import (
"runtime"
+ "slices"
"testing"
)
func TestGetSafeReadOnlyCommands(t *testing.T) {
commands := getSafeReadOnlyCommands()
-
+
// Check that we have some commands
if len(commands) == 0 {
t.Fatal("Expected some safe commands, got none")
}
-
+
// Check for cross-platform commands that should always be present
crossPlatformCommands := []string{"echo", "hostname", "whoami", "git status", "go version"}
for _, cmd := range crossPlatformCommands {
- found := false
- for _, safeCmd := range commands {
- if safeCmd == cmd {
- found = true
- break
- }
- }
+ found := slices.Contains(commands, cmd)
if !found {
t.Errorf("Expected cross-platform command %q to be in safe commands", cmd)
}
}
-
+
if runtime.GOOS == "windows" {
// Check for Windows-specific commands
windowsCommands := []string{"dir", "type", "Get-Process"}
for _, cmd := range windowsCommands {
- found := false
- for _, safeCmd := range commands {
- if safeCmd == cmd {
- found = true
- break
- }
- }
+ found := slices.Contains(commands, cmd)
if !found {
t.Errorf("Expected Windows command %q to be in safe commands on Windows", cmd)
}
}
-
+
// Check that Unix commands are NOT present on Windows
unixCommands := []string{"ls", "pwd", "ps"}
for _, cmd := range unixCommands {
- found := false
- for _, safeCmd := range commands {
- if safeCmd == cmd {
- found = true
- break
- }
- }
+ found := slices.Contains(commands, cmd)
if found {
t.Errorf("Unix command %q should not be in safe commands on Windows", cmd)
}
@@ -62,28 +45,16 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
// Check for Unix-specific commands
unixCommands := []string{"ls", "pwd", "ps"}
for _, cmd := range unixCommands {
- found := false
- for _, safeCmd := range commands {
- if safeCmd == cmd {
- found = true
- break
- }
- }
+ found := slices.Contains(commands, cmd)
if !found {
t.Errorf("Expected Unix command %q to be in safe commands on Unix", cmd)
}
}
-
+
// Check that Windows-specific commands are NOT present on Unix
windowsOnlyCommands := []string{"dir", "Get-Process", "systeminfo"}
for _, cmd := range windowsOnlyCommands {
- found := false
- for _, safeCmd := range commands {
- if safeCmd == cmd {
- found = true
- break
- }
- }
+ found := slices.Contains(commands, cmd)
if found {
t.Errorf("Windows-only command %q should not be in safe commands on Unix", cmd)
}
@@ -94,10 +65,10 @@ func TestGetSafeReadOnlyCommands(t *testing.T) {
func TestPlatformSpecificSafeCommands(t *testing.T) {
// Test that the function returns different results on different platforms
commands := getSafeReadOnlyCommands()
-
+
hasWindowsCommands := false
hasUnixCommands := false
-
+
for _, cmd := range commands {
if cmd == "dir" || cmd == "Get-Process" || cmd == "systeminfo" {
hasWindowsCommands = true
@@ -106,7 +77,7 @@ func TestPlatformSpecificSafeCommands(t *testing.T) {
hasUnixCommands = true
}
}
-
+
if runtime.GOOS == "windows" {
if !hasWindowsCommands {
t.Error("Expected Windows commands on Windows platform")
@@ -122,4 +93,5 @@ func TestPlatformSpecificSafeCommands(t *testing.T) {
t.Error("Expected Unix commands on Unix platform")
}
}
-}
+}
+
@@ -116,10 +116,7 @@ func (s *permissionService) Request(opts CreatePermissionRequest) bool {
s.Publish(pubsub.CreatedEvent, permission)
// Wait for the response indefinitely
- select {
- case resp := <-respCh:
- return resp
- }
+ return <-respCh
}
func (s *permissionService) AutoApproveSession(sessionID string) {
@@ -112,7 +112,7 @@ func (br baseRenderer) unmarshalParams(input string, target any) error {
}
// makeHeader builds the tool call header with status icon and parameters for a nested tool call.
-func (br baseRenderer) makeNestedHeader(v *toolCallCmp, tool string, width int, params ...string) string {
+func (br baseRenderer) makeNestedHeader(_ *toolCallCmp, tool string, width int, params ...string) string {
t := styles.CurrentTheme()
tool = t.S().Base.Foreground(t.FgHalfMuted).Render(tool) + " "
return tool + renderParamList(true, width-lipgloss.Width(tool), params...)