mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-18 06:14:17 +00:00
fix(memory): guard provider embedding dimensions to 1536 schema (#563)
- Reject incompatible explicit provider embedding dimensions on create/update - Ignore previously saved incompatible dimensions at runtime, fall back to 1536 - Share RequiredMemoryEmbeddingDimensions constant from store package - Remove dimensions input from provider UI (always 1536 per pgvector schema) - Add HTTP, runtime, and validation unit tests Closes #548 Supersedes #410
This commit is contained in:
1 parent
53932cf532
commit
65d0d62acf
14 files changed
+312
-47
No files matched your search
@@ -123,11 +123,12 @@ func buildEmbeddingProvider(
|
||||
apiBase = memCfg.EmbeddingAPIBase
|
||||
}
|
||||
|
||||
// Dimension truncation: provider settings override, default to 1536 to match pgvector schema.
|
||||
// Dimension truncation: default to RequiredMemoryEmbeddingDimensions to match pgvector schema.
|
||||
// Models that natively output 1536 ignore the parameter; models with larger native dims get truncated.
|
||||
dims := 1536
|
||||
if es != nil && es.Dimensions > 0 {
|
||||
dims = es.Dimensions
|
||||
dims := store.RequiredMemoryEmbeddingDimensions
|
||||
if es != nil && es.Dimensions > 0 && es.Dimensions != store.RequiredMemoryEmbeddingDimensions {
|
||||
slog.Warn("ignoring incompatible provider embedding dimensions for memory schema",
|
||||
"provider", dbp.Name, "requested", es.Dimensions, "required", store.RequiredMemoryEmbeddingDimensions)
|
||||
}
|
||||
|
||||
// Try registry first for the actual API key / base (handles runtime-registered providers)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/nextlevelbuilder/goclaw/internal/store"
|
||||
)
|
||||
|
||||
func captureEmbeddingRequest(t *testing.T, es *store.EmbeddingSettings) map[string]any {
|
||||
t.Helper()
|
||||
|
||||
var requestBody map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
|
||||
t.Fatalf("Decode() error = %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"data":[{"embedding":[0.1,0.2]}]}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
provider := &store.LLMProviderData{
|
||||
Name: "embedding-provider",
|
||||
ProviderType: store.ProviderOpenAICompat,
|
||||
APIKey: "test-key",
|
||||
APIBase: server.URL,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
ep := buildEmbeddingProvider(provider, es, nil, nil)
|
||||
if ep == nil {
|
||||
t.Fatal("buildEmbeddingProvider() = nil, want provider")
|
||||
}
|
||||
if _, err := ep.Embed(context.Background(), []string{"hello"}); err != nil {
|
||||
t.Fatalf("Embed() error = %v", err)
|
||||
}
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func TestBuildEmbeddingProviderDefaultsTo1536Dimensions(t *testing.T) {
|
||||
requestBody := captureEmbeddingRequest(t, nil)
|
||||
if got := requestBody["dimensions"]; got != float64(1536) {
|
||||
t.Fatalf("dimensions = %v, want 1536", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildEmbeddingProviderIgnoresIncompatibleStoredDimensions(t *testing.T) {
|
||||
requestBody := captureEmbeddingRequest(t, &store.EmbeddingSettings{
|
||||
Enabled: true,
|
||||
Model: "voyage-4-nano",
|
||||
Dimensions: 2048,
|
||||
})
|
||||
if got := requestBody["dimensions"]; got != float64(1536) {
|
||||
t.Fatalf("dimensions = %v, want fallback 1536", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user