mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
Keep launcher locale changes from mutating shared web-search routing (#2573)
The launcher wired UI language changes into a process-global backend switch that changed auto web-search provider selection and the reported current service for every handler in the same process. This narrows the fix to the validated leak: remove backend sync from frontend locale changes, drop the now-unused UI endpoint, and make auto selection fall back to a stable default when the query itself does not contain a script hint. Constraint: Keep the patch small and mergeable without redesigning per-user preference storage Rejected: Add per-user backend language state | larger scope than the validated bug and unclear maintainer preference Rejected: Persist preferred language in config | still shares mutable state across clients of the same instance Confidence: high Scope-risk: narrow Reversibility: clean Directive: If locale-aware provider routing is reintroduced later, scope it to explicit config or request context instead of package-global state Tested: go test ./web/backend/api ./pkg/tools -count=1; pnpm lint; pnpm build Not-tested: Full make check; live multi-browser manual launcher run after the backend endpoint removal
This commit is contained in:
@@ -89,7 +89,6 @@ func (h *Handler) RegisterRoutes(mux *http.ServeMux) {
|
||||
// Skills and tools support/actions
|
||||
h.registerSkillRoutes(mux)
|
||||
h.registerToolRoutes(mux)
|
||||
h.registerUIRoutes(mux)
|
||||
|
||||
// OS startup / launch-at-login
|
||||
h.registerStartupRoutes(mux)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
picotools "github.com/sipeed/picoclaw/pkg/tools"
|
||||
)
|
||||
|
||||
func TestHandleListTools(t *testing.T) {
|
||||
@@ -517,22 +516,12 @@ func TestResolveCurrentWebSearchProvider_FallsBackWhenProviderIsUnknown(t *testi
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCurrentWebSearchProvider_UsesPreferredLanguageForSogouAndDuckDuckGo(t *testing.T) {
|
||||
func TestResolveCurrentWebSearchProvider_PrefersStableDefaultForSogouAndDuckDuckGo(t *testing.T) {
|
||||
cfg := config.DefaultConfig()
|
||||
cfg.Tools.Web.Provider = "auto"
|
||||
cfg.Tools.Web.Sogou.Enabled = true
|
||||
cfg.Tools.Web.DuckDuckGo.Enabled = true
|
||||
|
||||
picotools.SetPreferredWebSearchLanguage("en")
|
||||
t.Cleanup(func() {
|
||||
picotools.SetPreferredWebSearchLanguage("")
|
||||
})
|
||||
|
||||
if got := resolveCurrentWebSearchProvider(cfg); got != "duckduckgo" {
|
||||
t.Fatalf("resolveCurrentWebSearchProvider() = %q, want duckduckgo", got)
|
||||
}
|
||||
|
||||
picotools.SetPreferredWebSearchLanguage("zh")
|
||||
if got := resolveCurrentWebSearchProvider(cfg); got != "sogou" {
|
||||
t.Fatalf("resolveCurrentWebSearchProvider() = %q, want sogou", got)
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/tools"
|
||||
)
|
||||
|
||||
type uiLanguageRequest struct {
|
||||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
func (h *Handler) registerUIRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("POST /api/ui/language", h.handleSetUILanguage)
|
||||
}
|
||||
|
||||
func (h *Handler) handleSetUILanguage(w http.ResponseWriter, r *http.Request) {
|
||||
var req uiLanguageRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
tools.SetPreferredWebSearchLanguage(req.Language)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/tools"
|
||||
)
|
||||
|
||||
func TestHandleSetUILanguage(t *testing.T) {
|
||||
tools.SetPreferredWebSearchLanguage("")
|
||||
t.Cleanup(func() {
|
||||
tools.SetPreferredWebSearchLanguage("")
|
||||
})
|
||||
|
||||
h := NewHandler("")
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/ui/language", strings.NewReader(`{"language":"zh"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
mux.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNoContent {
|
||||
t.Fatalf("status = %d, want %d, body=%s", rec.Code, http.StatusNoContent, rec.Body.String())
|
||||
}
|
||||
if got := tools.GetPreferredWebSearchLanguage(); got != "zh" {
|
||||
t.Fatalf("preferred web search language = %q, want zh", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleSetUILanguage_RejectsInvalidJSON(t *testing.T) {
|
||||
h := NewHandler("")
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/ui/language", strings.NewReader(`{`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
mux.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/logger"
|
||||
"github.com/sipeed/picoclaw/pkg/netbind"
|
||||
"github.com/sipeed/picoclaw/pkg/tools"
|
||||
"github.com/sipeed/picoclaw/web/backend/api"
|
||||
"github.com/sipeed/picoclaw/web/backend/dashboardauth"
|
||||
"github.com/sipeed/picoclaw/web/backend/launcherconfig"
|
||||
@@ -409,7 +408,6 @@ func main() {
|
||||
if *lang != "" {
|
||||
SetLanguage(*lang)
|
||||
}
|
||||
tools.SetPreferredWebSearchLanguage(string(GetLanguage()))
|
||||
|
||||
// Resolve config path
|
||||
configPath := utils.GetDefaultConfigPath()
|
||||
|
||||
Reference in New Issue
Block a user