Skip to content

10 · Engineering Practices & Appendix ​

Tenth installment of the architecture deep-dive: complete environment variable reference, GPU tiers, VRAM gating, code organization quick reference, build & run, and external agent adaptation. Corresponds to ARCHITECTURE.md §12–§15.


§12 External Agent Adaptation ​

  • Supports integrating user-run external agents (hosts of custom skills / custom pipelines)
  • External agents participate in the same graph via bridge REST + tool gateway
  • IDENTITY.md template is generated by _external_identity_md()
python
# src/models/assistant.py
def _external_identity_md(*, kind: str, display_name: str,
                          cli_path: str, workspace_dir: str,
                          base_url: str, model: str) -> str:
    """Minimal IDENTITY.md for externally-backed agent."""
    return (
        f"# {display_name}\n\n"
        f"This agent is a **proxy** for an external AI runtime...\n"
    )

§13 Complete Environment Variable Reference ​

13.1 LLM Configuration (LLMConfig) ​

VariableRequiredDefaultDescription
BASE_URL✅—OpenAI-compatible API base URL
API_KEY✅—API key
DEFAULT_MODEL✅—Default chat model
MANAGER_MODEL—"gpt-4o"Manager executive summary model
MINI_MODEL—"Qwen2.5-1.5B"Lightweight local model
FAST_MODEL—""Low-latency fast model (empty = fall back to DEFAULT_MODEL)
BETA—0.3Cost weight in model routing formula

13.2 Infrastructure (InfrastructureConfig) ​

VariableRequiredDefaultDescription
TIMEOUT—300HTTP timeout (seconds)
MAX_TURNS—50Maximum tool-call loop iterations
DIALOGUE_EXPIRE_TIME—3600Dialogue expiration time (seconds)
SLIDE_WINDOW_SIZE—5Dialogue history sliding window size
WORKSPACE_ROUTE—""Root working directory (empty = cwd)
TOP_K—5RAG recall top-K

13.3 Embedding Configuration (EmbeddingConfig) ​

VariableRequiredDefaultDescription
EMBEDDING_MODEL—"BAAI/bge-m3"Sentence-transformers model
BASE_ROUTE—""Root directory for local model/router files

13.4 Circuit Breaker Configuration (CircuitBreakerConfig) ​

VariableRequiredDefaultDescription
CB_FAILURE_THRESHOLD—5Number of failures before circuit opens
CB_RECOVERY_SECONDS—30.0Recovery time before half-open probe (seconds)
LLM_MAX_RETRIES—3Maximum retries per LLM call
LLM_RETRY_BASE_DELAY—1.0Initial backoff delay (seconds)
LLM_RETRY_MAX_DELAY—30.0Maximum backoff delay (seconds)
LLM_MAX_CONCURRENT_PER_URL—8Maximum concurrent LLM calls per URL (AIMD upper bound)
LLM_MIN_CONCURRENT_PER_URL—1AIMD shrink lower bound
LLM_QUEUE_WAIT_S—120Maximum seconds to wait for gate permission
LLM_AIMD_GROW_AFTER—20Number of consecutive successes before AIMD target +1
LLM_AIMD_SHRINK_FACTOR—0.5AIMD target multiplier on timeout
LLM_GATE_DISABLED—FalseCompletely disable the concurrency gate

13.5 GPU / VRAM Configuration ​

VariableRequiredDefaultDescription
FAMILIARS_TIER4_MAX_MB—5000tier4 VRAM upper bound (MiB)
FAMILIARS_TIER6_MAX_MB—7500tier6 VRAM upper bound (MiB)
FAMILIARS_GPU_TIER—autoOverride auto-detection (mode0/tier4/tier6/tier8)
FAMILIARS_GPU_TIER_FORCE_REDETECT—0Force re-detection of GPU tier

13.6 Security Configuration ​

VariableRequiredDefaultDescription
FAMILIARS_APPROVAL_DISABLED—01 = completely skip the approval gate

13.7 Bridge Configuration ​

VariableRequiredDefaultDescription
FAMILIARS_HTTP_INSECURE—01 = fall back to uvicorn + HTTP
FAMILIARS_DAEMON—01 = daemon mode (pidfile + log redirection)
FAMILIARS_DB_PATH—workspace/familiars.dbSQLite database path (:memory: for tests)
FAMILIARS_STREAM_LLM—autotrue/false to override streaming decisions
BRIDGE_PORT—18711Bridge listening port

13.8 External Service Configuration ​

VariableRequiredDefaultDescription
HUGGING_FACE_API_KEY—""Hugging Face API key
GPT_SOVITS_DIR—external/GPT-SoVITSGPT-SoVITS bundle path
THA3_DIR—external/talking-head-anime-3-demoTHA3 checkout path
DATAGEN_BASE_URL—""Data generation API base URL
DATAGEN_API_KEY—""Data generation API key

§14 GPU Tiers (src/base/gpu_tier.py) ​

