# 工具設計與規則

## 工具設計規則

新增或編輯工具的四條強制規則（build-time 契約來自 `reasoning_guide(topics=["tool_generate"])`，對外部 agent 則以 `tool_generate_guide` 曝露；後續品質由 `code-reviewer` skill 檢查，v1.0.17 起需以 `/skills` 安裝）：

1. **name 是首要的語意載體** — 此規則源自只有名稱的 stub 工具；自 v1.0.27 起所有工具在首輪即帶完整 schema，但模型瀏覽整份清單時最先看的仍是 name
2. **description 固定 3 行、60-200 字元** — What（核心動作）／When（觸發時機 vs 替代方案，例：`use for X; Y for Z`）／Precondition（關鍵限制，無則省略）。不放填充語、不用粗體、不放輸出 schema dump。
3. **僅限英文** — 中文只出現在面向使用者的 handler 回傳訊息
4. **選用欄位必須宣告 `default`** — handler 仍需防禦 nil/缺失

觸發條件與同類工具比較是 When 行的必要內容，不是禁止項——只寫核心動作而沒有觸發訊號的 description 視為不完整。Parameter description 須涵蓋 How／When／Example，非平凡型別（object/array/enum）若說明少於 20 字元視為不完整。

## 工具並行標記

`toolRegister.Def` 帶有六個行為旗標：

| 旗標 | 效果 |
|---|---|
| `AlwaysAllow` | 豁免 confirm gate（唯讀工具） |
| `AlwaysLoad` | 原意：第一輪即帶上 schema，而非只有名稱的 stub。共 15 個工具具備此旗標：`ask_user`、`calculate`、`chat_history`、`edit_file`、`fetch_page`、`find_files`、`find_tools`、`http_request`、`read_files`、`reasoning_guide`、`run_command`、`run_skill`、`search_web`、`write_result`、`write_todo`。自 v1.0.27 起所有工具都帶完整 schema 送出，此旗標已不影響 payload |
| `Concurrent` | 選擇加入 Pass 2 fan-out（每次呼叫一個 goroutine） |
| `Background` | 迴圈不等待其結果 |
| `SystemUse` | 內部管理用工具——不出現在一般列表，只有在對 `find_tools(mode=list)` 要求系統工具時才顯示 |
| `Timeout` | 覆寫預設上限（`DEFAULT_TOOL_TIMEOUT`，v1.1.2 起 15 分鐘，先前 1 分鐘）；`NoToolTimeout`（`ask_user` 自 v1.0.23 起使用）取消上限 |

加入 `Concurrent: true` 需同時滿足「無副作用」與「上游允許並行」。當前的並行工具集列於執行引擎頁。

## 工具 timeout 矩陣

`toolRegister.Dispatch` 會以工具註冊的 timeout（未覆寫時為 `DEFAULT_TOOL_TIMEOUT`——v1.1.2 起 15 分鐘，先前 1 分鐘）包住每一次呼叫——內建、script、API 與 MCP 皆然。各 adapter 在此上限內再套自己的限制：

| Adapter | Adapter 預設 | 可設定 | 實際上限 |
|---|---|---|---|
| Built-in | 15 分鐘 | 每個工具的 `Def.Timeout` | `Def.Timeout` |
| Script（`script_*`） | 15 分鐘（v1.1.2 前為 300 秒） | `~/.config/agenvoy/tools/script/<name>/` 的 `tool.json` `"timeout": <seconds>`——同時註冊為 dispatch timeout | `tool.json` 的值，未設定為 15 分鐘 |
| API（`api_*`） | 15 分鐘（v1.1.2 前為 60 秒） | `extensions/apis/<name>.json` 的 `doc.Endpoint.Timeout`——v1.1.2 起同時註冊為 dispatch timeout | `Endpoint.Timeout` 的值，未設定為 15 分鐘 |
| MCP HTTP | Transport `ResponseHeaderTimeout` 15 分鐘（v1.1.2 前為 60 秒） | 無 | 15 分鐘 dispatch 預設 |
| MCP stdio | 無 | 無 | 15 分鐘 dispatch 預設 |

長時間執行的工具（script + API）每 30 秒向 daemon log 發出 `running name=... elapsed=Ys/Zs` 以利可見性。

長時執行的內建工具於註冊時宣告各自上限：`run_command` = 30 分鐘（`RUN_COMMAND_TIMEOUT`；v1.1.2 前為 60 分鐘）、`subagents` = `MAX_SUBAGENT_TIMEOUT_MIN`（30 分鐘）、`download_file` = 註冊 10 分鐘，請求本身由自身參數限制（預設 120 秒、上限 600 秒）、`generate_audio` = 5 分鐘、`fetch_page` / `search_web` = 90 秒、`http_request` = 由自身參數指定（預設 60 秒、上限 300 秒），仍受 15 分鐘預設約束、`generate_image` = 15 分鐘、`html_template` = 30 秒、`open_file` = 10 秒、`ask_user` = 無上限。

## 憑證自動修復

`store_secret` 為 `SystemUse` 工具，不出現在一般的 `find_tools(mode=list)` 列表；自 v1.0.27 起它和其他工具一樣，完整 schema 就在首輪 payload 中。System prompt 原本的 `§10 Credential auto-heal` 段落已移除；現在 system prompt 只留一行 `Credentials` —— 金鑰存放於 OS keychain（service `agenvoy`、account = 金鑰名稱），Linux 再查 `~/.config/agenvoy/.secrets`，最後才是同名環境變數 —— 要求模型先讀 keychain，只有金鑰確實不存在時才使用 `store_secret`。流程寫在該工具自己的 description。遇到認證失敗——缺 key、`401`、`403`、token 過期——agent 從錯誤中取出 key 名稱、呼叫 `store_secret`（透過遮罩輸入取得新值 — 該值永不到達 LLM），再重新呼叫失敗的工具。每個工具每回合上限為兩輪 `store_secret`。
