feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s

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.
This commit is contained in:
Codex Local
2026-10-08 10:06:44 +08:00
parent 98fb2965d0
commit bf1233d5df
861 changed files with 94614 additions and 3209 deletions
+133
View File
@@ -0,0 +1,133 @@
package callmemory
import (
"context"
"errors"
"strings"
"testing"
"data-terminal-cloud/internal/volcsubtitle"
"github.com/google/uuid"
)
func openingWelcome(out any) string {
return out.(map[string]any)["params"].(map[string]any)["AgentConfig"].(map[string]any)["WelcomeMessage"].(string)
}
func assertNoOpeningActivity(t *testing.T, text string) {
t.Helper()
for _, invitation := range []string{"谜语", "猜猜", "猜个", "您猜", "编个", "编故事", "往下编", "故事可以这样开头"} {
if strings.Contains(text, invitation) {
t.Fatalf("opening starts an unrequested activity %q: %q", invitation, text)
}
}
}
func TestDirectDynamicOpeningFrozenAndRotation(t *testing.T) {
f, d := directFixture(t)
ctx := context.Background()
f.exec(t, `UPDATE subject_profile SET timezone='Asia/Shanghai',conversation_preferences='{"dynamic_opening":true}' WHERE id=$1::uuid`, f.subject)
var prepared []string
f.s.direct.PrepareWithWelcome = func(_ context.Context, subject, bot, sid, contextText, welcome string) error {
if subject != f.subject || bot != "elder-bot-"+f.subject || !validUUID(sid) {
t.Fatal("wrong preparation identity")
}
prepared = append(prepared, welcome)
return nil
}
seenIDs := map[string]bool{}
for i := 0; i < 7; i++ {
sid := uuid.NewString()
first, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: sid})
if err != nil {
t.Fatal(err)
}
assertNoOpeningActivity(t, openingWelcome(first))
if openingWelcome(first) != prepared[i] {
t.Fatal("supplier and device welcome differ")
}
retry, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: sid})
if err != nil || len(prepared) != i+1 || openingWelcome(first) != openingWelcome(retry) {
t.Fatal("renewal regenerated opening", err)
}
var meta directOpeningMetadata
var raw []byte
if err = f.p.QueryRow(ctx, `SELECT budget_snapshot->'opening' FROM call_session WHERE id=$1::uuid`, sid).Scan(&raw); err != nil || StrictJSON(raw, &meta) != nil {
t.Fatal("missing opening metadata", err, string(raw))
}
if i < 6 && seenIDs[meta.ID] {
t.Fatal("recent opening repeated", meta)
}
seenIDs[meta.ID] = true
if strings.Contains(string(raw), openingWelcome(first)) || strings.Contains(string(raw), "interests") {
t.Fatal("opening metadata stores personal text")
}
if _, err = f.s.DirectRequest(ctx, d, "end", DirectInput{SessionID: sid, Reason: "hangup", SDKStopped: true}); err != nil {
t.Fatal(err)
}
}
other, otherDevice := directFixture(t)
out, err := other.s.DirectRequest(ctx, otherDevice, "start", DirectInput{SessionID: uuid.NewString()})
if err != nil || openingWelcome(out) != "你好,今天想聊些什么?" {
t.Fatal("pilot changed another elder", err)
}
}
func TestDirectDynamicOpeningReopenAndRevocation(t *testing.T) {
f, d := directFixture(t)
ctx := context.Background()
f.exec(t, `UPDATE subject_profile SET profile_data='{"interests":["京剧"]}',conversation_preferences='{"dynamic_opening":true}' WHERE id=$1::uuid`, f.subject)
f.s.direct.PrepareWithWelcome = func(context.Context, string, string, string, string, string) error { return nil }
first := uuid.NewString()
if _, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: first}); err != nil {
t.Fatal(err)
}
n := int64(1)
for i, speaker := range []string{"input", "output"} {
seq := int64(i)
if err := f.s.DirectSubtitle(ctx, first, volcsubtitle.Packet{Type: "subtitle", Data: []volcsubtitle.Segment{{UserID: speaker, RoundID: &n, Sequence: &seq, Text: "测试真实字幕", Definite: true}}}); err != nil {
t.Fatal(err)
}
}
if _, err := f.s.DirectRequest(ctx, d, "end", DirectInput{SessionID: first, Reason: "hangup", SDKStopped: true}); err != nil {
t.Fatal(err)
}
next := uuid.NewString()
if _, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: next}); err != nil {
t.Fatal(err)
}
var category string
if err := f.p.QueryRow(ctx, `SELECT budget_snapshot->'opening'->>'category' FROM call_session WHERE id=$1::uuid`, next).Scan(&category); err != nil || category != "reconnect" {
t.Fatal("real recent exchange did not reconnect", category, err)
}
if _, err := f.s.DirectRequest(ctx, d, "end", DirectInput{SessionID: next, Reason: "hangup", SDKStopped: true}); err != nil {
t.Fatal(err)
}
f.exec(t, `UPDATE consent_record SET withdrawn_at=now() WHERE subject_id=$1::uuid AND consent_type='personalized_memory'`, f.subject)
// Retained transcript evidence must not re-enable personalized reconnect.
f.exec(t, `INSERT INTO call_utterance(session_id,utterance_id,source_revision,speaker,text_content,interrupted,source_at) VALUES($1::uuid,'test-user',0,'USER','测试',false,now()),($1::uuid,'test-assistant',0,'ASSISTANT','测试',false,now())`, next)
sid := uuid.NewString()
if _, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: sid}); err != nil {
t.Fatal(err)
}
if err := f.p.QueryRow(ctx, `SELECT budget_snapshot->'opening'->>'category' FROM call_session WHERE id=$1::uuid`, sid).Scan(&category); err != nil || category == "reconnect" || category == "interest" {
t.Fatal("revoked memory used for opening", category, err)
}
}
func TestDirectDynamicOpeningFailedPrepareDoesNotCommit(t *testing.T) {
f, d := directFixture(t)
ctx := context.Background()
f.exec(t, `UPDATE subject_profile SET conversation_preferences='{"dynamic_opening":true}' WHERE id=$1::uuid`, f.subject)
f.s.direct.PrepareWithWelcome = func(context.Context, string, string, string, string, string) error {
return errors.New("provider unavailable")
}
sid := uuid.NewString()
if _, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: sid}); err == nil || err.Error() != "VOICE_AGENT_CONFIG_FAILED" {
t.Fatal("failed configuration was accepted", err)
}
var count int
if err := f.p.QueryRow(ctx, `SELECT count(*) FROM call_session WHERE id=$1::uuid`, sid).Scan(&count); err != nil || count != 0 {
t.Fatal("failed preparation consumed a session/opening", count, err)
}
}