81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
// Package ai handles immutable Agent-version snapshots. The JSON Schema is
|
|
// loaded from the pinned upstream contract bundle; this package does not
|
|
// duplicate or loosen that schema.
|
|
package ai
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"unicode/utf8"
|
|
|
|
"github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer"
|
|
|
|
"git.ipao.vip/rogee/go-sip/contracts"
|
|
"git.ipao.vip/rogee/go-sip/internal/contract"
|
|
)
|
|
|
|
type Mode string
|
|
|
|
const (
|
|
ModeFullAI Mode = "full_ai"
|
|
ModeASROnly Mode = "asr_only"
|
|
)
|
|
|
|
type Snapshot struct {
|
|
TenantKey string
|
|
AgentVersionID string
|
|
Digest string
|
|
Raw []byte
|
|
Mode Mode
|
|
}
|
|
|
|
func Validate(raw []byte) (Snapshot, error) {
|
|
if !utf8.Valid(raw) {
|
|
return Snapshot{}, errors.New("AI configuration must be valid UTF-8")
|
|
}
|
|
if err := contract.ValidateSourceSchema("ai-config.schema.json", raw); err != nil {
|
|
return Snapshot{}, err
|
|
}
|
|
var value struct {
|
|
AgentVersionID string `json:"agent_version_id"`
|
|
Mode Mode `json:"mode"`
|
|
}
|
|
if err := json.Unmarshal(raw, &value); err != nil {
|
|
return Snapshot{}, err
|
|
}
|
|
mode := value.Mode
|
|
if mode == "" {
|
|
// Legacy immutable snapshots predate the explicit mode field and are
|
|
// full-AI snapshots because llm/prompt/tts are required by that branch.
|
|
mode = ModeFullAI
|
|
}
|
|
if mode != ModeFullAI && mode != ModeASROnly {
|
|
return Snapshot{}, fmt.Errorf("unsupported AI mode %q", mode)
|
|
}
|
|
canonical, err := jsoncanonicalizer.Transform(raw)
|
|
if err != nil {
|
|
return Snapshot{}, fmt.Errorf("canonicalize AI configuration: %w", err)
|
|
}
|
|
digest := sha256.Sum256(canonical)
|
|
return Snapshot{AgentVersionID: value.AgentVersionID, Digest: hex.EncodeToString(digest[:]), Raw: append([]byte(nil), raw...), Mode: mode}, nil
|
|
}
|
|
|
|
func ValidateForMode(raw []byte, mode Mode) (Snapshot, error) {
|
|
if mode != ModeFullAI && mode != ModeASROnly {
|
|
return Snapshot{}, fmt.Errorf("unsupported AI mode %q", mode)
|
|
}
|
|
snapshot, err := Validate(raw)
|
|
if err != nil {
|
|
return Snapshot{}, err
|
|
}
|
|
if snapshot.Mode != mode {
|
|
return Snapshot{}, fmt.Errorf("AI config mode %q does not match requested mode %q", snapshot.Mode, mode)
|
|
}
|
|
return snapshot, nil
|
|
}
|
|
|
|
func ContractSource() string { return contracts.SourceCommit }
|