返回 JoyAI-Echo
my-tool.md
1 # My Tool
2
3 Let the agent sense and adjust its own runtime state — like asking a coworker "are you busy? can you switch to a bigger monitor?"
4
5 ## Why You Need It
6
7 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.
8
9 My tool fills this gap. With it, the agent can:
10
11 - **Know who it is**: What model am I using? Where is my workspace? How many iterations remain?
12 - **Adapt on the fly**: Complex task? Expand the context window. Simple chat? Switch to a faster model.
13 - **Remember across turns**: Store notes in your scratchpad that persist into the next conversation turn.
14
15 ## Configuration
16
17 Enabled by default (read-only mode). The agent can check its state but not set it.
18
19 ```yaml
20 tools:
21 my:
22 enable: true # default: true
23 allow_set: false # default: false (read-only)
24 ```
25
26 To allow the agent to set its configuration (e.g. switch models, adjust parameters), set `tools.my.allow_set: true`.
27
28 Legacy `tools.myEnabled` / `tools.mySet` keys are auto-migrated on load, and
29 rewritten in-place the next time `nanobot onboard` refreshes the config.
30
31 All modifications are held in memory only — restart restores defaults.
32
33 ---
34
35 ## check — Check "my" current state
36
37 Without parameters, returns a key config overview:
38
39 ```text
40 my(action="check")
41 # → max_iterations: 40
42 # context_window_tokens: 65536
43 # model: 'anthropic/claude-sonnet-4-20250514'
44 # workspace: PosixPath('/tmp/workspace')
45 # provider_retry_mode: 'standard'
46 # max_tool_result_chars: 16000
47 # _current_iteration: 3
48 # _last_usage: {'prompt_tokens': 45000, 'completion_tokens': 8000}
49 # Note: prompt_tokens is cumulative across all turns, not current context window occupancy.
50 ```
51
52 With a key parameter, drill into a specific config:
53
54 ```text
55 my(action="check", key="_last_usage.prompt_tokens")
56 # → How many prompt tokens I've used so far
57
58 my(action="check", key="model")
59 # → What model I'm currently running on
60
61 my(action="check", key="web_config.enable")
62 # → Whether web search is enabled
63 ```
64
65 ### What you can do with it
66
67 | Scenario | How |
68 |----------|-----|
69 | "What model are you using?" | `check("model")` |
70 | "How many more tool calls can you make?" | `check("max_iterations")` minus `check("_current_iteration")` |
71 | "How many tokens has this conversation used?" | `check("_last_usage")` — cumulative across all turns |
72 | "Where is your working directory?" | `check("workspace")` |
73 | "Show me your full config" | `check()` |
74 | "Are there any subagents running?" | `check("subagents")` — shows phase, iteration, elapsed time, tool events |
75
76 ---
77
78 ## set — Runtime tuning
79
80 Changes take effect immediately, no restart required.
81
82 ```text
83 my(action="set", key="max_iterations", value=80)
84 # → Bump iteration limit from 40 to 80
85
86 my(action="set", key="model", value="fast-model")
87 # → Switch to a faster model
88
89 my(action="set", key="context_window_tokens", value=131072)
90 # → Expand context window for long documents
91 ```
92
93 You can also store custom state in your scratchpad:
94
95 ```text
96 my(action="set", key="current_project", value="nanobot")
97 my(action="set", key="user_style_preference", value="concise")
98 my(action="set", key="task_complexity", value="high")
99 # → These values persist into the next conversation turn
100 ```
101
102 ### Protected parameters
103
104 These parameters have type and range validation — invalid values are rejected:
105
106 | Parameter | Type | Range | Purpose |
107 |-----------|------|-------|---------|
108 | `max_iterations` | int | 1–100 | Max tool calls per conversation turn |
109 | `context_window_tokens` | int | 4,096–1,000,000 | Context window size |
110 | `model` | str | non-empty | LLM model to use |
111
112 Other parameters (e.g. `workspace`, `provider_retry_mode`, `max_tool_result_chars`) can be set freely, as long as the value is JSON-safe.
113
114 ---
115
116 ## Practical Scenarios
117
118 ### "This task is complex, I need more room"
119
120 ```text
121 Agent: This codebase is large, let me expand my context window to handle it.
122 → my(action="set", key="context_window_tokens", value=131072)
123 ```
124
125 ### "Simple question, don't waste compute"
126
127 ```text
128 Agent: This is a straightforward question, let me switch to a faster model.
129 → my(action="set", key="model", value="fast-model")
130 ```
131
132 ### "Remember user preferences across turns"
133
134 ```text
135 Turn 1: my(action="set", key="user_prefers_concise", value=True)
136 Turn 2: my(action="check", key="user_prefers_concise")
137 # → True (still remembers the user likes concise replies)
138 ```
139
140 ### "Self-diagnosis"
141
142 ```text
143 User: "Why aren't you searching the web?"
144 Agent: Let me check my web config.
145 → my(action="check", key="web_config.enable")
146 # → False
147 Agent: Web search is disabled — please set web.enable: true in your config.
148 ```
149
150 ### "Token budget management"
151
152 ```text
153 Agent: Let me check how much budget I have left.
154 → my(action="check", key="_last_usage")
155 # → {"prompt_tokens": 45000, "completion_tokens": 8000}
156 Agent: I've used ~53k tokens total so far. I'll keep my remaining replies concise.
157 ```
158
159 ### "Subagent monitoring"
160
161 ```text
162 Agent: Let me check on the background tasks.
163 → my(action="check", key="subagents")
164 # → 2 subagent(s):
165 # [task-1] 'Code review'
166 # phase: running, iteration: 5, elapsed: 12.3s
167 # tools: read(✓), grep(✓)
168 # usage: {'prompt_tokens': 8000, 'completion_tokens': 1200}
169 # [task-2] 'Write tests'
170 # phase: pending, iteration: 0, elapsed: 0.2s
171 # tools: none
172 Agent: The code review is progressing well. The test task hasn't started yet.
173 ```
174
175 ---
176
177 ## Safety Mechanisms
178
179 Core design principle: **All modifications live in memory only. Restart restores defaults.** The agent cannot cause persistent damage.
180
181 ### Off-limits (BLOCKED)
182
183 Cannot be checked or modified — fully hidden:
184
185 | Category | Attributes | Reason |
186 |----------|-----------|--------|
187 | Core infrastructure | `bus`, `provider`, `_running` | Changes would crash the system |
188 | Tool registry | `tools` | Must not remove its own tools |
189 | Subsystems | `runner`, `sessions`, `consolidator`, etc. | Affects other users/sessions |
190 | Sensitive data | `_mcp_servers`, `_pending_queues`, etc. | Contains credentials and message routing |
191 | Security boundaries | `restrict_to_workspace`, `channels_config` | Bypassing would violate isolation |
192 | Python internals | `__class__`, `__dict__`, etc. | Prevents sandbox escape |
193
194 ### Read-only (check only)
195
196 Can be checked but not set:
197
198 | Category | Attributes | Reason |
199 |----------|-----------|--------|
200 | Subagent manager | `subagents` | Observable, but replacing breaks the system |
201 | Execution config | `exec_config` | Can check sandbox/enable status, cannot change it |
202 | Web config | `web_config` | Can check enable status, cannot change it |
203 | Iteration counter | `_current_iteration` | Updated by runner only |
204
205 ### Sensitive field protection
206
207 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`).
208
208 lines MARKDOWN