p2.1: honcho-embed, wayback http/204, memento, keys owner
Embed requests send dixie.embed_model (default honcho-embed). Wayback accepts http://web.archive.org, rewrites to https, skips non-200 closest.status. Memento-Datetime is parsed as an HTTP date and future/garbage values become empty snapshot_at. keys add writes via temp+fchown/chmod/rename so root does not clobber keys.toml. Digest fallback is capped at the 6k-token budget.
This commit is contained in:
+21
-10
@@ -154,15 +154,16 @@ func (g *Gate) Release() {
|
||||
}
|
||||
|
||||
type Engine struct {
|
||||
ChatURL string
|
||||
EmbedURL string
|
||||
Model string
|
||||
Thinking bool
|
||||
Client *http.Client
|
||||
Gate *Gate
|
||||
Timeout time.Duration
|
||||
Log *slog.Logger
|
||||
Cache *dcache.DB
|
||||
ChatURL string
|
||||
EmbedURL string
|
||||
EmbedModel string
|
||||
Model string
|
||||
Thinking bool
|
||||
Client *http.Client
|
||||
Gate *Gate
|
||||
Timeout time.Duration
|
||||
Log *slog.Logger
|
||||
Cache *dcache.DB
|
||||
|
||||
mu sync.Mutex
|
||||
Calls uint64
|
||||
@@ -201,6 +202,13 @@ func (e *Engine) model() string {
|
||||
return "ornith-1.5-9b-uncensored"
|
||||
}
|
||||
|
||||
func (e *Engine) embedModel() string {
|
||||
if e != nil && e.EmbedModel != "" {
|
||||
return e.EmbedModel
|
||||
}
|
||||
return "honcho-embed"
|
||||
}
|
||||
|
||||
func (e *Engine) noteFallback(reason string) {
|
||||
if e == nil {
|
||||
return
|
||||
@@ -379,7 +387,7 @@ func (e *Engine) embed(ctx context.Context, inputs []string) ([][]float64, error
|
||||
}
|
||||
|
||||
func (e *Engine) embedBatch(ctx context.Context, inputs []string) ([][]float64, error) {
|
||||
payload, _ := json.Marshal(map[string]any{"input": inputs, "model": "qwen3-embedding-0.6b"})
|
||||
payload, _ := json.Marshal(map[string]any{"input": inputs, "model": e.embedModel()})
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e.EmbedURL, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -541,6 +549,9 @@ func countBudget(chunks []string, budget int) int {
|
||||
return n
|
||||
}
|
||||
|
||||
// CapBudget trims s to the digest input budget (SmallDoc estimated tokens).
|
||||
func CapBudget(s string) string { return trimTokens(s, SmallDoc) }
|
||||
|
||||
func trimTokens(s string, max int) string {
|
||||
r := []rune(s)
|
||||
n := max * 4
|
||||
|
||||
@@ -250,3 +250,42 @@ func TestChunkOrderAndBudget(t *testing.T) {
|
||||
t.Fatal("document order")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbedUsesConfiguredModel(t *testing.T) {
|
||||
var got string
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var body struct {
|
||||
Model string `json:"model"`
|
||||
}
|
||||
_ = json.NewDecoder(r.Body).Decode(&body)
|
||||
got = body.Model
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"data": []map[string]any{
|
||||
{"index": 0, "embedding": []float64{1, 0}},
|
||||
{"index": 1, "embedding": []float64{0, 1}},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer ts.Close()
|
||||
e := &Engine{EmbedURL: ts.URL, EmbedModel: "honcho-embed", Client: ts.Client()}
|
||||
if _, err := e.embedBatch(context.Background(), []string{"q", "chunk"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "honcho-embed" {
|
||||
t.Fatalf("model %q", got)
|
||||
}
|
||||
e.EmbedModel = "other-embed"
|
||||
if _, err := e.embedBatch(context.Background(), []string{"q", "chunk"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "other-embed" {
|
||||
t.Fatalf("model %q", got)
|
||||
}
|
||||
e.EmbedModel = ""
|
||||
if _, err := e.embedBatch(context.Background(), []string{"q", "chunk"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "honcho-embed" {
|
||||
t.Fatalf("default model %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user