ollama/create/clef_test.go
Daniel Hiltgen a00d083bb5
mlx: System one support (#18701)
* mlxrunner: restore System One scoring

Carry the MLX implementation and its tests from the original System One
commit. The API/compiler and llama-server implementation already exist on
the release branch, so retain those versions. Adapt the optional model test
to the renamed decision package and its explicit rendering/context setup.

(cherry picked from commit 26e546ddb3)

* Enable MLX System One and add regression coverage

* mlxrunner: add Laya support for System One

Import Laya checkpoints and implement bidirectional decision scoring.

* mlxrunner: release cached buffers after System One scoring

* decision: match Tev1 and Nimble publisher prompt formats

Select Tev1 prompts using renderer metadata and fix JSON formatting, with regression coverage for GGUF and MLX.

* mlx: support Clef and Clef Flash decision models

Add model import, quantization safeguards, and text/image scoring with the Clef joint decision head.

* support vision capabilities for decision models

* Make Clef scoring cancellable between prefill chunks

Preserve joint-head inputs and test cancellation, cleanup, and recovery.

* mlx: separate decision preparation and readout from forward

Let serial and batched scoring share model-owned preparation and readout
without duplicating architecture-specific logic in the runner.

* mlx: add Strands Decider support

* implement caching

---------

Co-authored-by: ParthSareen <parth.sareen@ollama.com>
2026-10-03 13:17:21 -07:00

257 lines
8.4 KiB
Go

package create
import (
"bytes"
"context"
"encoding/json"
"os"
"path/filepath"
"reflect"
"slices"
"strings"
"testing"
st "github.com/ollama/ollama/fs/safetensors"
)
func writeClefSource(t *testing.T, dir string) {
t.Helper()
writeConfigJSON(t, dir, `{"architectures":["Qwen3_5ForConditionalGeneration"],"model_type":"qwen3_5","text_config":{"hidden_size":4},"publisher_extension":{"large_integer":123456789012345678901234567890,"scale":1e6}}`)
for name, data := range map[string]string{
"joint_head_config.json": `{"hidden_size":4,"width":2,"heads":1,"layers":1,"routing_layers":1,"feedforward":4}`,
"model.safetensors.index.json": `{"weight_map":{"model.weight":"model.safetensors"}}`,
} {
if err := os.WriteFile(filepath.Join(dir, name), []byte(data), 0o600); err != nil {
t.Fatal(err)
}
}
createTestSafetensors(t, filepath.Join(dir, "model.safetensors"), []*st.TensorData{
st.NewTensorDataFromBytes("model.weight", "BF16", []int32{2, 4}, make([]byte, 16)),
})
createTestSafetensors(t, filepath.Join(dir, "joint_head.safetensors"), []*st.TensorData{
st.NewTensorDataFromBytes("memory_projection.weight", "BF16", []int32{2, 4}, make([]byte, 16)),
st.NewTensorDataFromBytes("type_embedding.weight", "BF16", []int32{3, 2}, make([]byte, 12)),
})
}
func TestClefInventory(t *testing.T) {
for _, tc := range []struct{ name, remove, config, index, wantError string }{
{name: "complete"},
{name: "monolithic backbone", remove: "model.safetensors.index.json"},
{name: "head already indexed", index: `{"weight_map":{"model.weight":"model.safetensors","memory_projection.weight":"joint_head.safetensors","type_embedding.weight":"joint_head.safetensors"}}`},
{name: "missing config", remove: "joint_head_config.json", wantError: "read Clef joint head config"},
{name: "missing head", remove: "joint_head.safetensors", wantError: "read Clef joint head"},
{name: "different backbone", config: `{"architectures":["Qwen3ForCausalLM"]}`, wantError: "unsupported Clef backbone"},
{name: "different hidden size", config: `{"architectures":["Qwen3_5ForConditionalGeneration"],"text_config":{"hidden_size":8}}`, wantError: "invalid Clef joint head configuration"},
} {
t.Run(tc.name, func(t *testing.T) {
dir := t.TempDir()
writeClefSource(t, dir)
if tc.remove != "" {
if err := os.Remove(filepath.Join(dir, tc.remove)); err != nil {
t.Fatal(err)
}
}
if tc.config != "" {
writeConfigJSON(t, dir, tc.config)
}
if tc.index != "" {
if err := os.WriteFile(filepath.Join(dir, "model.safetensors.index.json"), []byte(tc.index), 0o600); err != nil {
t.Fatal(err)
}
}
inv, err := ReadInventory(dir)
if err == nil {
inv, err = prepareClefInventory(inv)
}
if tc.wantError != "" {
if err == nil || !strings.Contains(err.Error(), tc.wantError) {
t.Fatalf("prepareClefInventory() error=%v, want %q", err, tc.wantError)
}
return
}
if err != nil {
t.Fatal(err)
}
if inv.Config.Architecture() != "ClefForDecision" || len(inv.Tensors) != 3 || inv.Tensors["memory_projection.weight"].File != "joint_head.safetensors" {
t.Fatalf("incorrect composite inventory: %+v", inv)
}
files, err := SafetensorsWeightFiles(dir)
if err != nil {
t.Fatal(err)
}
if !slices.Equal(files, []string{"joint_head.safetensors", "model.safetensors"}) {
t.Fatalf("source files=%v", files)
}
})
}
}
func TestClefImportPreservesSourceConfig(t *testing.T) {
dir := t.TempDir()
writeClefSource(t, dir)
original, err := os.ReadFile(filepath.Join(dir, "config.json"))
if err != nil {
t.Fatal(err)
}
ordinary, err := ReadInventory(dir)
if err != nil {
t.Fatal(err)
}
if ordinary.Config.Architecture() != "Qwen3_5ForConditionalGeneration" || ordinary.Has("memory_projection.weight") {
t.Fatalf("filenames selected Clef without explicit intent: %+v", ordinary)
}
store := newCaptureStore()
var result ManifestInfo
err = Create(t.Context(), "clef-test", dir, PipelineOptions{
Renderer: "clef",
Validation: MLXValidationOptions{Force: true, Warning: func(string) {}},
}, store, func(_ context.Context, _ string, info ManifestInfo) error {
result = info
return nil
}, func(string) {})
if err != nil {
t.Fatal(err)
}
unchanged, err := os.ReadFile(filepath.Join(dir, "config.json"))
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(unchanged, original) {
t.Fatal("publisher source config changed during import")
}
var source, output map[string]json.RawMessage
if err := json.Unmarshal(original, &source); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(store.blobs["config.json"], &output); err != nil {
t.Fatal(err)
}
source["architectures"] = json.RawMessage(`["ClefForDecision"]`)
if !reflect.DeepEqual(output, source) {
t.Fatalf("output config changed fields other than architectures: %s", store.blobs["config.json"])
}
var configLayers int
for _, layer := range result.Layers {
if layer.Name == "config.json" {
configLayers++
}
}
if configLayers != 1 {
t.Fatalf("got %d config.json layers, want 1", configLayers)
}
if result.ModelConfig.Renderer != "clef" || result.ModelConfig.Parser != "" || !slices.Equal(result.ModelConfig.Capabilities, []string{"decision"}) {
t.Fatalf("incorrect manifest config: %+v", result.ModelConfig)
}
if _, ok := store.blobs["memory_projection.weight"]; !ok {
t.Fatal("head tensor was omitted")
}
}
func TestClefMetadata(t *testing.T) {
for _, tc := range []struct {
name string
vision bool
capabilities []string
}{
{"text", false, []string{"decision"}},
{"vision", true, []string{"decision", "vision"}},
} {
t.Run(tc.name, func(t *testing.T) {
dir := t.TempDir()
writeClefSource(t, dir)
inv, err := ReadInventory(dir)
if err == nil {
inv, err = prepareClefInventory(inv)
}
if err != nil {
t.Fatal(err)
}
if tc.vision {
v := map[string]any{}
inv.Config.VisionConfig = &v
}
cfg, err := inferSafetensorsConfig(dir, inv.Config, "", "clef")
if err != nil {
t.Fatal(err)
}
if !slices.Equal(cfg.Capabilities, tc.capabilities) || cfg.Parser != "" || cfg.Renderer != "clef" {
t.Fatalf("incorrect Clef metadata: %+v", cfg)
}
})
}
}
func TestClefImportRejectsIncompleteSource(t *testing.T) {
for _, missing := range []string{"joint_head_config.json", "joint_head.safetensors"} {
t.Run(missing, func(t *testing.T) {
dir := t.TempDir()
writeClefSource(t, dir)
if err := os.Remove(filepath.Join(dir, missing)); err != nil {
t.Fatal(err)
}
store := newCaptureStore()
err := Create(t.Context(), "clef-test", dir, PipelineOptions{Renderer: "clef"}, store, func(context.Context, string, ManifestInfo) error {
t.Fatal("incomplete source reached manifest writer")
return nil
}, func(string) {})
if err == nil || len(store.blobs) != 0 {
t.Fatalf("incomplete source: error=%v, wrote %d blobs", err, len(store.blobs))
}
})
}
}
func TestClefWeightFiles(t *testing.T) {
for _, tc := range []struct {
name, head string
indexed bool
wantError bool
}{
{name: "absent"},
{name: "unindexed", head: "file"},
{name: "already indexed", head: "file", indexed: true},
{name: "directory", head: "directory", wantError: true},
} {
t.Run(tc.name, func(t *testing.T) {
dir := t.TempDir()
index := `{"weight_map":{"model.weight":"model.safetensors"}}`
if tc.indexed {
index = `{"weight_map":{"model.weight":"model.safetensors","head.weight":"joint_head.safetensors"}}`
}
if err := os.WriteFile(filepath.Join(dir, "model.safetensors.index.json"), []byte(index), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "consolidated.safetensors"), nil, 0o600); err != nil {
t.Fatal(err)
}
head := filepath.Join(dir, "joint_head.safetensors")
if tc.head == "file" {
if err := os.WriteFile(head, nil, 0o600); err != nil {
t.Fatal(err)
}
} else if tc.head == "directory" {
if err := os.Mkdir(head, 0o700); err != nil {
t.Fatal(err)
}
}
files, err := SafetensorsWeightFiles(dir)
if tc.wantError {
if err == nil || !strings.Contains(err.Error(), "regular file") {
t.Fatalf("got %v, want regular-file error", err)
}
return
}
if err != nil {
t.Fatal(err)
}
want := []string{"model.safetensors"}
if tc.head == "file" {
want = []string{"joint_head.safetensors", "model.safetensors"}
}
if !slices.Equal(files, want) {
t.Fatalf("files=%v, want %v", files, want)
}
})
}
}