66 "fmt"
77 "log/slog"
88 "os"
9+ "slices"
910 "strings"
1011 "sync"
1112
@@ -63,6 +64,18 @@ func extractTargets(tc types.ToolCall) []string {
6364// discover non-conventional argument names.
6465var filePathLikeKeySubstrings = []string {"path" , "file" , "dir" , "destination" , "target" }
6566
67+ func filePathPropertyPriority (name string ) int {
68+ lower := strings .ToLower (name )
69+ switch {
70+ case strings .Contains (lower , "src" ), strings .Contains (lower , "source" ), strings .Contains (lower , "input" ):
71+ return 0
72+ case strings .Contains (lower , "dst" ), strings .Contains (lower , "dest" ), strings .Contains (lower , "output" ), strings .Contains (lower , "target" ), strings .Contains (lower , "backup" ):
73+ return 2
74+ default :
75+ return 1
76+ }
77+ }
78+
6679// ExtractTargetsFromSchema walks the tool's JSON Schema to discover file-path
6780// arguments in the tool call. It does this by:
6881// 1. Reading `parameters` (the JSON Schema map) to enumerate property names.
@@ -82,7 +95,19 @@ func ExtractTargetsFromSchema(t tool.Tool, tc types.ToolCall) []string {
8295 // a JSON Schema (e.g. an LLM-emitted tool or a tests-only stub).
8396 return extractTargets (tc )
8497 }
85- for propName , propDef := range props {
98+ propNames := make ([]string , 0 , len (props ))
99+ for propName := range props {
100+ propNames = append (propNames , propName )
101+ }
102+ slices .SortStableFunc (propNames , func (a , b string ) int {
103+ pa , pb := filePathPropertyPriority (a ), filePathPropertyPriority (b )
104+ if pa != pb {
105+ return pa - pb
106+ }
107+ return strings .Compare (a , b )
108+ })
109+ for _ , propName := range propNames {
110+ propDef := props [propName ]
86111 propNameLower := strings .ToLower (propName )
87112 // Convention 1: property name contains a file-path substring.
88113 nameMatches := false
0 commit comments