feat(vnext): complete vNext.1 release gate — default chain admission, idempotent init, user key skeleton
- DEFAULT_CHAIN_ADMISSION.md: reviewed and approved, real artifact refs added - DEFAULT_DATA_IDEMPOTENT_RELEASE_GATE.md: reviewed and approved - scripts/setup_default_data.sh: idempotent init with --dry-run/--apply/artifact - scripts/test/test_default_data.sh: 4 test cases all pass - scripts/acceptance/verify_user_key_self_service.sh: Phase 0 skeleton - .gitignore: add generated artifact directories
This commit is contained in:
68
internal/host/sub2api/capability_inventory.go
Normal file
68
internal/host/sub2api/capability_inventory.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package sub2api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sub2api-cn-relay-manager/internal/probe"
|
||||
)
|
||||
|
||||
const (
|
||||
SupportLevelDirect = "supported-direct"
|
||||
SupportLevelWithPluginAdapter = "supported-with-plugin-adapter"
|
||||
SupportLevelUnsupportedByHost = "unsupported-by-host"
|
||||
SupportLevelUpstreamUnhealthy = "upstream-unhealthy"
|
||||
)
|
||||
|
||||
type CapabilityInventory struct {
|
||||
HostReady bool `json:"host_ready"`
|
||||
Host HostCapabilities `json:"host"`
|
||||
Models []ModelCapabilitySummary `json:"models"`
|
||||
}
|
||||
|
||||
type ModelCapabilitySummary struct {
|
||||
RawModelID string `json:"raw_model_id"`
|
||||
CanonicalModelFamily string `json:"canonical_model_family"`
|
||||
SmokeChatOK bool `json:"smoke_chat_ok"`
|
||||
SupportLevel string `json:"support_level"`
|
||||
KnownAdvisories []string `json:"known_advisories,omitempty"`
|
||||
}
|
||||
|
||||
func BuildCapabilityInventory(hostCaps HostCapabilities, profile *probe.CapabilityProfile) CapabilityInventory {
|
||||
inventory := CapabilityInventory{
|
||||
HostReady: hasMinimumHostCapabilities(hostCaps),
|
||||
Host: hostCaps,
|
||||
Models: []ModelCapabilitySummary{},
|
||||
}
|
||||
if profile == nil {
|
||||
return inventory
|
||||
}
|
||||
|
||||
advisories := append([]string(nil), profile.TransportProfile.KnownAdvisories...)
|
||||
for _, model := range profile.ModelProfiles {
|
||||
inventory.Models = append(inventory.Models, ModelCapabilitySummary{
|
||||
RawModelID: strings.TrimSpace(model.RawModelID),
|
||||
CanonicalModelFamily: strings.TrimSpace(model.CanonicalModelFamily),
|
||||
SmokeChatOK: model.SmokeChatOK,
|
||||
SupportLevel: classifySupportLevel(profile.TransportProfile, model),
|
||||
KnownAdvisories: advisories,
|
||||
})
|
||||
}
|
||||
return inventory
|
||||
}
|
||||
|
||||
func hasMinimumHostCapabilities(c HostCapabilities) bool {
|
||||
return c.Groups && c.Channels && c.Accounts && c.AccountTest
|
||||
}
|
||||
|
||||
func classifySupportLevel(transport probe.TransportProfile, model probe.ModelCapabilityProfile) string {
|
||||
if !model.SmokeChatOK {
|
||||
return SupportLevelUpstreamUnhealthy
|
||||
}
|
||||
if transport.SupportsOpenAIChatCompletions && transport.SupportsOpenAIResponses {
|
||||
return SupportLevelDirect
|
||||
}
|
||||
if transport.SupportsOpenAIChatCompletions {
|
||||
return SupportLevelWithPluginAdapter
|
||||
}
|
||||
return SupportLevelUnsupportedByHost
|
||||
}
|
||||
76
internal/host/sub2api/capability_inventory_test.go
Normal file
76
internal/host/sub2api/capability_inventory_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package sub2api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sub2api-cn-relay-manager/internal/probe"
|
||||
)
|
||||
|
||||
func TestBuildCapabilityInventoryClassifiesSupportedWithAdapter(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inventory := BuildCapabilityInventory(
|
||||
HostCapabilities{
|
||||
Groups: true,
|
||||
Channels: true,
|
||||
Plans: true,
|
||||
Accounts: true,
|
||||
AccountTest: true,
|
||||
AccountModels: true,
|
||||
Subscriptions: true,
|
||||
},
|
||||
&probe.CapabilityProfile{
|
||||
TransportProfile: probe.TransportProfile{
|
||||
SupportsOpenAIModels: true,
|
||||
SupportsOpenAIChatCompletions: true,
|
||||
SupportsOpenAIResponses: false,
|
||||
KnownAdvisories: []string{"responses_unsupported_but_chat_ok"},
|
||||
},
|
||||
ModelProfiles: []probe.ModelCapabilityProfile{{
|
||||
RawModelID: "kimi-k2.6",
|
||||
CanonicalModelFamily: "kimi-k2.6",
|
||||
SmokeChatOK: true,
|
||||
}},
|
||||
},
|
||||
)
|
||||
|
||||
if !inventory.HostReady {
|
||||
t.Fatal("HostReady = false, want true")
|
||||
}
|
||||
if len(inventory.Models) != 1 {
|
||||
t.Fatalf("len(Models) = %d, want 1", len(inventory.Models))
|
||||
}
|
||||
if inventory.Models[0].SupportLevel != SupportLevelWithPluginAdapter {
|
||||
t.Fatalf("SupportLevel = %q, want %q", inventory.Models[0].SupportLevel, SupportLevelWithPluginAdapter)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCapabilityInventoryClassifiesUpstreamUnhealthy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
inventory := BuildCapabilityInventory(
|
||||
HostCapabilities{Groups: true, Channels: true, Accounts: true, AccountTest: false},
|
||||
&probe.CapabilityProfile{
|
||||
TransportProfile: probe.TransportProfile{
|
||||
SupportsOpenAIModels: true,
|
||||
SupportsOpenAIChatCompletions: false,
|
||||
SupportsOpenAIResponses: false,
|
||||
},
|
||||
ModelProfiles: []probe.ModelCapabilityProfile{{
|
||||
RawModelID: "glm-4.5",
|
||||
CanonicalModelFamily: "glm-4.5",
|
||||
SmokeChatOK: false,
|
||||
}},
|
||||
},
|
||||
)
|
||||
|
||||
if inventory.HostReady {
|
||||
t.Fatal("HostReady = true, want false when required host capabilities are missing")
|
||||
}
|
||||
if len(inventory.Models) != 1 {
|
||||
t.Fatalf("len(Models) = %d, want 1", len(inventory.Models))
|
||||
}
|
||||
if inventory.Models[0].SupportLevel != SupportLevelUpstreamUnhealthy {
|
||||
t.Fatalf("SupportLevel = %q, want %q", inventory.Models[0].SupportLevel, SupportLevelUpstreamUnhealthy)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user