mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-01 01:59:01 -05:00
Add the add-on runtime to LocalAI: manifests, the host operation broker, admin gating by account role, the add-on UI bundle builder and the SDK for add-on pages. Move the navigation to Chat, Models, Add-ons and Settings, with pinned add-ons in the sidebar and an Add-ons drawer. Ship the first-party add-ons (voice, face, fine-tuning, quantization) as packages for linux/amd64, linux/arm64 and darwin/arm64. Intel macOS (darwin/amd64) is enabled in the platform files. Squashed from the review branch. The tree is unchanged; the pre-squash history is kept on a local backup branch. Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
61 lines
2.1 KiB
Go
61 lines
2.1 KiB
Go
// SPDX-License-Identifier: MIT
|
|
package contract
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestHostWireTypesRoundTrip(t *testing.T) {
|
|
req := HostRequest{OperationID: "op1", Op: "finetune.get", Arguments: json.RawMessage(`{"jobId":"j1"}`)}
|
|
b, err := json.Marshal(req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := DecodeHostRequest(b, 1<<20)
|
|
if err != nil || got.OperationID != "op1" || got.Op != "finetune.get" || string(got.Arguments) != `{"jobId":"j1"}` {
|
|
t.Fatalf("%+v %v", got, err)
|
|
}
|
|
resp := HostResponse{Error: &HostError{Code: "scope", Message: "no"}}
|
|
b, _ = json.Marshal(resp)
|
|
var back HostResponse
|
|
if err := json.Unmarshal(b, &back); err != nil || back.Error == nil || back.Error.Code != "scope" || back.Error.Error() == "" {
|
|
t.Fatalf("%+v %v", back, err)
|
|
}
|
|
b, _ = json.Marshal(HostResponse{Result: json.RawMessage(`{"ok":true}`)})
|
|
if err := json.Unmarshal(b, &back); err != nil || string(back.Result) != `{"ok":true}` {
|
|
t.Fatalf("%s %v", b, err)
|
|
}
|
|
}
|
|
|
|
func TestTheStrictDecoderRefusesWhatItDoesNotKnow(t *testing.T) {
|
|
for name, body := range map[string]string{
|
|
"unknown field": `{"operationId":"a","op":"finetune.get","arguments":{},"userId":"x"}`,
|
|
"duplicate key": `{"operationId":"a","operationId":"b","op":"finetune.get"}`,
|
|
"trailing": `{"operationId":"a","op":"finetune.get"} {}`,
|
|
"not an object": `[]`,
|
|
"empty": ``,
|
|
} {
|
|
if _, err := DecodeHostRequest([]byte(body), 1<<20); err == nil {
|
|
t.Errorf("%s: accepted", name)
|
|
}
|
|
}
|
|
if _, err := DecodeHostRequest([]byte(`{"operationId":"a","op":"finetune.get"}`), 10); err == nil {
|
|
t.Error("an oversized body was accepted")
|
|
}
|
|
}
|
|
|
|
func TestAnOperationNameHasTheDottedShape(t *testing.T) {
|
|
for op, want := range map[string]bool{
|
|
"finetune.get": true, "quantize.start": true, "finetune.a.b": true,
|
|
"": false, "finetune": false, ".get": false, "Finetune.get": false, "finetune.get ": false,
|
|
"finetune/get": false, "finetune.get\n": false, "fine-tune.get": false, "finetune.": false,
|
|
strings.Repeat("a", 70) + ".get": false,
|
|
} {
|
|
if got := ValidHostOp(op); got != want {
|
|
t.Errorf("%q: got %v want %v", op, got, want)
|
|
}
|
|
}
|
|
}
|