Component Development · Part 1 of 3 — How it works

Component System

A component is a Python class extending BaseCell. Drop it into components/ and within 3 seconds it is scanned, loaded and wrapped as a tool the LLM can call directly — no registration, no config edits, no restart.

From file to tool

Each layer has its own job. A failure at any step is recorded as a load error and visible via component.info().

components/foo.py
  │ discover_components()     scan the dir, extract BaseCell subclasses via AST
  │ _instantiate_component()  dynamic import + instantiate + on_load()
  │ register_cell()           write into the in-memory registry _cell_registry
  │ register_to_config()      append to settings.yaml enabled_components
  │ CellToolAdapter           wrap as BaseTool (with JSON Schema)
  │ ComponentToolRegistry     thread-safe registry, version++
  ↓
AgentLoop calls get_all_tools() every turn → the LLM sees foo
  ↓
execute_with_context() → _cmd_xxx() → Dict returned

Three registries

The same component shows up in three places, each with a different purpose.

LayerLocationRole
In-memory registry_cell_registryLive component instances; hot reload mutates this directly
Config manifestsettings.yamlPersisted enabled list, maintained by the system — manual edits get overwritten
Tool registryComponentToolRegistryThread-safe tool view with a version counter; AgentLoop re-reads it every turn

Core features

FeatureDescription
Auto discoveryScans the directory and extracts BaseCell subclasses via AST — no decorators, no registration code
Hot-plugComponentWatcher compares file mtimes every 3s; add / modify / delete triggers an incremental reload
Tool wrappingCellToolAdapter turns the component into a BaseTool with a generated function-calling definition
Sandbox isolationRuns in a subprocess by default so a crash or infinite loop cannot take down the main process; 120s timeout
No-sandbox whitelistTrusted components can run in-process; changes trigger an immediate hot reload
Reserved namesshell / memory / file are system tools and cannot be shadowed by a component

How the tool definition is built

Nothing is hand-written — it is all derived from your code. This is the one place where component style matters.

  • The signature defines parameter names, types and required fields (no default = required)
  • The docstring Args: section supplies descriptions; missing entries fall back to the parameter name
  • Annotations int/float/bool/list/dict map to integer/number/boolean/array/object
  • A class docstring over 400 chars is truncated and auto-appended with the command list and a help hint
# Single command: params are flat, no command field
def _cmd_ping(self) -> Dict: ...

# Multiple commands: command becomes an enum and all other params merge into one level,
# so do not reuse a param name with a different type across commands
def _cmd_get(self, key: str) -> Dict: ...
def _cmd_set(self, key: str, value: str) -> Dict: ...

Command inference fallback

The LLM occasionally forgets the command field. The adapter scores every subcommand by parameter overlap (required params weigh more) and runs the best match; an explicit command is always honoured.

Reserved tool names

These three belong to built-in tools. A component registering the same name is rejected — keep cell_name clear of them.

  • shell — ShellTool
  • memory — MemoryTool
  • file — FileTool

Sandbox and whitelist

Every non-whitelisted component runs in a subprocess. The process is reused across calls but recycled when idle.

ParameterValue
Per-command timeout120 s
Idle process recycle300 s
Heartbeat interval30 s
Custom whitelist fileconfig/sandbox.yaml

Built-in no-sandbox components (hard-coded, cannot be removed): component, scheduler, skill_manager, skill_installer, sub_agent, web_fetch, web_search, qq_files, telegram_files, feishu_files, weixin_files.

Whitelist operations (list, add, remove) are covered in Part 2; this part only explains the model.

Built-in components

Shipped with the release. The source lives in components/ — read it and edit it directly.

ComponentFunction
componentGenerate, list, reload components; sandbox whitelist; cache cleanup
schedulerScheduled tasks: interval / daily / weekly
skill_manager / skill_installerSkill package index, install and uninstall
sub_agentParallel sub-agent orchestration with independent tools and persona
web_fetch / web_searchHeadless browser fetch and multi-engine search
qq_files / telegram_files / feishu_files / weixin_filesFile transfer over each IM channel

Troubleshooting

SymptomFix
Component missing from the tool listCheck component.info(name) for the load error — usually an import failure or not inheriting BaseCell
Code changes have no effectTop-level .py edits reload automatically; package-internal edits are not watched — call component.reload()