# My Tool Let the agent sense and adjust its own runtime state — like asking a coworker "are you busy? can you switch to a bigger monitor?" ## Why You Need It Normal tools let the agent operate on the outside world (read/write files, search code). But the agent knows nothing about itself — it doesn't know which model it's running on, how many iterations are left, or how many tokens it has consumed. My tool fills this gap. With it, the agent can: - **Know who it is**: What model am I using? Where is my workspace? How many iterations remain? - **Adapt on the fly**: Complex task? Expand the context window. Simple chat? Switch to a faster model. - **Remember across turns**: Store notes in your scratchpad that persist into the next conversation turn. > [!NOTE] > This tool uses **snake_case** keys (`model_preset`, `context_window_tokens`). > The matching config fields in `config.json` are **camelCase** (`modelPreset`, `contextWindowTokens`). > See [`configuration.md`](./configuration.md#model-presets) for how to define presets in your config. ## Configuration Enabled by default (read-only mode). The agent can check its state but not set it. ```yaml tools: my: enable: true # default: true allow_set: false # default: false (read-only) ``` To allow the agent to set its configuration (e.g. switch models, adjust parameters), set `tools.my.allow_set: true`. Legacy `tools.myEnabled` / `tools.mySet` keys are auto-migrated on load, and rewritten in-place the next time `nanobot onboard` refreshes the config. All modifications are held in memory only — restart restores defaults. --- ## check — Check "my" current state Without parameters, returns a key config overview: ```text my(action="check") # → max_iterations: 40 # model_preset: 'fast' # workspace: PosixPath('/tmp/workspace') # provider_retry_mode: 'standard' # max_tool_result_chars: 16000 # _current_iteration: 3 # _last_usage: {'prompt_tokens': 45000, 'completion_tokens': 8000} # Note: prompt_tokens is cumulative across all turns, not current context window occupancy. ``` With a key parameter, drill into a specific config: ```text my(action="check", key="_last_usage.prompt_tokens") # → How many prompt tokens I've used so far my(action="check", key="model_preset") # → Current active preset name (e.g. 'fast') my(action="check", key="model_presets") # → Lists all preset names and their models, e.g.: # fast → gpt-4.1-mini (openai) # deep → claude-opus-4-7 (anthropic) my(action="check", key="web_config.enable") # → Whether web search is enabled ``` ### What you can do with it | Scenario | How | |----------|-----| | "What model are you using?" | `check("model_preset")` | | "How many more tool calls can you make?" | `check("max_iterations")` minus `check("_current_iteration")` | | "How many tokens has this conversation used?" | `check("_last_usage")` — cumulative across all turns | | "Where is your working directory?" | `check("workspace")` | | "Show me your full config" | `check()` | | "Are there any subagents running?" | `check("subagents")` — shows phase, iteration, elapsed time, tool events | --- ## set — Runtime tuning Changes take effect immediately, no restart required. ```text my(action="set", key="max_iterations", value=80) # → Bump iteration limit from 40 to 80 my(action="set", key="model_preset", value="fast") # → Switch to the 'fast' preset (model, provider, temperature, etc. all at once) # # If the preset name does not exist: # → Error: model_preset 'unknown' not found. Available: fast, deep my(action="set", key="context_window_tokens", value=131072) # → Expand context window for long documents ``` You can also store custom state in your scratchpad: ```text my(action="set", key="current_project", value="nanobot") my(action="set", key="user_style_preference", value="concise") my(action="set", key="task_complexity", value="high") # → These values persist into the next conversation turn ``` ### Protected parameters These parameters have validation — invalid values are rejected: | Parameter | Type | Range / Constraint | Purpose | |-----------|------|-------------------|---------| | `max_iterations` | int | 1–100 | Max tool calls per conversation turn | | `model_preset` | str | must exist in `model_presets` | Switch to a named preset bundle | Other parameters (e.g. `model`, `context_window_tokens`, `workspace`, `provider_retry_mode`, `max_tool_result_chars`) can be set freely, as long as the value is JSON-safe. > [!NOTE] > Setting `model` or `context_window_tokens` directly automatically clears the active `model_preset`, because the live state no longer matches the preset bundle. Use `model_preset` for atomic switches instead. --- ## Practical Scenarios ### "This task is complex, I need more room" ```text Agent: This codebase is large, let me expand my context window to handle it. → my(action="set", key="context_window_tokens", value=131072) ``` ### "Simple question, don't waste compute" ```text Agent: This is a straightforward question, let me switch to the fast preset. → my(action="set", key="model_preset", value="fast") ``` ### "Remember user preferences across turns" ```text Turn 1: my(action="set", key="user_prefers_concise", value=True) Turn 2: my(action="check", key="user_prefers_concise") # → True (still remembers the user likes concise replies) ``` ### "Self-diagnosis" ```text User: "Why aren't you searching the web?" Agent: Let me check my web config. → my(action="check", key="web_config.enable") # → False Agent: Web search is disabled — please set web.enable: true in your config. ``` ### "Token budget management" ```text Agent: Let me check how much budget I have left. → my(action="check", key="_last_usage") # → {"prompt_tokens": 45000, "completion_tokens": 8000} Agent: I've used ~53k tokens total so far. I'll keep my remaining replies concise. ``` ### "Subagent monitoring" ```text Agent: Let me check on the background tasks. → my(action="check", key="subagents") # → 2 subagent(s): # [task-1] 'Code review' # phase: running, iteration: 5, elapsed: 12.3s # tools: read(✓), grep(✓) # usage: {'prompt_tokens': 8000, 'completion_tokens': 1200} # [task-2] 'Write tests' # phase: pending, iteration: 0, elapsed: 0.2s # tools: none Agent: The code review is progressing well. The test task hasn't started yet. ``` --- ## Safety Mechanisms Core design principle: **All modifications live in memory only. Restart restores defaults.** The agent cannot cause persistent damage. ### Off-limits (BLOCKED) Cannot be checked or modified — fully hidden: | Category | Attributes | Reason | |----------|-----------|--------| | Core infrastructure | `bus`, `provider`, `_running` | Changes would crash the system | | Tool registry | `tools` | Must not remove its own tools | | Subsystems | `runner`, `sessions`, `consolidator`, etc. | Affects other users/sessions | | Sensitive data | `_mcp_servers`, `_pending_queues`, etc. | Contains credentials and message routing | | Security boundaries | `restrict_to_workspace`, `channels_config` | Bypassing would violate isolation | | Python internals | `__class__`, `__dict__`, etc. | Prevents sandbox escape | ### Read-only (check only) Can be checked but not set: | Category | Attributes | Reason | |----------|-----------|--------| | Subagent manager | `subagents` | Observable, but replacing breaks the system | | Execution config | `exec_config` | Can check sandbox/enable status, cannot change it | | Web config | `web_config` | Can check enable status, cannot change it | | Iteration counter | `_current_iteration` | Updated by runner only | ### Sensitive field protection Sub-fields matching sensitive names (`api_key`, `password`, `secret`, `token`, etc.) are blocked from both check and set, regardless of parent path. This prevents credential leaks via dot-path traversal (e.g. `web_config.search.api_key`).