fix: validate Cua window discovery filters and guide recovery

This commit is contained in:
chenmingxuan committed 2026-10-17 13:23:56 +08:00
1 parent c89588a80d
commit 1c1d700e9b
12 files changed
+337 -31

No files matched your search

+92
View File
@@ -0,0 +1,92 @@
package main
import (
"errors"
"fmt"
"math"
"strings"
)
// Optional filters must remain optional across JSON-schema clients. In
// particular, null means unspecified; zero is not a wildcard process ID.
func windowQuery(args obj) (obj, error) {
query := obj{}
for key, value := range args {
if value != nil {
query[key] = value
}
}
if value, ok := query["app"]; ok {
app, valid := value.(string)
if !valid {
return nil, errors.New("app must be an application name or null")
}
if app = strings.TrimSpace(app); app == "" {
delete(query, "app")
} else {
query["app"] = app
}
}
if value, ok := query["pid"]; ok {
valid := num(value) > 0 && num(value) <= math.MaxUint32
switch n := value.(type) {
case float64:
valid = valid && n == math.Trunc(n)
case int, int64:
default:
valid = false
}
if !valid {
return nil, errors.New("pid must be a positive Windows process ID from a matching list_windows result. If unknown, omit pid or use null and search by app, e.g. {\"app\":\"Brave\",\"on_screen_only\":true}. Never use 0 or a different app's foreground PID")
}
}
return query, nil
}
// Upstream's empty-result hint names the unrelated foreground process. Do not
// present that PID as a recovery candidate. Keep the exact filters and provide
// a separate suggested query; never silently widen the caller's PID scope.
func windowListing(result obj, query obj) obj {
if result["isError"] == true {
return result
}
data := object(result["structuredContent"])
windows, ok := data["windows"].([]any)
if !ok {
return failure("Driver returned no window list; this is an observation error, not evidence that the application is absent", "not_started", "none", "invalid_window_list")
}
lookup := obj{"status": "matched", "filters": query, "count": len(windows)}
lines := []string{fmt.Sprintf("Found %d matching window(s).", len(windows))}
for _, value := range windows {
window := object(value)
lines = append(lines, fmt.Sprintf("- %s (pid %d), window_id %d, title %q", str(window["app_name"]), num(window["pid"]), num(window["window_id"]), str(window["title"])))
}
if len(windows) == 0 {
lookup["status"] = "no_match"
lines = append(lines, "No windows match these filters. This alone does not prove the application is unavailable or screenshot capture is broken. Do not substitute another application's foreground PID.")
if str(query["app"]) != "" && query["pid"] != nil {
next := obj{}
for key, value := range query {
if key != "pid" {
next[key] = value
}
}
lookup["suggested_arguments"] = next
lines = append(lines, "app and pid are combined filters. Retry list_windows for the same app with pid omitted; use only a PID returned for that app.")
} else if query["on_screen_only"] == true {
next := obj{}
for key, value := range query {
next[key] = value
}
next["on_screen_only"] = false
lookup["suggested_arguments"] = next
lines = append(lines, "Retry the same filters with on_screen_only=false to check for minimized/off-screen windows. A listed window still needs a fresh get_window_state before interaction.")
} else {
lines = append(lines, "Verify the requested application name or PID. When the PID is unknown, search by the known app name with pid omitted. Do not guess a PID or operate an unrelated window.")
}
}
data["lookup"] = lookup
result["structuredContent"] = data
result["content"] = []any{textBlock(strings.Join(lines, "\n"))}
return result
}