14.1 Tier Matrix ​

python
Tier = Literal["mode0", "tier4", "tier6", "tier8"]

# Thresholds (MiB, as reported by nvidia-smi)
_TIER4_MAX_MB = float(os.getenv("FAMILIARS_TIER4_MAX_MB", "5000"))
_TIER6_MAX_MB = float(os.getenv("FAMILIARS_TIER6_MAX_MB", "7500"))
TierVRAM RangeFeature Set
mode0No GPUAPI-only (no local models)
tier4≤5000 MiB4-bit + sequential loading; decider/memorizer queue-triggered
tier6≤7500 MiBrewriter+embedder+reranker co-resident; audio calls allowed
tier8>7500 MiBFull feature set

14.2 Detection Flow ​

python
def _probe_total_vram_mb() -> Optional[float]:
    """nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits
    
    Apple Silicon / macOS has no nvidia-smi → mode0 (unless FAMILIARS_GPU_TIER overrides).
    Result is cached to workspace/gpu_tier.json.
    """

14.3 Transient Downgrade ​

python
# _transient_tier: Optional[Tier] = None
# User selects "downgrade tier" in the frontend → sets _transient_tier
# Does not write to gpu_tier.json → next startup restores auto-detection

§15 VRAM Gating (src/base/vram_gate.py) ​

15.1 Priority Taxonomy ​

python
# Priority taxonomy (lower = more important):
#   1 — CRITICAL   Active user requests (TTS speaking, operate() in flight, LLM generating)
#   2 — IMPORTANT  Steady-state user interaction (selected agent's decider, bge embedding, reranker)
#   3 — NICE       Useful but can wait (memorizer writer, mini-model, EasyOCR, emotion tagger)
#   4 — BACKGROUND Indexing/training (never user-visible)

15.2 Entry Structure ​

python
@dataclass
class _Entry:
    model_id: str
    priority: int
    estimated_mb: float
    on_evict: Optional[Callable[[], None]] = None
    is_subprocess: bool = False
    category: Literal["sync", "queue"] = "sync"
    is_working: bool = False
    on_checkpoint: Optional[Callable[[], Any]] = None
    admitted_at: float = field(default_factory=time.monotonic)
    last_active_at: float = field(default_factory=time.monotonic)
    idle_ttl_sec: Optional[float] = None

15.3 Category Semantics ​

CategoryDescriptionEviction Rule
syncUser-blocking. UI actions load synchronouslyCan evict idle residents or queue residents
queueInterruptible background workRuns on_checkpoint() snapshot on eviction

15.4 Never-Dropped Guarantee ​

  • acquired() blocks on Condition.wait()
  • Any release / update_priority calls notify_all()
  • Caller exception → entry released, slot not held indefinitely
  • The only non-admission path: explicit timeout parameter → TimeoutError

15.5 Thread Priority Boost ​

python
@contextmanager
def boost_thread_priority(priority: int) -> Iterator[None]:
    """Temporarily boost priority for user-blocking threads.
    
    Nested calls take the min → inner CRITICAL + outer NICE = inner CRITICAL.
    Prevents inner boosts from accidentally weakening outer guarantees.
    """

Usage:

python
from src.base.vram_gate import boost_thread_priority, PRIORITY_CRITICAL

with boost_thread_priority(PRIORITY_CRITICAL):
    do_user_facing_work()   # All gate.acquired() calls inside are CRITICAL

§16 Code Organization Quick Reference ​

16.1 Core Jump Table ​

FileResponsibility
src/bridge/app.pyFastAPI mounting, CUDA pin, JIT model load, autorun, monitor rehydrate
src/bridge/deps.pyDI providers (AssistantManager/DialogueManager/CommHub/UsageTracker)
src/bridge/run.pyBridge startup entry (hypercorn + HTTPS/2)
src/models/assistant.pyAssistant + AssistantManager (lifecycle/reports/persona evolution)
src/models/conversation.pyConversationSession + DialogueManager + RAG composition
src/models/transferer.pyCross-agent / cross-client / cross-model dispatch (6 priority levels)
src/models/clients/base_client.pyToolClient base — tool loop, history pruning, schema normalization
src/tools/tool_dispatcher.pyTool name → callable table (15 default tool instances)
src/tools/security.pyRisk levels / approval gate / dynamic score escalation
src/tools/sensitive_detector.pyThree-layer sensitive info detection (gitleaks + presidio + mini-LLM)
src/base/crypto.pyCrypto primitives (HKDF b"familiars-secrets-v1")
src/utils/browser_tools.pyChrome CDP automation (single shared instance)
src/utils/memory_tools.pyNode, DialogTree, Memorizer
src/utils/memory_store.pyMemory storage layer (scope × category matrix)
src/utils/daily_tools.pySchedule/todo/reminder/report tools
src/utils/reminder_dispatch.pyReminder dispatch (inbox.jsonl + native notifications)
src/base/vram_gate.pySingle VRAM admission gate (4 priority levels / sync+queue categories)
src/base/gpu_tier.pyGPU tier detection (mode0/tier4/tier6/tier8)
src/base/config.pypydantic-settings Settings aggregate + validate_config()
src/storage/db.pySQLite WAL + migration runner (v1…v50)
src/broker/hub.pyBroker layer root (identity/transport/matching/rate-limiting/ledger)
src/flow/engine.pyFlowEngine concurrent execution
src/flow/resume.pyResume from breakpoints (mutation log + hash verification)
src/digital_human/session.pyDigitalHumanSession (three-task async pipeline)
src/digital_human/config.pyDigitalHumanConfig
electron/electron/main.jsElectron main process
electron/electron/python.jsBridge lifecycle (port probe/health check/subprocess management)

