From d167c94cddef5223729f9938600b2ef51fd8074d Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Tue, 24 Feb 2026 15:43:41 +0900 Subject: [PATCH] perf: reduce []byte/string conversions and add ASCII fast paths - bytes.NewReader instead of strings.NewReader(string(...)) in web search - Consolidate multiple string(body) calls into single variable - sb.Write(paramsJSON) instead of string conversion in CLI provider - ASCII fast paths in Truncate/wrapLine before []rune conversion - Byte-length truncation for ASCII-only branch names - Extract runeDisplayWidth to avoid per-rune string(r) in wrap loop Co-Authored-By: Claude Opus 4.6 --- pkg/channels/telegram.go | 44 +++++++++++++++------------- pkg/git/worktree.go | 9 +++--- pkg/providers/claude_cli_provider.go | 4 ++- pkg/tools/web.go | 11 +++---- pkg/utils/string.go | 8 +++++ 5 files changed, 45 insertions(+), 31 deletions(-) diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index c422e9fec..b83602389 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -1036,28 +1036,32 @@ func formatMarkdownTable(lines []string) string { return strings.TrimRight(b.String(), "\n") } +func runeDisplayWidth(r rune) int { + switch { + case r == '\u200d' || r == '\u200c' || r == '\ufe0f': + return 0 + case unicode.Is(unicode.Mn, r): + return 0 + case isEmojiRune(r): + return 3 + case unicode.In(r, + unicode.Han, + unicode.Hiragana, + unicode.Katakana, + unicode.Hangul): + return 2 + case (r >= 0x3000 && r <= 0x303F) || (r >= 0xFF00 && r <= 0xFFEF): + // CJK symbols/punctuation and half/fullwidth forms. + return 2 + default: + return 1 + } +} + func displayWidth(s string) int { w := 0 for _, r := range s { - switch { - case r == '\u200d' || r == '\u200c' || r == '\ufe0f': - continue - case unicode.Is(unicode.Mn, r): - continue - case isEmojiRune(r): - w += 3 - case unicode.In(r, - unicode.Han, - unicode.Hiragana, - unicode.Katakana, - unicode.Hangul): - w += 2 - case (r >= 0x3000 && r <= 0x303F) || (r >= 0xFF00 && r <= 0xFFEF): - // CJK symbols/punctuation and half/fullwidth forms. - w += 2 - default: - w++ - } + w += runeDisplayWidth(r) } return w } @@ -1092,7 +1096,7 @@ func wrapByDisplayWidth(s string, maxWidth int) []string { flush() continue } - rw := displayWidth(string(r)) + rw := runeDisplayWidth(r) if rw == 0 { cur.WriteRune(r) continue diff --git a/pkg/git/worktree.go b/pkg/git/worktree.go index fbb91da1d..1923f55d9 100644 --- a/pkg/git/worktree.go +++ b/pkg/git/worktree.go @@ -67,12 +67,11 @@ func SanitizeBranchName(task string) string { s = "worktree" } - // Truncate to 40 chars - runes := []rune(s) - if len(runes) > 40 { - runes = runes[:40] + // Truncate to 40 chars (ASCII fast path: branch names are ASCII after sanitization) + if len(s) > 40 { + s = s[:40] } - s = strings.TrimRight(string(runes), "-") + s = strings.TrimRight(s, "-") return "plan/" + s } diff --git a/pkg/providers/claude_cli_provider.go b/pkg/providers/claude_cli_provider.go index 74ec33b98..6074a8ee1 100644 --- a/pkg/providers/claude_cli_provider.go +++ b/pkg/providers/claude_cli_provider.go @@ -130,7 +130,9 @@ func (p *ClaudeCliProvider) buildToolsPrompt(tools []ToolDefinition) string { } if len(tool.Function.Parameters) > 0 { paramsJSON, _ := json.Marshal(tool.Function.Parameters) - sb.WriteString(fmt.Sprintf("Parameters:\n```json\n%s\n```\n", string(paramsJSON))) + sb.WriteString("Parameters:\n```json\n") + sb.Write(paramsJSON) + sb.WriteString("\n```\n") } sb.WriteString("\n") } diff --git a/pkg/tools/web.go b/pkg/tools/web.go index 6e177ec8d..445c8d718 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -278,7 +278,7 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou return "", fmt.Errorf("failed to marshal request: %w", err) } - req, err := http.NewRequestWithContext(ctx, "POST", searchURL, strings.NewReader(string(payloadBytes))) + req, err := http.NewRequestWithContext(ctx, "POST", searchURL, bytes.NewReader(payloadBytes)) if err != nil { return "", fmt.Errorf("failed to create request: %w", err) } @@ -534,6 +534,7 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolRe var text, extractor string + bodyStr := string(body) if strings.Contains(contentType, "application/json") { var jsonData any if err := json.Unmarshal(body, &jsonData); err == nil { @@ -541,15 +542,15 @@ func (t *WebFetchTool) Execute(ctx context.Context, args map[string]any) *ToolRe text = string(formatted) extractor = "json" } else { - text = string(body) + text = bodyStr extractor = "raw" } } else if strings.Contains(contentType, "text/html") || len(body) > 0 && - (strings.HasPrefix(string(body), "