|
| 1 | +package config |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + |
| 6 | + "github.com/mudler/LocalAI/pkg/grpc" |
| 7 | + pb "github.com/mudler/LocalAI/pkg/grpc/proto" |
| 8 | + |
| 9 | + . "github.com/onsi/ginkgo/v2" |
| 10 | + . "github.com/onsi/gomega" |
| 11 | + grpclib "google.golang.org/grpc" |
| 12 | +) |
| 13 | + |
| 14 | +// markerBackend answers ModelMetadata with a fixed marker and records whether it |
| 15 | +// was called at all. Embedding grpc.Backend keeps the rest of the (large) |
| 16 | +// interface unimplemented on purpose: DetectThinkingSupportFromBackend must only |
| 17 | +// reach for ModelMetadata, and any other call would panic loudly. |
| 18 | +type markerBackend struct { |
| 19 | + grpc.Backend |
| 20 | + marker string |
| 21 | + called bool |
| 22 | +} |
| 23 | + |
| 24 | +func (m *markerBackend) ModelMetadata(ctx context.Context, in *pb.ModelOptions, opts ...grpclib.CallOption) (*pb.ModelMetadataResponse, error) { |
| 25 | + m.called = true |
| 26 | + return &pb.ModelMetadataResponse{MediaMarker: m.marker}, nil |
| 27 | +} |
| 28 | + |
| 29 | +var _ = Describe("media marker probing across llama.cpp backend variants", func() { |
| 30 | + // llama.cpp picks a random per-process media marker (ggml-org/llama.cpp#21962), |
| 31 | + // so the marker MUST come from the backend. A config that pins a concrete |
| 32 | + // variant name still runs the same llama.cpp gRPC server and must be probed, |
| 33 | + // or the rendered prompt keeps LocalAI's "<__media__>" sentinel and |
| 34 | + // mtmd_tokenize reports zero markers against one bitmap (#10945). |
| 35 | + const backendMarker = "<__media_9fJqQpVb2hZK3nT7__>" |
| 36 | + |
| 37 | + probe := func(backend string) *ModelConfig { |
| 38 | + cfg := &ModelConfig{} |
| 39 | + cfg.Backend = backend |
| 40 | + client := &markerBackend{marker: backendMarker} |
| 41 | + DetectThinkingSupportFromBackend(context.Background(), cfg, client, &pb.ModelOptions{}) |
| 42 | + return cfg |
| 43 | + } |
| 44 | + |
| 45 | + DescribeTable("captures the backend-reported marker", |
| 46 | + func(backend string) { |
| 47 | + Expect(probe(backend).MediaMarker).To(Equal(backendMarker)) |
| 48 | + }, |
| 49 | + Entry("meta backend", "llama-cpp"), |
| 50 | + Entry("auto-detected (empty) backend", ""), |
| 51 | + Entry("development channel", "llama-cpp-development"), |
| 52 | + Entry("vulkan variant", "vulkan-llama-cpp"), |
| 53 | + Entry("vulkan development variant", "vulkan-llama-cpp-development"), |
| 54 | + Entry("cuda 12 variant", "cuda12-llama-cpp"), |
| 55 | + Entry("cuda 13 jetson variant", "cuda13-nvidia-l4t-arm64-llama-cpp"), |
| 56 | + Entry("rocm variant", "rocm-llama-cpp"), |
| 57 | + Entry("metal variant", "metal-llama-cpp"), |
| 58 | + Entry("intel sycl variant", "intel-sycl-f16-llama-cpp"), |
| 59 | + Entry("cpu variant", "cpu-llama-cpp"), |
| 60 | + Entry("quantization variant", "llama-cpp-quantization"), |
| 61 | + ) |
| 62 | + |
| 63 | + DescribeTable("leaves the marker untouched for backends that are not llama.cpp", |
| 64 | + func(backend string) { |
| 65 | + cfg := &ModelConfig{} |
| 66 | + cfg.Backend = backend |
| 67 | + client := &markerBackend{marker: backendMarker} |
| 68 | + DetectThinkingSupportFromBackend(context.Background(), cfg, client, &pb.ModelOptions{}) |
| 69 | + Expect(client.called).To(BeFalse(), "backend %q must not be probed", backend) |
| 70 | + Expect(cfg.MediaMarker).To(BeEmpty()) |
| 71 | + }, |
| 72 | + // ik-llama.cpp is a separate engine with its own gRPC server that still |
| 73 | + // uses mtmd_default_marker(), so the sentinel already matches and there |
| 74 | + // is nothing to probe. |
| 75 | + Entry("ik-llama-cpp", "ik-llama-cpp"), |
| 76 | + Entry("ik-llama-cpp development", "ik-llama-cpp-development"), |
| 77 | + Entry("cpu ik-llama-cpp", "cpu-ik-llama-cpp"), |
| 78 | + Entry("vllm", "vllm"), |
| 79 | + Entry("mlx", "mlx"), |
| 80 | + Entry("whisper", "whisper"), |
| 81 | + ) |
| 82 | +}) |
0 commit comments