feat: establish unified administration and model context baseline
This commit is contained in:
@@ -24,11 +24,10 @@ const (
|
||||
var renameProjectionDirectory = os.Rename
|
||||
|
||||
type runtimeCatalog struct {
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
DefaultSession string `json:"defaultSession"`
|
||||
DefaultMetadataGeneration string `json:"defaultMetadataGeneration,omitempty"`
|
||||
Embedding config.ModelCatalogEmbedding `json:"embedding"`
|
||||
Models []runtimeCatalogModel `json:"models"`
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
DefaultInteraction string `json:"defaultInteraction"`
|
||||
Embedding config.ModelCatalogEmbedding `json:"embedding"`
|
||||
Models []runtimeCatalogModel `json:"models"`
|
||||
}
|
||||
|
||||
type runtimeCatalogModel struct {
|
||||
@@ -74,19 +73,33 @@ type piSettings struct {
|
||||
|
||||
// Render builds every projection in memory so no partial candidate can be published.
|
||||
func Render(installation config.Installation) (map[string][]byte, error) {
|
||||
if err := installation.ModelCatalog.NormalizeDefaults(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models := installation.ModelCatalog.RuntimeModels()
|
||||
hasMetadata := false
|
||||
for _, model := range models {
|
||||
hasMetadata = hasMetadata || model.MetadataGeneration != nil
|
||||
}
|
||||
runtimeModels := make([]runtimeCatalogModel, 0, len(models))
|
||||
customProviders := make(map[string]piProvider)
|
||||
enabled := make([]string, 0)
|
||||
for _, model := range models {
|
||||
sessionAdapter, metadataAdapter := model.SessionAdapter, model.MetadataAdapter
|
||||
if model.Session == nil {
|
||||
sessionAdapter = nil
|
||||
}
|
||||
if model.MetadataGeneration == nil {
|
||||
metadataAdapter = nil
|
||||
}
|
||||
runtimeModels = append(runtimeModels, runtimeCatalogModel{
|
||||
ID: model.ID, Provider: model.Provider, Model: model.Model, Label: model.Label,
|
||||
UpstreamModel: model.UpstreamModel, Endpoint: model.Endpoint,
|
||||
Authentication: model.Authentication, SessionAdapter: model.SessionAdapter,
|
||||
MetadataAdapter: model.MetadataAdapter, Session: model.Session,
|
||||
Authentication: model.Authentication, SessionAdapter: sessionAdapter,
|
||||
MetadataAdapter: metadataAdapter, Session: model.Session,
|
||||
MetadataGeneration: model.MetadataGeneration,
|
||||
})
|
||||
if model.Session == nil {
|
||||
if model.Session == nil || (hasMetadata && model.MetadataGeneration == nil) {
|
||||
continue
|
||||
}
|
||||
if model.SessionAdapter == nil || model.SessionAdapter.Mode != "openai_compatible" {
|
||||
@@ -117,9 +130,8 @@ func Render(installation config.Installation) (map[string][]byte, error) {
|
||||
sort.Strings(enabled)
|
||||
|
||||
catalogBytes, err := marshalJSON(runtimeCatalog{
|
||||
SchemaVersion: 1, DefaultSession: installation.ModelCatalog.Defaults.Session,
|
||||
DefaultMetadataGeneration: installation.ModelCatalog.Defaults.MetadataGeneration,
|
||||
Embedding: installation.ModelCatalog.Embedding, Models: runtimeModels,
|
||||
SchemaVersion: 2, DefaultInteraction: installation.ModelCatalog.Defaults.Interaction,
|
||||
Embedding: installation.ModelCatalog.Embedding, Models: runtimeModels,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("render runtime model catalog: %w", err)
|
||||
@@ -294,7 +306,7 @@ func renderCompose(installation config.Installation, fingerprint string) []byte
|
||||
embedding-model-init:
|
||||
environment:
|
||||
OLLAMA_MODEL: %s
|
||||
`, strconv.Quote(fingerprint), strconv.Quote(installation.ModelCatalog.Defaults.Session),
|
||||
`, strconv.Quote(fingerprint), strconv.Quote(installation.ModelCatalog.Defaults.Interaction),
|
||||
strconv.Quote(embedding.ID), strconv.Quote(embeddingModelName(embedding.ID)), strconv.Quote(strconv.Itoa(embedding.Dimensions)),
|
||||
strconv.Quote(installation.GeneratedModelCatalogPath()), strconv.Quote(installation.GeneratedPiModelsPath()),
|
||||
strconv.Quote(installation.GeneratedPiSettingsPath()), strconv.Quote(embedding.ID),
|
||||
|
||||
@@ -2,6 +2,7 @@ package modelprojection
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -32,7 +33,7 @@ func TestRenderProducesDeterministicCatalogPiAndComposeProjections(t *testing.T)
|
||||
}
|
||||
|
||||
catalog := string(first[CatalogFile])
|
||||
for _, expected := range []string{`"id": "local/qwen"`, `"defaultSession": "zai/glm-5.3"`, `"embedding"`} {
|
||||
for _, expected := range []string{`"id": "local/qwen"`, `"defaultInteraction": "zai/glm-5.3"`, `"embedding"`} {
|
||||
if !strings.Contains(catalog, expected) {
|
||||
t.Fatalf("catalog projection missing %s:\n%s", expected, catalog)
|
||||
}
|
||||
@@ -42,8 +43,8 @@ func TestRenderProducesDeterministicCatalogPiAndComposeProjections(t *testing.T)
|
||||
t.Fatalf("Pi models projection must contain only custom providers:\n%s", piModels)
|
||||
}
|
||||
settings := string(first[PiSettingsFile])
|
||||
if !strings.Contains(settings, `"deepseek/deepseek-v4-pro"`) || !strings.Contains(settings, `"local/qwen2.5:7b"`) {
|
||||
t.Fatalf("Pi settings projection missing enabled session models:\n%s", settings)
|
||||
if strings.Contains(settings, `"deepseek/deepseek-v4-pro"`) || !strings.Contains(settings, `"local/qwen2.5:7b"`) {
|
||||
t.Fatalf("Pi settings must enable only shared Core/Admin models:\n%s", settings)
|
||||
}
|
||||
if !strings.Contains(piModels, `"id": "qwen2.5:7b"`) || !strings.Contains(catalog, `"id": "local/qwen"`) {
|
||||
t.Fatalf("Pi projection must map canonical catalog keys to upstream model IDs")
|
||||
@@ -56,6 +57,69 @@ func TestRenderProducesDeterministicCatalogPiAndComposeProjections(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepSeekBuiltinAndMetadataShareCatalogIdentityAndSecretReference(t *testing.T) {
|
||||
i := projectionFixture(t)
|
||||
p := i.ModelCatalog.Providers["deepseek"]
|
||||
p.Authentication = config.ModelAuthentication{Mode: "secret_env", APIKeyEnv: "DEEPSEEK_API_KEY"}
|
||||
p.MetadataGeneration = &config.ModelMetadataAdapter{LiteLLMProvider: "deepseek"}
|
||||
for _, id := range []string{"deepseek-v4-pro", "deepseek-v4-flash"} {
|
||||
p.Models[id] = config.CatalogModel{Session: &config.SessionModel{}, MetadataGeneration: &config.MetadataGenerationModel{}}
|
||||
}
|
||||
i.ModelCatalog.Providers["deepseek"] = p
|
||||
i.ModelCatalog.Defaults.Interaction = "deepseek/deepseek-v4-pro"
|
||||
files, err := Render(i)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var catalog runtimeCatalog
|
||||
if err := json.Unmarshal(files[CatalogFile], &catalog); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
count := 0
|
||||
for _, model := range catalog.Models {
|
||||
if model.Provider != "deepseek" {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
if model.Authentication.APIKeyEnv != "DEEPSEEK_API_KEY" || model.SessionAdapter == nil || model.MetadataAdapter == nil {
|
||||
t.Fatalf("DeepSeek must share auth and both adapters: %#v", model)
|
||||
}
|
||||
if !bytes.Contains(files[PiSettingsFile], []byte(model.ID)) {
|
||||
t.Fatalf("shared model missing from Pi selection: %s", model.ID)
|
||||
}
|
||||
}
|
||||
if count != 2 || bytes.Contains(files[PiModelsFile], []byte("deepseek")) {
|
||||
t.Fatal("both DeepSeek models must use native Pi definitions, not duplicated custom definitions")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectionKeepsSingleUseInventoryOutOfSharedPiSelection(t *testing.T) {
|
||||
i := projectionFixture(t)
|
||||
p := i.ModelCatalog.Providers["zai"]
|
||||
p.Models["core-only"] = config.CatalogModel{Session: &config.SessionModel{ContextWindow: 32768, MaxTokens: 8192}}
|
||||
p.Models["admin-only"] = config.CatalogModel{MetadataGeneration: &config.MetadataGenerationModel{}}
|
||||
i.ModelCatalog.Providers["zai"] = p
|
||||
files, err := Render(i)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var catalog runtimeCatalog
|
||||
if err := json.Unmarshal(files[CatalogFile], &catalog); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, model := range catalog.Models {
|
||||
if model.ID == "zai/core-only" && model.MetadataAdapter != nil {
|
||||
t.Fatal("projected an unused metadata adapter")
|
||||
}
|
||||
if model.ID == "zai/admin-only" && model.SessionAdapter != nil {
|
||||
t.Fatal("projected an unused session adapter")
|
||||
}
|
||||
}
|
||||
if bytes.Contains(files[PiSettingsFile], []byte("core-only")) || bytes.Contains(files[PiSettingsFile], []byte("admin-only")) {
|
||||
t.Fatal("single-use inventory leaked into global Pi selection")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateDoesNotReplaceUnchangedProjection(t *testing.T) {
|
||||
installation := projectionFixture(t)
|
||||
if err := Generate(installation); err != nil {
|
||||
@@ -167,11 +231,11 @@ func projectionFixture(t *testing.T) config.Installation {
|
||||
return config.Installation{
|
||||
Path: filepath.Join(root, "thothii-installation.yaml"),
|
||||
ModelCatalog: config.ModelCatalog{
|
||||
Defaults: config.ModelCatalogDefaults{Session: "zai/glm-5.3", MetadataGeneration: "local/qwen"},
|
||||
Defaults: config.ModelCatalogDefaults{Interaction: "zai/glm-5.3"},
|
||||
Embedding: config.ModelCatalogEmbedding{ID: "ollama/qwen3-embedding:0.6b", Dimensions: 1024},
|
||||
Providers: map[string]config.ModelProvider{
|
||||
"deepseek": {Authentication: config.ModelAuthentication{Mode: "pi_auth"}, Session: &config.ModelSessionAdapter{Mode: "pi_builtin"}, Models: map[string]config.CatalogModel{"deepseek-v4-pro": {Session: &config.SessionModel{}}}},
|
||||
"zai": {Endpoint: &config.ModelEndpoint{BaseURL: "https://api.z.ai/v1"}, Authentication: config.ModelAuthentication{Mode: "none"}, Session: &config.ModelSessionAdapter{Mode: "openai_compatible"}, Models: map[string]config.CatalogModel{"glm-5.3": {Label: "GLM-5.3", Session: &config.SessionModel{Reasoning: true, ContextWindow: 200000, MaxTokens: 131072}}}},
|
||||
"zai": {Endpoint: &config.ModelEndpoint{BaseURL: "https://api.z.ai/v1"}, Authentication: config.ModelAuthentication{Mode: "none"}, Session: &config.ModelSessionAdapter{Mode: "openai_compatible"}, MetadataGeneration: &config.ModelMetadataAdapter{LiteLLMProvider: "openai"}, Models: map[string]config.CatalogModel{"glm-5.3": {Label: "GLM-5.3", Session: &config.SessionModel{Reasoning: true, ContextWindow: 200000, MaxTokens: 131072}, MetadataGeneration: &config.MetadataGenerationModel{}}}},
|
||||
"local": {Endpoint: &config.ModelEndpoint{BaseURL: "http://ollama:11434/v1"}, Authentication: config.ModelAuthentication{Mode: "none"}, Session: &config.ModelSessionAdapter{Mode: "openai_compatible"}, MetadataGeneration: &config.ModelMetadataAdapter{LiteLLMProvider: "openai"}, Models: map[string]config.CatalogModel{"qwen": {UpstreamModel: "qwen2.5:7b", Session: &config.SessionModel{ContextWindow: 32768, MaxTokens: 8192}, MetadataGeneration: &config.MetadataGenerationModel{DisableThinking: true}}}},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user