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
+85
View File
@@ -0,0 +1,85 @@
package vikingmemory
import (
"context"
"crypto/sha256"
"data-terminal-cloud/internal/callmemory"
"encoding/hex"
"encoding/json"
"errors"
"strings"
)
// ChatMemories returns untruncated native-chat records and checks scope again on
// every provider result. Memoir extraction and projection assistants are excluded.
func (c *Client) ChatMemories(ctx context.Context, user, kind, query string, limit int, start, end int64) ([]callmemory.VikingRecord, bool, error) {
if user == "" || kind != "event" && kind != "profile" || limit < 1 || limit > 5000 {
return nil, false, errors.New("invalid chat memory scope")
}
rule := c.options.EventType
if kind == "profile" {
rule = c.options.ProfileType
}
filter := map[string]any{"user_id": []string{user}, "assistant_id": []string{AssistantID}, "memory_type": []string{rule}}
if start > 0 {
filter["start_time"] = start
}
if end > 0 {
filter["end_time"] = end
}
payload := map[string]any{"filter": filter, "limit": limit}
if query != "" {
payload["query"] = query
}
var data struct {
Items []struct {
Item
Time int64 `json:"time"`
Types []string `json:"memory_type"`
} `json:"result_list"`
}
if e := c.call(ctx, "/api/memory/"+kind+"/search", payload, &data); e != nil {
return nil, false, e
}
out := []callmemory.VikingRecord{}
limited := len(data.Items) >= limit
for _, item := range data.Items {
// Shared records cannot be deleted through an individual elder's console.
if item.ID == "" || len(item.UserID) != 1 || item.UserID[0] != user || len(item.AssistantID) != 1 || item.AssistantID[0] != AssistantID || !contains(item.Types, rule) {
// A filtered or malformed response cannot prove a deleted ID is absent.
limited = true
continue
}
content := []string{}
for _, key := range []string{"summary", "user_profile"} {
if raw := item.MemoryInfo[key]; len(raw) > 0 {
var text string
if json.Unmarshal(raw, &text) != nil {
text = string(raw)
}
if strings.TrimSpace(text) != "" {
content = append(content, text)
}
}
}
if len(content) == 0 {
b, _ := json.MarshalIndent(item.MemoryInfo, "", " ")
content = append(content, string(b))
}
r := callmemory.VikingRecord{ID: item.ID, Kind: kind, Time: item.Time, SessionID: item.SessionID, Content: strings.Join(content, "\n"), MemoryInfo: item.MemoryInfo}
raw, e := json.Marshal(r)
if e != nil {
return nil, false, e
}
sum := sha256.Sum256(raw)
r.Digest = hex.EncodeToString(sum[:])
out = append(out, r)
}
return out, limited, nil
}
func (c *Client) DeleteChatMemory(ctx context.Context, kind, id string) error {
if (kind != "event" && kind != "profile") || id == "" {
return errors.New("invalid chat memory deletion")
}
return c.call(ctx, "/api/memory/"+kind+"/delete", map[string]any{kind + "_id": id}, nil)
}