fix duplicate toolFeedbackArgsPreview function declaration
This commit is contained in:
parent
4ddd650be4
commit
97b1c3efec
8 changed files with 11 additions and 218 deletions
|
|
@ -14,9 +14,7 @@
|
||||||
"tool_feedback": {
|
"tool_feedback": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"max_args_length": 300,
|
"max_args_length": 300,
|
||||||
"separate_messages": false,
|
"separate_messages": false
|
||||||
"pretty_print": true,
|
|
||||||
"disable_escape_html": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4519,8 +4519,7 @@ func TestRun_PicoToolFeedbackSuppressesDuplicateInterimAssistantContent(t *testi
|
||||||
MaxTokens: 4096,
|
MaxTokens: 4096,
|
||||||
MaxToolIterations: 10,
|
MaxToolIterations: 10,
|
||||||
ToolFeedback: config.ToolFeedbackConfig{
|
ToolFeedback: config.ToolFeedbackConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
PrettyPrint: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -177,19 +176,7 @@ func toolFeedbackArgsPreview(args map[string]any, maxLen int) string {
|
||||||
args = map[string]any{}
|
args = map[string]any{}
|
||||||
}
|
}
|
||||||
|
|
||||||
argsJSON, err := json.MarshalIndent(args, "", " ")
|
argsJSON := utils.FormatArgsJSON(args, true, false)
|
||||||
if err != nil {
|
|
||||||
return utils.Truncate(fmt.Sprintf("%v", args), maxLen)
|
|
||||||
}
|
|
||||||
return utils.Truncate(string(argsJSON), maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toolFeedbackArgsPreviewWithOptions(args map[string]any, maxLen int, prettyPrint, disableEscapeHTML bool) string {
|
|
||||||
if args == nil {
|
|
||||||
args = map[string]any{}
|
|
||||||
}
|
|
||||||
|
|
||||||
argsJSON := utils.FormatArgsJSON(args, prettyPrint, disableEscapeHTML)
|
|
||||||
return utils.Truncate(argsJSON, maxLen)
|
return utils.Truncate(argsJSON, maxLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ toolLoop:
|
||||||
feedbackMsg := utils.FormatToolFeedbackMessage(
|
feedbackMsg := utils.FormatToolFeedbackMessage(
|
||||||
toolName,
|
toolName,
|
||||||
toolFeedbackExplanation,
|
toolFeedbackExplanation,
|
||||||
toolFeedbackArgsPreviewWithOptions(toolArgs, toolFeedbackMaxLen, al.cfg.Agents.Defaults.ToolFeedback.PrettyPrint, al.cfg.Agents.Defaults.ToolFeedback.DisableEscapeHTML),
|
toolFeedbackArgsPreview(toolArgs, toolFeedbackMaxLen),
|
||||||
)
|
)
|
||||||
fbCtx, fbCancel := context.WithTimeout(turnCtx, 3*time.Second)
|
fbCtx, fbCancel := context.WithTimeout(turnCtx, 3*time.Second)
|
||||||
_ = al.bus.PublishOutbound(fbCtx, outboundMessageForTurnWithKind(ts, feedbackMsg, messageKindToolFeedback))
|
_ = al.bus.PublishOutbound(fbCtx, outboundMessageForTurnWithKind(ts, feedbackMsg, messageKindToolFeedback))
|
||||||
|
|
@ -373,7 +373,7 @@ toolLoop:
|
||||||
feedbackMsg := utils.FormatToolFeedbackMessage(
|
feedbackMsg := utils.FormatToolFeedbackMessage(
|
||||||
toolName,
|
toolName,
|
||||||
toolFeedbackExplanation,
|
toolFeedbackExplanation,
|
||||||
toolFeedbackArgsPreviewWithOptions(toolArgs, toolFeedbackMaxLen, al.cfg.Agents.Defaults.ToolFeedback.PrettyPrint, al.cfg.Agents.Defaults.ToolFeedback.DisableEscapeHTML),
|
toolFeedbackArgsPreview(toolArgs, toolFeedbackMaxLen),
|
||||||
)
|
)
|
||||||
fbCtx, fbCancel := context.WithTimeout(turnCtx, 3*time.Second)
|
fbCtx, fbCancel := context.WithTimeout(turnCtx, 3*time.Second)
|
||||||
_ = al.bus.PublishOutbound(fbCtx, outboundMessageForTurnWithKind(ts, feedbackMsg, messageKindToolFeedback))
|
_ = al.bus.PublishOutbound(fbCtx, outboundMessageForTurnWithKind(ts, feedbackMsg, messageKindToolFeedback))
|
||||||
|
|
|
||||||
|
|
@ -247,11 +247,9 @@ type SubTurnConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolFeedbackConfig struct {
|
type ToolFeedbackConfig struct {
|
||||||
Enabled bool `json:"enabled" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_ENABLED"`
|
Enabled bool `json:"enabled" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_ENABLED"`
|
||||||
MaxArgsLength int `json:"max_args_length" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_MAX_ARGS_LENGTH"`
|
MaxArgsLength int `json:"max_args_length" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_MAX_ARGS_LENGTH"`
|
||||||
SeparateMessages bool `json:"separate_messages" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_SEPARATE_MESSAGES"`
|
SeparateMessages bool `json:"separate_messages" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_SEPARATE_MESSAGES"`
|
||||||
PrettyPrint bool `json:"pretty_print" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_PRETTY_PRINT"`
|
|
||||||
DisableEscapeHTML bool `json:"disable_escape_html" env:"PICOCLAW_AGENTS_DEFAULTS_TOOL_FEEDBACK_DISABLE_ESCAPE_HTML"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AgentDefaults struct {
|
type AgentDefaults struct {
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,9 @@ func DefaultConfig() *Config {
|
||||||
SummarizeTokenPercent: 75,
|
SummarizeTokenPercent: 75,
|
||||||
SteeringMode: "one-at-a-time",
|
SteeringMode: "one-at-a-time",
|
||||||
ToolFeedback: ToolFeedbackConfig{
|
ToolFeedback: ToolFeedbackConfig{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
MaxArgsLength: 300,
|
MaxArgsLength: 300,
|
||||||
SeparateMessages: false,
|
SeparateMessages: false,
|
||||||
PrettyPrint: true,
|
|
||||||
DisableEscapeHTML: true,
|
|
||||||
},
|
},
|
||||||
SplitOnMarker: false,
|
SplitOnMarker: false,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ToolFeedbackContinuationHint = "Continuing the current task."
|
|
||||||
|
|
||||||
func FormatArgsJSON(args map[string]any, prettyPrint, disableEscapeHTML bool) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
enc := json.NewEncoder(&buf)
|
|
||||||
if prettyPrint {
|
|
||||||
enc.SetIndent("", " ")
|
|
||||||
}
|
|
||||||
if disableEscapeHTML {
|
|
||||||
enc.SetEscapeHTML(false)
|
|
||||||
}
|
|
||||||
if err := enc.Encode(args); err != nil {
|
|
||||||
return "{}"
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(buf.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatToolFeedbackMessage(toolName, explanation, argsPreview string) string {
|
|
||||||
toolName = strings.TrimSpace(toolName)
|
|
||||||
explanation = strings.TrimSpace(explanation)
|
|
||||||
argsPreview = strings.TrimSpace(argsPreview)
|
|
||||||
|
|
||||||
bodyLines := make([]string, 0, 2)
|
|
||||||
if explanation != "" {
|
|
||||||
bodyLines = append(bodyLines, explanation)
|
|
||||||
}
|
|
||||||
if argsPreview != "" {
|
|
||||||
bodyLines = append(bodyLines, "```json\n"+argsPreview+"\n```")
|
|
||||||
}
|
|
||||||
body := strings.Join(bodyLines, "\n")
|
|
||||||
|
|
||||||
if toolName == "" {
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
if body == "" {
|
|
||||||
return fmt.Sprintf("\U0001f527 `%s`", toolName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("\U0001f527 `%s`\n%s", toolName, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FitToolFeedbackMessage(content string, maxLen int) string {
|
|
||||||
content = strings.TrimSpace(content)
|
|
||||||
if content == "" || maxLen <= 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if len([]rune(content)) <= maxLen {
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|
||||||
firstLine, rest, hasRest := strings.Cut(content, "\n")
|
|
||||||
firstLine = strings.TrimSpace(firstLine)
|
|
||||||
rest = strings.TrimSpace(rest)
|
|
||||||
|
|
||||||
if !hasRest || rest == "" {
|
|
||||||
return Truncate(firstLine, maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len([]rune(firstLine)) >= maxLen {
|
|
||||||
return Truncate(firstLine, maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
remaining := maxLen - len([]rune(firstLine)) - 1
|
|
||||||
if remaining <= 0 {
|
|
||||||
return Truncate(firstLine, maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
return firstLine + "\n" + Truncate(rest, remaining)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Truncate(s string, maxLen int) string {
|
|
||||||
runes := []rune(s)
|
|
||||||
if len(runes) <= maxLen {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return string(runes[:maxLen])
|
|
||||||
}
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_Defaults(t *testing.T) {
|
|
||||||
args := map[string]any{"path": "README.md", "line": 42}
|
|
||||||
got := FormatArgsJSON(args, false, false)
|
|
||||||
var gotVal, wantVal any
|
|
||||||
if err := json.Unmarshal([]byte(got), &gotVal); err != nil {
|
|
||||||
t.Fatalf("FormatArgsJSON() returned invalid JSON: %v", err)
|
|
||||||
}
|
|
||||||
want := `{"path":"README.md","line":42}`
|
|
||||||
if err := json.Unmarshal([]byte(want), &wantVal); err != nil {
|
|
||||||
t.Fatalf("invalid test want JSON: %v", err)
|
|
||||||
}
|
|
||||||
if !jsonValEq(gotVal, wantVal) {
|
|
||||||
t.Fatalf("FormatArgsJSON() = %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_PrettyPrint(t *testing.T) {
|
|
||||||
args := map[string]any{"path": "README.md", "line": 42}
|
|
||||||
got := FormatArgsJSON(args, true, false)
|
|
||||||
var gotVal any
|
|
||||||
if err := json.Unmarshal([]byte(got), &gotVal); err != nil {
|
|
||||||
t.Fatalf("FormatArgsJSON() returned invalid JSON: %v", err)
|
|
||||||
}
|
|
||||||
want := `{"path":"README.md","line":42}`
|
|
||||||
var wantVal any
|
|
||||||
if err := json.Unmarshal([]byte(want), &wantVal); err != nil {
|
|
||||||
t.Fatalf("invalid test want JSON: %v", err)
|
|
||||||
}
|
|
||||||
if !jsonValEq(gotVal, wantVal) {
|
|
||||||
t.Fatalf("FormatArgsJSON() prettyPrint = %q, want structure %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_DisableEscapeHTML(t *testing.T) {
|
|
||||||
args := map[string]any{"msg": "a < b && c > d"}
|
|
||||||
got := FormatArgsJSON(args, false, true)
|
|
||||||
var gotVal, wantVal any
|
|
||||||
want := `{"msg":"a < b && c > d"}`
|
|
||||||
if err := json.Unmarshal([]byte(got), &gotVal); err != nil {
|
|
||||||
t.Fatalf("FormatArgsJSON() returned invalid JSON: %v", err)
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(want), &wantVal); err != nil {
|
|
||||||
t.Fatalf("invalid test want JSON: %v", err)
|
|
||||||
}
|
|
||||||
if !jsonValEq(gotVal, wantVal) {
|
|
||||||
t.Fatalf("FormatArgsJSON() disableEscapeHTML = %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_PrettyPrintAndDisableEscapeHTML(t *testing.T) {
|
|
||||||
args := map[string]any{"msg": "a < b && c > d"}
|
|
||||||
got := FormatArgsJSON(args, true, true)
|
|
||||||
var gotVal, wantVal any
|
|
||||||
want := `{"msg":"a < b && c > d"}`
|
|
||||||
if err := json.Unmarshal([]byte(got), &gotVal); err != nil {
|
|
||||||
t.Fatalf("FormatArgsJSON() returned invalid JSON: %v", err)
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(want), &wantVal); err != nil {
|
|
||||||
t.Fatalf("invalid test want JSON: %v", err)
|
|
||||||
}
|
|
||||||
if !jsonValEq(gotVal, wantVal) {
|
|
||||||
t.Fatalf("FormatArgsJSON() combined = %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_EscapeHTMLByDefault(t *testing.T) {
|
|
||||||
args := map[string]any{"msg": "a < b && c > d"}
|
|
||||||
got := FormatArgsJSON(args, false, false)
|
|
||||||
var gotVal, wantVal any
|
|
||||||
want := `{"msg":"a \u003c b \u0026\u0026 c \u003e d"}`
|
|
||||||
if err := json.Unmarshal([]byte(got), &gotVal); err != nil {
|
|
||||||
t.Fatalf("FormatArgsJSON() returned invalid JSON: %v", err)
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(want), &wantVal); err != nil {
|
|
||||||
t.Fatalf("invalid test want JSON: %v", err)
|
|
||||||
}
|
|
||||||
if !jsonValEq(gotVal, wantVal) {
|
|
||||||
t.Fatalf("FormatArgsJSON() default escape = %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatArgsJSON_NilArgs(t *testing.T) {
|
|
||||||
got := FormatArgsJSON(nil, false, false)
|
|
||||||
want := `null`
|
|
||||||
if got != want {
|
|
||||||
t.Fatalf("FormatArgsJSON() nil = %q, want %q", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonValEq(a, b any) bool {
|
|
||||||
aJSON, _ := json.Marshal(a)
|
|
||||||
bJSON, _ := json.Marshal(b)
|
|
||||||
return string(aJSON) == string(bJSON)
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue