feat(metadata): enhance metadata extraction with heuristic fallback support

This commit is contained in:
2026-03-27 00:31:30 +02:00
parent f76d1bbd23
commit 8775c3e4ce
2 changed files with 357 additions and 44 deletions

View File

@@ -7,6 +7,7 @@ import (
"log/slog"
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
)
@@ -250,3 +251,93 @@ func TestExtractMetadataUsesReasoningContentWhenContentEmpty(t *testing.T) {
t.Fatalf("metadata people = %#v, want [Hein]", metadata.People)
}
}
func TestExtractMetadataFallsBackToHeuristicsWhenModelsFail(t *testing.T) {
var calls atomic.Int32
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = calls.Add(1)
_ = json.NewEncoder(w).Encode(map[string]any{
"choices": []map[string]any{
{"message": map[string]any{"content": "not json"}},
},
})
}))
defer server.Close()
client := New(Config{
Name: "test",
BaseURL: server.URL,
APIKey: "secret",
MetadataModel: "primary",
FallbackMetadataModel: "secondary",
HTTPClient: server.Client(),
Log: discardLogger(),
})
input := "Personal profile - Hein (Warkanum):\n- Born: 23 May 1989\n- Wife: Cindy, born 16 November 1994"
metadata, err := client.ExtractMetadata(context.Background(), input)
if err != nil {
t.Fatalf("ExtractMetadata() error = %v", err)
}
if calls.Load() != 2 {
t.Fatalf("call count = %d, want 2", calls.Load())
}
if metadata.Type != "person_note" {
t.Fatalf("metadata type = %q, want person_note", metadata.Type)
}
if len(metadata.DatesMentioned) < 2 {
t.Fatalf("metadata dates = %#v, want extracted dates", metadata.DatesMentioned)
}
if len(metadata.People) == 0 || !strings.EqualFold(metadata.People[0], "Cindy") {
t.Fatalf("metadata people = %#v, want Cindy", metadata.People)
}
}
func TestExtractMetadataRetriesEmptyResponse(t *testing.T) {
var calls atomic.Int32
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
call := calls.Add(1)
var req chatCompletionsRequest
_ = json.NewDecoder(r.Body).Decode(&req)
if req.Stream == nil || *req.Stream {
t.Fatalf("expected stream=false, got %#v", req.Stream)
}
if call == 1 {
_ = json.NewEncoder(w).Encode(map[string]any{
"choices": []map[string]any{
{"message": map[string]any{"content": ""}},
},
})
return
}
_ = json.NewEncoder(w).Encode(map[string]any{
"choices": []map[string]any{
{"message": map[string]any{"content": "{\"people\":[],\"action_items\":[],\"dates_mentioned\":[],\"topics\":[\"mcp\"],\"type\":\"observation\",\"source\":\"mcp\"}"}},
},
})
}))
defer server.Close()
client := New(Config{
Name: "test",
BaseURL: server.URL,
APIKey: "secret",
MetadataModel: "meta-model",
HTTPClient: server.Client(),
Log: discardLogger(),
})
metadata, err := client.ExtractMetadata(context.Background(), "hello")
if err != nil {
t.Fatalf("ExtractMetadata() error = %v", err)
}
if calls.Load() < 2 {
t.Fatalf("call count = %d, want >= 2", calls.Load())
}
if metadata.Type != "observation" {
t.Fatalf("metadata type = %q, want observation", metadata.Type)
}
}