- Bounded source review of mem0ai/mem0 @2c81af3 (embedded lib, Apache-2.0,
upstream-maintained extract/consolidate/hybrid-search; SQLite history)
- Zep CE screened out (4-container stack, legacy/docker-compose.ce.yaml:5-71)
- 8-mechanism matrix from discussion takeaways: requirement/current/candidate/
thin-adapter/to-verify per mechanism
- Recommendation shifts from v2 Option C (self-maintained port) to Route E
(direct SDK adoption + thin product adapters); Option C kept as verified
fallback; spike-first with acceptance gates, no claim of final selection
- v2 report carried in verbatim as evidence base
Co-authored-by: multica-agent <github@multica.ai>
- 6 modified + handoff JSON per CHANGES-HEL-824.json, all hashes verified against git 4321aeb and package bytes
- rework_browser_check: skip full-text sheet at micro height (<420px design hides the control); migrate stale 返回日子 selector to 结束交谈 · 回到日子
- fresh run evidence: web build 25/25 unit tests, backend 142/142 (py3.12), all four browser checks PASS incl. new compact first-press and 700ms slow-frame sections (slow_frames_new_turn_to_reply_s=2.32s), layout regression 320/390/1024/1600 both themes
Co-authored-by: multica-agent <github@multica.ai>
- browser_check.py: 视觉观察 → 视觉观察(模拟) (author renamed the aria-label, selector not migrated)
- import_check.py: handle the dirty-settings leave confirmation before opening the record (pre-existing gap, fails at base db571ba too)
- rework_browser_check.py: long-user-line reply budget 10s→60s (approved hel-799 dwell ≈2.4s/page), conditional 继续 resume (toLatest resumes flow in the approved prototype), 600ms settle before measuring compact typing nav transition
- regenerated docs/frontend + docs/rework evidence from this Linux run
Co-authored-by: multica-agent <github@multica.ai>
Single-file HTML, Canvas 2D, no libraries, no images, no fonts to load.
The one idea worth explaining: the accent colour IS the valence.
moodColor(v) maps v in [-1,1] across cold blue -> neutral grey -> warm amber,
and every mark in the frame reads from it. So when she drops, the whole
picture goes cold -- no caption has to tell you she is sad. Same data,
three places: the trace colour, the memory hue, the retrieval highlight.
Timeline is a pure function render(t), no RAF accumulation. Every frame
renders in isolation, which means frames are reproducible, any resolution
can be re-exported, and the preview can be captured frame-by-frame instead
of screen-recorded.
Four acts:
0-6s membrane matter bounces off it, information passes through
6-12s heartbeat beats with no input; positive recovers fast, negative slow
12-17s memory points sink by salience; one gets pulled back up
by a mood-matching cue; floor at 0.03 so nothing vanishes
17-22s title
Also: ?t=12.5 freezes on that frame (for cover shots), and a REC button
uses canvas.captureStream + MediaRecorder to export webm directly.
Preview: 200 ANMF frames, 22000ms total, verified by parsing the RIFF/ANMF
chunks (Pillow does not expose per-frame WebP duration).
tools/render_preview.py renders frames via headless Chrome and assembles.
On this Windows box Python cannot spawn Chrome (0x80000003, same family as
the 0xC0000142 shell failure), so the render loop was driven from PowerShell
and the script only assembled. Both paths are documented in the script.
Corrects a common misconception: the 60s heartbeat must not call any LLM.
It runs the mood decay equation -- microseconds of float math. Giving it a
model is an architecture error, not a resource problem.
Real token spend lands in two places:
- per-turn input context (ontology + state + dyad + memory)
- background task frequency
So route by scene, not by time:
none rule/math tick, reach-out decision, fillers, avatar drive
low local small life events, memory gist, fact extract
standard mid + short speculative-response second segment
high flagship main dialogue, proactive message, crisis
Hard constraints:
- dialogue floor is LOW, never NONE (can get dumber, cannot lose lines)
- crisis never degrades (product constraint, not perf tuning)
- degradation is predictable: one rung per request, floor only at
the hard budget threshold
Cost levers, by actual payoff:
1. prompt caching (fixed prefix) -- by far the largest
2. upstream compression (small model condenses 20 memories to 3)
3. batching (one batch per 30min, not 20 single calls)
4. swapping to a smaller model -- smallest payoff, hurts persona
Also: cost degradation is narratable. 'Net error -> I zoned out' already
exists in the projection table, so being throttled is in-character and true.
- config.py: tiers / routing / budget, replacing llm+llm_fast+llm_background
- think/: scenes, budget, router, wiring
- models.yaml restructured around tiers
- SPEC gains 9.5
- 20 new tests; 78 total pass; ruff clean
Contracts (the shared language):
- percept / state / context / utterance / render / audio / capabilities
- Capability model instead of vendor schemas (see below)
Providers (capability-based abstraction):
- LLM + Embedding: OpenAI-compatible shape IS the standard, adopted directly
- ASR: internal contract is an event stream (partial -> final), because
/v1/audio/transcriptions has no partial and dialogue needs it for
endpointing. OpenAI adapter degrades to supports_partial=False.
- TTS: internal contract carries tags/emotion/style, because
/v1/audio/speech has no paralinguistics and [laughter]/[breath] are
the core of feeling alive. Unsupported providers are stripped AND
reported via Degradation -- silent degradation is forbidden.
- Avatar: no de-facto standard, custom RenderCmd protocol driven by State.
Core:
- mood: dynamical system, slow variables, negativity bias (grudge),
numbing after prolonged negativity
- bazi: four pillars -> numeric vector; 'ming' is data, not prose
- projection: phi, system event -> in-world statement; uncovered events
are counted as projection gaps
Storage:
- SQLite schema, three memory layers, dyad ledger
- accessibility floor 0.03 (not 0): forgettable but still there
Config split:
- models.yaml is the ONLY place model versions live
- character.yaml holds world rules / emotion params, no version numbers
58 tests pass; ruff clean.