Simplify model inventory responses #284

Merged
m merged 2 commits from codex/chat-semantic-inventory into main 2026-08-24 21:07:27 +00:00
2 changed files with 78 additions and 13 deletions
+67 -12
View File
@@ -30,6 +30,7 @@ import (
"log"
"net/http"
"os"
"sort"
"strconv"
"strings"
"time"
@@ -1510,28 +1511,82 @@ func humanCognitiveModelInventory(candidates []capability.ResolvedCognitiveBindi
if len(candidates) == 0 {
return "В реестре пока нет подтверждённых подключённых моделей. Встроенный локальный канал Домового доступен всегда; внешние модели добавляются через настройки подключения. Ключи и пароли в чат не выводятся."
}
lines := make([]string, 0, len(candidates)+1)
lines = append(lines, "Подключённые модели из реестра:")
type inventoryEntry struct {
name string
status string
rank int
seenAt int
}
entries := make([]inventoryEntry, 0, len(candidates))
byName := make(map[string]int, len(candidates))
for _, candidate := range candidates {
modelName := string(candidate.Model.ProviderModelID)
if modelName == "" {
modelName = "имя модели не подтверждено"
continue
}
status := cognitiveInventoryStatus(candidate)
pricing := cognitiveInventoryPricing(candidate.Provider)
details := []string{status, "тип " + string(candidate.Provider.Kind), "политика " + string(candidate.Binding.DataPolicy)}
if pricing != "" {
details = append(details, pricing)
status := conciseCognitiveInventoryStatus(candidate)
rank := cognitiveInventoryRank(candidate)
if index, exists := byName[modelName]; exists {
if rank < entries[index].rank {
entries[index].status = status
entries[index].rank = rank
}
continue
}
if candidate.Provider.AuthMode != "" && candidate.Provider.AuthMode != capability.AuthNone {
details = append(details, "доступ "+humanAuthMode(candidate.Provider.AuthMode))
byName[modelName] = len(entries)
entries = append(entries, inventoryEntry{name: modelName, status: status, rank: rank, seenAt: len(entries)})
}
sort.SliceStable(entries, func(left, right int) bool {
if entries[left].rank != entries[right].rank {
return entries[left].rank < entries[right].rank
}
lines = append(lines, "- "+modelName+" ("+strings.Join(details, "; ")+")")
return entries[left].seenAt < entries[right].seenAt
})
lines := make([]string, 0, len(entries)+2)
lines = append(lines, "Доступные модели:")
unconfirmed := 0
for _, entry := range entries {
if entry.rank >= 3 {
unconfirmed++
continue
}
lines = append(lines, "- "+entry.name+" — "+entry.status)
}
if len(lines) == 1 {
return "Подтверждённых доступных моделей сейчас нет."
}
if unconfirmed > 0 {
lines = append(lines, fmt.Sprintf("Ещё %d моделей требуют проверки.", unconfirmed))
}
lines = append(lines, "Секреты, ключи и пароли намеренно не показываются.")
return strings.Join(lines, "\n")
}
func conciseCognitiveInventoryStatus(candidate capability.ResolvedCognitiveBinding) string {
if candidate.Provider.Health == capability.HealthAvailable && candidate.Model.Health == capability.HealthAvailable {
if candidate.Binding.Activation == capability.ActivationActive {
return "активна"
}
return "доступна"
}
if candidate.Provider.Health == capability.HealthDegraded || candidate.Model.Health == capability.HealthDegraded {
return "работает с ограничениями"
}
return "не подтверждена"
}
func cognitiveInventoryRank(candidate capability.ResolvedCognitiveBinding) int {
if candidate.Provider.Health == capability.HealthAvailable && candidate.Model.Health == capability.HealthAvailable {
if candidate.Binding.Activation == capability.ActivationActive {
return 0
}
return 1
}
if candidate.Provider.Health == capability.HealthDegraded || candidate.Model.Health == capability.HealthDegraded {
return 2
}
return 3
}
func cognitiveInventoryStatus(candidate capability.ResolvedCognitiveBinding) string {
if candidate.Provider.Health == capability.HealthAvailable && candidate.Model.Health == capability.HealthAvailable {
if candidate.Binding.Activation == capability.ActivationActive {
+11 -1
View File
@@ -74,11 +74,21 @@ func TestHumanCognitiveModelInventoryDoesNotExposeSecrets(t *testing.T) {
Provider: capability.ProviderInstance{Kind: "openai-compatible-chat-v1", CredentialRef: "secret-ref", AuthMode: capability.AuthKey, BillingMode: capability.BillingPerRequest, RequestCostMicros: &cost, Health: capability.HealthAvailable},
Model: capability.ModelDescriptor{ProviderModelID: "example-model", Health: capability.HealthAvailable},
}}, nil)
if strings.Contains(text, "secret-ref") || strings.Contains(text, "25") || !strings.Contains(text, "example-model") || !strings.Contains(text, "API-ключ") {
if strings.Contains(text, "secret-ref") || strings.Contains(text, "25") || !strings.Contains(text, "example-model") || !strings.Contains(text, "активна") {
t.Fatalf("unsafe or incomplete inventory: %q", text)
}
}
func TestHumanCognitiveModelInventoryDeduplicatesAndPrioritizesAvailable(t *testing.T) {
text := humanCognitiveModelInventory([]capability.ResolvedCognitiveBinding{
{Binding: capability.CognitiveBinding{Activation: capability.ActivationInactive}, Provider: capability.ProviderInstance{Health: capability.HealthUnavailable}, Model: capability.ModelDescriptor{ProviderModelID: "same-model", Health: capability.HealthUnavailable}},
{Binding: capability.CognitiveBinding{Activation: capability.ActivationActive}, Provider: capability.ProviderInstance{Health: capability.HealthAvailable}, Model: capability.ModelDescriptor{ProviderModelID: "same-model", Health: capability.HealthAvailable}},
}, nil)
if strings.Count(text, "same-model") != 1 || !strings.Contains(text, "same-model — активна") {
t.Fatalf("expected one active model entry, got %q", text)
}
}
func TestCreatorSessionHandlerAcceptsConfiguredCredentials(t *testing.T) {
handler := creatorSessionHandler("recovery", "m", "password", []byte("01234567890123456789012345678901"), func() time.Time { return time.Unix(1000, 0) })
request := httptest.NewRequest(http.MethodPost, "/v1/creator/sessions", strings.NewReader(`{"username":"m","password":"password"}`))