Files
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

325 lines
10 KiB
Go

// Package callmemory implements CALL-MEMORY-1.1. Provider capabilities are
// evidence-backed release gates, never inferred from a successful configuration write.
package callmemory
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"sort"
"strings"
"time"
"unicode/utf8"
)
const ContractVersion = "CALL-MEMORY-1.1"
const MaxBody = 8 << 10
const MaxMemoryBody = 64 << 10
const LeaseMS int64 = 45000
const ManifestMS int64 = 30000
type Error struct {
Status int
Code, Message, Recovery string
}
func (e *Error) Error() string { return e.Code }
func fault(status int, code string) *Error { return &Error{status, code, code, "NONE"} }
func hash(b []byte) string { h := sha256.Sum256(b); return hex.EncodeToString(h[:]) }
func jsonBytes(v any) []byte { b, _ := json.Marshal(v); return b }
// StrictJSON rejects ambiguous duplicate keys, trailing values and unknown struct fields.
func StrictJSON(b []byte, v any) error {
if !utf8.Valid(b) {
return fault(400, "INVALID_JSON")
}
d := json.NewDecoder(bytes.NewReader(b))
d.UseNumber()
var walk func() error
walk = func() error {
t, e := d.Token()
if e != nil {
return e
}
delim, ok := t.(json.Delim)
if !ok {
return nil
}
switch delim {
case '{':
keys := map[string]bool{}
for d.More() {
k, e := d.Token()
if e != nil {
return e
}
s, ok := k.(string)
if !ok || keys[s] {
return errors.New("duplicate key")
}
keys[s] = true
if e = walk(); e != nil {
return e
}
}
case '[':
for d.More() {
if e := walk(); e != nil {
return e
}
}
default:
return errors.New("invalid delimiter")
}
_, e = d.Token()
return e
}
if e := walk(); e != nil {
return fault(400, "INVALID_JSON")
}
if _, e := d.Token(); e != io.EOF {
return fault(400, "INVALID_JSON")
}
d = json.NewDecoder(bytes.NewReader(b))
d.DisallowUnknownFields()
if e := d.Decode(v); e != nil {
return fault(400, "INVALID_JSON")
}
return nil
}
func ManifestMAC(key []byte, b64 string) string {
h := hmac.New(sha256.New, key)
h.Write([]byte("CALLCFG1\n" + b64))
return hex.EncodeToString(h.Sum(nil))
}
func EncodeManifest(key []byte, m Manifest) (string, string, error) {
b, e := json.Marshal(m)
if e != nil || len(key) != 32 || len(b) > 24<<10 {
return "", "", fault(400, "INVALID_MANIFEST")
}
encoded := base64.RawURLEncoding.EncodeToString(b)
return encoded, ManifestMAC(key, encoded), nil
}
func DecodeManifest(key []byte, b64, mac string) (Manifest, error) {
var m Manifest
if len(key) != 32 || len(b64) > 32<<10 || len(mac) != 64 || !hmac.Equal([]byte(ManifestMAC(key, b64)), []byte(mac)) {
return m, fault(400, "MANIFEST_INVALID")
}
b, e := base64.RawURLEncoding.DecodeString(b64)
if e != nil || base64.RawURLEncoding.EncodeToString(b) != b64 {
return m, fault(400, "MANIFEST_INVALID")
}
e = StrictJSON(b, &m)
if e == nil {
e = m.Validate()
}
return m, e
}
// Validate is also used by device clients after authenticating the original bytes.
func (m Manifest) Validate() error {
if m.ContractVersion != ContractVersion || !validUUID(m.ManifestID) || !validUUID(m.SessionID) || !short(m.DeviceID) || !validUUID(m.BootID) || !short(m.HookID) || m.CallGeneration < 0 || m.BindingGeneration < 0 || m.Mode != "RTC" || !short(m.BotID) || !short(m.ProfileID) || !short(m.AudioProfileID) || !oneOf(m.Purpose, "NORMAL", "FIRST_TEST") || !oneOf(m.FirstTurnMode, "AI_WELCOME", "USER_FIRST") || !oneOf(m.MemoryMode, "OFF", "HOT_ONLY", "NATIVE_VIKING") || m.MemoryRevision < 0 || m.VisibleRevision < 0 || m.VisibleRevision > m.MemoryRevision || m.PrivacyEpoch < 0 || m.ContextVersion < 0 || m.IssuedAt <= 0 || m.ExpiresAt <= m.IssuedAt || m.ExpiresAt-m.IssuedAt > ManifestMS || m.LeaseMS <= 0 || m.LeaseMS > LeaseMS || m.LeaseExpiresAt <= m.IssuedAt || m.LeaseExpiresAt-m.IssuedAt > m.LeaseMS || m.MaxCallMS <= 0 || m.MaxCallMS > 3600000 || len(m.VendorParams) > 16<<10 || !json.Valid([]byte(m.VendorParams)) || (m.LocalNotice && !short(m.NoticeProfileID)) {
return fault(400, "MANIFEST_INVALID")
}
return nil
}
type Manifest struct {
ContractVersion string `json:"contract_version"`
ManifestID string `json:"manifest_id"`
SessionID string `json:"business_session_id"`
DeviceID string `json:"device_id"`
BootID string `json:"boot_id"`
HookID string `json:"hook_event_id"`
CallGeneration int64 `json:"call_generation"`
BindingGeneration int64 `json:"binding_generation"`
IssuedAt int64 `json:"issued_at_ms"`
ExpiresAt int64 `json:"expires_at_ms"`
Mode string `json:"mode"`
BotID string `json:"bot_id"`
ProfileID string `json:"provider_profile_id"`
Purpose string `json:"purpose"`
FirstTurnMode string `json:"first_turn_mode"`
MemoryMode string `json:"memory_mode"`
MemoryRevision int64 `json:"memory_revision"`
VisibleRevision int64 `json:"viking_visible_revision"`
PrivacyEpoch int64 `json:"privacy_epoch"`
ContextVersion int64 `json:"context_version"`
AudioProfileID string `json:"audio_profile_id"`
VendorParams string `json:"vendor_params_json"`
LeaseMS int64 `json:"auth_lease_ms"`
LeaseExpiresAt int64 `json:"auth_lease_expires_at_ms"`
MaxCallMS int64 `json:"max_call_ms"`
LocalNotice bool `json:"local_notice_enabled"`
NoticeProfileID string `json:"notice_profile_id"`
}
type Profile struct {
ID, SDKVersion, BotID, ModelVersion, Transport string
Audio map[string]any
Template map[string]any
Mapping map[string]string
Capabilities map[string]bool
Evidence map[string]string
}
func (p Profile) Check(mode string) error {
if !oneOf(mode, "OFF", "HOT_ONLY", "NATIVE_VIKING") || p.ID == "" || p.SDKVersion == "" || p.BotID == "" || p.ModelVersion == "" || p.Transport != "RTC" {
return fault(409, "PROVIDER_PROFILE_UNVERIFIED")
}
for _, g := range []string{"H01", "H02", "H04", "H05", "H06", "H07", "H09", "H11"} {
if strings.TrimSpace(p.Evidence[g]) == "" || !p.Capabilities[g] {
return fault(409, "PROVIDER_PROFILE_UNVERIFIED")
}
}
if mode == "NATIVE_VIKING" {
for _, g := range []string{"H03", "H08", "H12"} {
if p.Evidence[g] == "" || !p.Capabilities[g] {
return fault(409, "PROVIDER_PROFILE_UNVERIFIED")
}
}
}
return nil
}
// Compile changes only explicitly reviewed JSON pointer paths. OFF clears the
// exact same fields used by native memory; no guessed provider field names.
func (p Profile) Compile(mode, context, welcome, user, assistant, dialog string) (string, error) {
if e := p.Check(mode); e != nil {
return "", e
}
var out map[string]any
if e := json.Unmarshal(jsonBytes(p.Template), &out); e != nil {
return "", e
}
paths := []string{}
for _, name := range []string{"memory_enabled", "hot_context", "welcome_text", "user_id", "assistant_id", "dialog_id"} {
path := p.Mapping[name]
for _, prior := range paths {
if path == prior || strings.HasPrefix(path, prior+"/") || strings.HasPrefix(prior, path+"/") {
return "", fault(409, "PROVIDER_MAPPING_UNVERIFIED")
}
}
paths = append(paths, path)
}
values := map[string]any{"memory_enabled": mode == "NATIVE_VIKING", "hot_context": context, "welcome_text": welcome, "user_id": user, "assistant_id": assistant, "dialog_id": dialog}
if mode == "OFF" {
values["hot_context"] = ""
values["welcome_text"] = ""
}
if mode != "NATIVE_VIKING" {
values["user_id"] = ""
values["assistant_id"] = ""
}
for name, v := range values {
path := p.Mapping[name]
if path == "" {
return "", fault(409, "PROVIDER_MAPPING_UNVERIFIED")
}
if e := setPointer(out, path, v); e != nil {
return "", e
}
}
b, e := json.Marshal(out)
if e != nil || len(b) > 16<<10 {
return "", fault(413, "VENDOR_PARAMS_TOO_LARGE")
}
return string(b), nil
}
func setPointer(m map[string]any, path string, value any) error {
if !strings.HasPrefix(path, "/") {
return fault(409, "PROVIDER_MAPPING_UNVERIFIED")
}
parts := strings.Split(path[1:], "/")
for i, raw := range parts {
k := strings.ReplaceAll(strings.ReplaceAll(raw, "~1", "/"), "~0", "~")
if k == "" {
return fault(409, "PROVIDER_MAPPING_UNVERIFIED")
}
if i == len(parts)-1 {
m[k] = value
return nil
}
n, ok := m[k].(map[string]any)
if !ok {
return fault(409, "PROVIDER_MAPPING_UNVERIFIED")
}
m = n
}
return nil
}
type ContextFact struct {
ID, EntityKey, Text, Type, ItemStatus, Policy string
Version int64
SourceTime time.Time
}
func BuildContext(facts []ContextFact, limit int) string {
// Only the latest valid record for one entity participates. Keep complete facts
// so truncation cannot strip a negation, a date, or an uncertainty qualifier.
sort.SliceStable(facts, func(i, j int) bool {
if !facts[i].SourceTime.Equal(facts[j].SourceTime) {
return facts[i].SourceTime.After(facts[j].SourceTime)
}
if facts[i].Version != facts[j].Version {
return facts[i].Version > facts[j].Version
}
return facts[i].ID < facts[j].ID
})
seen := map[string]bool{}
parts := []string{}
used := 0
for _, f := range facts {
key := f.EntityKey
if key == "" {
key = f.ID
}
if seen[key] {
continue
}
seen[key] = true
if f.Policy != "ALLOWED" || strings.TrimSpace(f.Text) == "" {
continue
}
if f.Type == "OPEN_ITEM" && f.ItemStatus != "OPEN" {
continue
}
text := strings.TrimSpace(f.Text)
n := utf8.RuneCountInString(text)
if used+n+1 > limit {
continue
}
used += n + 1
parts = append(parts, text)
}
return strings.Join(parts, "\n")
}
func SelectMemoryMode(revision, visible int64, critical, consent, offVerified bool) (string, error) {
if !consent {
if !offVerified {
return "", fault(409, "MEMORY_OFF_UNVERIFIED")
}
return "OFF", nil
}
if critical {
if !offVerified {
return "", fault(409, "MEMORY_CRITICAL_LAG")
}
return "HOT_ONLY", nil
}
if revision == 0 {
return "HOT_ONLY", nil
}
if visible <= revision {
return "NATIVE_VIKING", nil
}
return "", fmt.Errorf("invalid memory watermark")
}