- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
14 KiB
Companions
Nomi's virtual companion has grown from "a single nomi" into a multi-companion
family: you can create several companions, use them side by side, raise
them separately, and give each its own name, character, persona, and
chat model. Each companion can also be bound to its own dedicated knowledge
bases (turning it into a finance companion, a literature companion, a coding companion,
…), while every companion shares one memory hub — collection and learning
run as a single global pipeline, so whatever one companion learns, the whole
family remembers. Memories, companions, and knowledge bases can each be
packed into a .zip bundle for export/import, making machine-to-machine
migration painless.
The entry point is the Desktop Companion page in the sidebar (the
/nomiroute); the right-click menu of any desktop companion window ("Open chat") deep-links there too.
Page layout: companion switcher + two tab domains
The top of the Desktop Companion page is the companion switcher bar: one card per companion (character thumbnail + name + level) plus a New companion button. The selected companion drives the companion-domain tabs below; everything that is global lives in the shared-domain tabs:
| Domain | Tab | Contents |
|---|---|---|
| Companion domain (follows the switcher) | Overview | Desktop-companion toggle + that companion's level / XP / mood + shared stats |
| Chat | That companion's own companion threads | |
| Model & Knowledge | Chat model picker / knowledge bindings | |
| Remote | That companion's IM bots (bound per companion — see the channels guide) | |
| Settings | Name / character / persona / quiet hours / delete companion | |
| Shared domain (one per install) | Memories · Collect · Learn · Suggestions | The shared memory hub (one copy for all companions) |
| Migrate | Export / import migration bundles (see below) |
Creating and managing companions
- Click New companion on the switcher bar, pick a name and one of the six characters (mochi / ink / roux / pixel / bolt / boo).
- The first companion automatically becomes the default companion (its card carries a "default" badge). The default companion is the fallback whenever a channel has no explicit binding (see the channels section below).
- In a companion's Settings tab you can rename it at any time (takes effect immediately), swap the character, tune the persona (preset or custom), pick a chat model just for this companion, and toggle the desktop companion plus its quiet hours.
- Deleting a companion cascades: its companion conversations, runtime
state (XP, …), and
('companion', companionId)knowledge bindings are removed together; if you delete the default companion, the default role moves on to the next one. Deleting down to zero companions is allowed (the shared memory hub exists independently of companions — collection and learning keep running).
On disk each companion is a directory — {data_dir}/companion/companions/{companion_id}/config.json,
the directory is the source of truth — which is also the unit the
companion bundle exports and imports.
Multiple desktop companions on screen
Every companion with the desktop-companion switch enabled gets its own desktop
window (transparent, always-on-top, draggable; window label
companion-{companionId}). Several can share the screen; keeping it to 5 or fewer
is recommended (each window is an independent WebView instance — the
UI warns about performance beyond that but does not enforce a limit).
Right-click any desktop companion to jump straight to its chat.
The shared memory hub
All companions share one set of memory facilities under
{data_dir}/companion/shared/:
- Collection — a single pipeline subscribes to the global event
bus, gathers your working data according to the collect switches,
and writes
shared/events/YYYYMMDD.jsonl. - Learning — a single learner incrementally distills events into
long-term memories on the configured interval, stored in
shared/memory.db. The learning pipeline uses the learn model from the shared config (independent of each companion's chat model — one pipeline, one budget). - Memories saved during any companion's chat, and memories produced by learning, are visible to every companion — switch companions mid-stream and the new one remembers everything that happened before.
XP and mood attribution
| Source | Credited to |
|---|---|
| Learning-run output (scored by events processed + new memories) | All companions (the family grows together) |
| Suggestion adopted (+20) | All companions |
| Companion chat turn (+2) | Only the companion in that conversation |
| Memory saved during chat (+5) | Only that companion |
Mood is global: it is produced by learning runs and stored in shared state, so all companions share one mood (per-companion mood/personality divergence is reserved for a later version).
Binding knowledge bases to a companion
In a companion's Model & Knowledge tab → Knowledge section, use the binding
control to mount one or more knowledge bases on that companion (the binding
is ('companion', companionId)). Scope of effect:
- The companion's companion chats and the channel conversations it
greets (conversations carrying
extra.companionId) mount that companion's bound knowledge bases — searchable during the conversation. Regular conversations without a companionId keep their conversation-level bindings; the two are not merged. - What the agent sees: bases are mounted at
{workspace}/.nomi/knowledge/, and the injected context carries, per base, the description + an AI digest + "when to consult" hints + a budgeted table of contents (20 entries per base / 60 global, directories aggregated beyond that), plus an explicit retrieval protocol — the agent is told to look things up rather than answer from memory. - Write-back comes in two modes, briefly:
- staged — knowledge produced during a conversation first lands
in the base's
_inbox/(isolated per conversation) for you to review on the knowledge page before it is committed; - direct — skips staging and writes straight into the base.
- staged — knowledge produced during a conversation first lands
in the base's
- AI bootstrap: the AI generate button on the knowledge page
(list edit modal and detail page) calls
POST /api/knowledge/bases/{id}/autogento produce the base's description andREADME.md; a.zipimport auto-fills an empty description. Requires a configured AI provider (409otherwise). - URL sources: a base can be created from up to 16 URLs.
snapshot mode fetches them at creation, converts each page to
markdown under the base's
snapshots/(pages over 32 KB are AI-compressed) and auto-generates the digest — refreshable from the detail page; live mode lets the agent fetch at runtime (engines without a web tool can call the gateway toolnomi_knowledge_fetch_url). Only publichttp/httpsURLs are accepted (SSRF guard). - The companion can also grow its own libraries: the Desktop Gateway
ships seven knowledge tools (list / bindings / create / write /
autogen / fetch-url), and knowledge-deposit tips are built into the
companion's system prompt — a companion or channel chat can create a base
and distill notes into it unprompted. When
nomi_knowledge_create_baseis called withurls, the fetching runs as a background job — the tool returns immediately, so the agent must not create the base again just because the snapshots haven't appeared yet; once the base's description shows up, the fetch + digest pipeline has finished.
Bind different bases to different companions and you get a "finance companion", a "literature companion", a "coding companion" — persona, model, and knowledge are all per-companion, while memory stays shared.
Binding a companion to a channel
Each IM platform (Telegram / Lark / DingTalk / WeChat) can bind its own
greeter companion for remote messages: open the companion's Remote
tab (/nomi?companion=<id>&tab=remote) and connect or rebind the bot
there. The binding is still persisted as assistant.{platform}.companionId
for legacy platform-level preferences when a channel row has no direct
companion binding. With no binding the default companion takes over;
switching the binding resets that channel's active sessions (the next
message is greeted by the new companion); if a bound companion is deleted,
the platform falls back to the default companion and the sessions are
likewise reset. See the "Master Agent mode" section of the
Channels guide.
A companionId grants no permissions (memory is shared anyway): it only selects persona / model / knowledge mounts — unlike the
desktopGatewaymarker, which grants gateway tools.
Export / import: migrating between machines
The shared-domain Migrate tab offers three kinds of .zip bundles
(the migration UI is desktop-only; paths are picked with the system
dialog):
| Bundle | Contents | Import semantics |
|---|---|---|
| Memory bundle | All long-term memories + learning history + mood; optionally the raw event data (checkbox) | Merged with dedup into local memories (original timestamps and sources preserved) |
| Companion bundle | One companion's persona / character / settings / XP + the name list of its bound knowledge bases (knowledge_refs) |
Creates a new companion under a fresh id, name conflicts get a "(2)" suffix; knowledge refs are matched by name against local bases to rebuild bindings — unmatched names are listed so you can import those knowledge bundles first and bind manually |
| Knowledge-base bundle | Base metadata + the md file tree verbatim | Lands as a new knowledge base, name conflicts get "(2)" |
Migration steps:
- Old machine: export the memory bundle (tick events only if you want them) → export a companion bundle per companion → export a knowledge-base bundle per base.
- New machine: import the knowledge-base bundles first (so companion bundles can rebuild bindings by name) → then the companion bundles → then the memory bundle.
- Check each companion's model setting: model config travels verbatim in the bundle, but if the new machine has no matching provider it shows as unconfigured — re-select in settings.
Privacy boundaries
events/*.jsonlis raw collected data containing your working content verbatim — it is not exported by default; it only enters the memory bundle when you explicitly tick "include raw event data".- Chat history does not travel with the companion bundle: companion conversation logs live in the main database; the companion bundle carries only persona and settings. Chat logs stay on the original machine.
Automatic migration of legacy data
After upgrading from the single-companion version, the first boot detects the
legacy layout {data_dir}/companion/nomi/: if it exists and companion/shared/
does not, it is automatically migrated into the shared memory hub plus
a first companion (default name "Nomi", inheriting the existing XP /
persona / character / model / desktop-companion position / companion
threads). The migration is idempotent and re-entrant; on completion a
.migrated marker is written into the legacy directory, which is kept
around (to be cleaned up after one release cycle). No manual action is
needed.
Manual walkthrough checklist
To verify a multi-companion setup end to end, walk through in order:
- Create two companions: create companions A and B, rename them, change characters; confirm the first one carries the "default" badge.
- Bind one base each: bind knowledge base X to A and Y to B (companion Model & Knowledge tab → Knowledge).
- Retrieval isolation: in A's and B's chats, ask about content that only exists in X / Y respectively; confirm A only hits X and B only hits Y.
- Shared memory round-trip: in A's chat, have it remember something (save a memory); switch to B's chat and ask — confirm B knows it.
- Export/import roundtrip: export the memory bundle + A's companion bundle + base X's bundle; (on a new machine or after a wipe) import in the order knowledge base → companion → memory; confirm the rebuilt A has its binding restored automatically and memories merge without duplicates.
- Channel companion switch: on some channel platform, switch the greeter companion from A to B; confirm the active sessions are reset and the next remote message is greeted with B's persona and B's knowledge mounts.
Routes & API
| What | Where |
|---|---|
| List / create companions | GET/POST /api/companion/companions |
| Companion detail / update / delete | GET/PATCH/DELETE /api/companion/companions/{companionId} |
| Shared config (collect / learn / default companion) | GET/PATCH /api/companion/config |
| Per-companion companion threads | GET /api/companion/companions/{companionId}/companion/threads, …/companion/active |
| Export memory bundle | POST /api/companion/export/memory ({dest_path, include_events}) |
| Export companion bundle | POST /api/companion/export/companions/{companionId} |
| Import memory / companion bundle | POST /api/companion/import (dispatched by manifest.kind) |
| Export / import knowledge-base bundle | POST /api/knowledge/bases/{id}/export, POST /api/knowledge/bases/import |
| Bind a companion to a channel | POST /api/channel/settings/companion |
Related
- Channels — channel Master Agent mode and per-platform companion binding.
- Data and Storage — the
companion/data directory layout.