16.2 Tool Class Jump Table ​

Tool ClassSource FileExample Methods
BaseToolssrc/utils/base_tools.pyread, write, execute_shell_script, find, grep, download
BaseTools.InputControllerEmbedded in BaseToolskeyboard_type, keyboard_write
BrowserToolssrc/utils/browser_tools.pybrowser_open, browser_click, browser_type, explore_page
MultimodalToolssrc/utils/multimodal_tools.pyvision_describe, operate, screenshot
DailyToolssrc/utils/daily_tools.pycreate_schedule, create_todo, create_reminder
DailyMonitorToolssrc/utils/daily_monitor/Daily context collection
DocToolssrc/utils/doc/tools.pyread_docx, write_docx, generate_ppt, generate_excel
MemoryToolssrc/utils/memory_tools.pyread_memory, write_memory, rag_query
SystemToolssrc/utils/system_tools.pyget_system_info, network_info
UserToolssrc/utils/user_tools.pyget_user_profile, update_user_profile
UserSecretToolssrc/utils/user_secret_tools.pyget_user_secret, store_user_secret
PhoneToolssrc/utils/phone_tools.pyPhone-related operations
SkillToolssrc/tools/skill_tools.pyexecute_skill
SkillWatcherToolssrc/utils/skill_watcher_tools.pySkill change monitoring
BrokerToolssrc/utils/broker_tools.pyBroker operations

§17 Build & Run ​

17.1 Development Environment ​

bash
# Python environment
python -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate
pip install -r requirements.txt

# Configuration
cp .env.example .env            # Edit .env to fill in API configuration

# Start Bridge
python -m src.bridge.run        # HTTPS/2 on 127.0.0.1:18711

# Start Electron (development mode)
cd electron && npm run electron:dev

17.2 CLI ​

bash
# CLI drives the running bridge (X-Bridge-Token auto-read from workspace/.bridge_token)
python main.py --help                    # 39 command groups, 200+ subcommands
python main.py agents list --pretty
python main.py chat stream --prompt "hi" --agent-id 1
python main.py todos create --title "buy milk" --deadline 2026-07-05T18:00

Full reference: CLI Command Reference.

17.3 Production Build ​

bash
cd electron && npm run electron:build

17.4 Testing ​

bash
# All tests must use a real SQLite
FAMILIARS_DB_PATH=:memory: pytest

# Specific modules
pytest test/recipes/       # Recipe tests (300+)
pytest test/bridge/        # Bridge tests
pytest test/models/        # Model tests

17.5 Production Relay ​

deploy/relay/app/          # Docker + Caddy, Cloudflare DNS-01

§18 Key Design Constraints ​

18.1 CUDA First-Touch Thread ​

Windows WDDM does not allow a worker thread to first-touch CUDA.
src/bridge/app.py executes torch.cuda.init() + torch.zeros(1, device="cuda") at import time.
Violation → process crashes with 0xC0000005 (access violation).

18.2 Path Alignment Timing ​

align_all_paths() must run before DialogueManager._load_existing_dialogues.
Otherwise stale paths are read into context → LLM loops ls-ing ghost paths.

18.3 Port Stability ​

18711 is the default port, not a fixed port.
The port file workspace/.bridge.port is the actual signal.
The CLI reads the port file; Electron writes it after probing.
The autorun watchdog always uses 18711; Electron calls pickFreePort() when a conflict is found.

18.4 Single Embedder Instance ​

No DialogTree caches model instances (properties route to the singleton getter).
Allows unload_embedding_model to release ~700MB of VRAM.
Old version: N dialogues = N refs → after eviction CUDA tensors still referenced → TTS admission fails.

18.5 consult_doc Is Still Active ​

_CONSULT_TARGETS in src/models/clients/base_client.py still routes consult_doc → doc_tools.
Historical claims that "consult_doc was removed" are wrong → the mapping is still live and used by planners.

§19 Appendix: Migration List ​

See the complete migration list in 05-Persistence Layer §6.4.2.

Current version: v46 (v46__guild_task_tags.sql).


End of the ten-part architecture deep-dive. Continue: Developer Guide or Ecosystem Development Tutorials.

Familiars · 多 Agent AI 桌面应用