5.8 KiB
Self-Evolution
The self tool allows the agent to inspect, modify, and invoke its own runtime state — enabling adaptive behavior where the agent tunes itself to the task at hand.
This feature is disabled by default. It is intended for advanced users who understand the implications of letting an LLM modify its own runtime parameters.
Enabling
Add to your config.yaml:
tools:
self_evolution: true
All changes are in-memory only. Restarting the agent restores defaults.
What It Does
The agent gains a self tool with the following actions:
inspect — View Runtime State
Without a key, returns a summary of configurable parameters.
self(action="inspect")
# → max_iterations: 40
# context_window_tokens: 65536
# model: 'anthropic/claude-sonnet-4-20250514'
With a dot-path key, navigates into nested objects:
self(action="inspect", key="subagents._running_tasks")
# → subagents: 2 running — ['a1b2c3', 'd4e5f6']
self(action="inspect", key="web_config.enable")
# → web_config.enable: True
self(action="inspect", key="context.build_system_prompt")
# → method build_system_prompt() — use 'call' action to invoke
modify — Change Runtime Parameters
For attributes that already exist on the loop, the change takes immediate effect via setattr. For new keys, the value is stored in a free-form _runtime_vars dictionary.
self(action="modify", key="max_iterations", value=80)
# → Set max_iterations = 80 (was 40)
self(action="modify", key="provider_retry_mode", value="persistent")
# → Set provider_retry_mode = 'persistent' (was 'standard')
self(action="modify", key="my_custom_flag", value=True)
# → Set _runtime_vars.my_custom_flag = True
Restricted parameters (type and range validated):
| Parameter | Type | Range |
|---|---|---|
max_iterations |
int | 1–100 |
context_window_tokens |
int | 4,096–1,000,000 |
model |
str | min 1 character |
All other attributes are freely modifiable without type constraints.
call — Invoke Methods
Call any reachable method on the agent loop or its sub-objects. Supports both sync and async methods.
self(action="call", method="subagents.get_running_count")
# → 0
self(action="call", method="context.build_system_prompt")
# → <full system prompt text>
self(action="call", method="subagents.cancel_by_session",
args={"session_key": "weixin:user123"})
# → 2
list_tools — Show Registered Tools
self(action="list_tools")
# → Tools (12):
# read_file: Read a file from the workspace
# write_file: Write content to a file
# ...
manage_tool — Register/Unregister Tools
self(action="manage_tool", name="web_search", manage_action="unregister")
# → Unregistered tool 'web_search'
self(action="manage_tool", name="web_search", manage_action="register")
# → Re-registered tool 'web_search'
The self tool itself cannot be unregistered (lockout prevention).
snapshot / restore / list_snapshots — Config Templates
Save and restore named configuration snapshots:
self(action="snapshot", name="coding_mode")
# → Snapshot 'coding_mode' saved
self(action="modify", key="max_iterations", value=100)
self(action="modify", key="context_window_tokens", value=131072)
self(action="snapshot", name="high_capacity")
# → Snapshot 'high_capacity' saved
self(action="restore", name="coding_mode")
# → Restored snapshot 'coding_mode'
self(action="list_snapshots")
# → Snapshots (2): ['coding_mode', 'high_capacity']
Snapshots capture all restricted parameter values and _runtime_vars. They are stored in memory and lost on restart.
reset — Restore Defaults
self(action="reset", key="max_iterations")
# → Reset max_iterations = 40 (was 80)
self(action="reset", key="my_custom_flag")
# → Deleted _runtime_vars.my_custom_flag
Safety Model
What is blocked
Only attributes that would cause hard crashes or lockout:
bus— corrupts message routingprovider— corrupts all LLM calls_running— main loop control flag- Internal self-tool state (
_config_defaults,_runtime_vars,_config_snapshots, etc.) - Dunder attributes (
__class__,__dict__, etc.)
What is NOT blocked
Everything else — tools, subagents, sessions, context, consolidator, dream, runner, commands, web_config, exec_config, workspace, etc.
The design philosophy: since all changes are in-memory and lost on restart, the risk is low. The agent should be free to experiment.
Runtime safeguards
| Safeguard | Limit |
|---|---|
_runtime_vars key cap |
64 keys |
| Value size limit | 1,024 total elements (recursive) |
| Nesting depth limit | 10 levels |
| Callable values | Rejected |
| Non-JSON-safe types | Rejected |
| Watchdog | Validates restricted params each iteration, auto-resets invalid values |
Use Cases
Adaptive performance tuning
The agent can increase context_window_tokens or max_iterations mid-conversation when it detects a complex task, and restore defaults afterward.
Dynamic tool management
Disable tools that are noisy for a specific task (e.g., web_search during a coding session), then re-enable them later.
Configuration templates
Save optimal configurations for different task types and switch between them:
snapshot("coding") → high iterations, large context
snapshot("chat") → low iterations, small context
snapshot("research") → web tools enabled, medium context
Subagent monitoring
Observe running subagent tasks and cancel stale ones:
inspect("subagents._running_tasks")
call("subagents.cancel_by_session", args={"session_key": ...})
Debugging
Inspect the current system prompt, check token usage, or view session state from within the agent loop.