# 檔案工具

尋找、讀取、編輯、移除、還原、開啟與追蹤檔案的工具。

| 工具 | 說明 |
|---|---|
| `find_files` | 尋找檔案（`queries: [{dir, pattern, file_pattern, recursive}]`）。`mode=list` 回傳目錄內容（依字母排序），`mode=glob` 以檔名 pattern 比對路徑，自 v1.0.23 起依最近修改時間由新到舊排序，`mode=search` 以 RE2 regex grep 檔案內容。省略 mode 時自動推斷：`pattern` + `file_pattern` → search、只有 `pattern` → glob、兩者皆無 → list。glob pattern 必須含字面字元，全萬用字元（`**/*`）會被拒絕。多筆 query 的結果會合併去重。`mode=list` 與 `mode=glob` 上限為總計 128 KiB，截斷時結尾會說明丟棄了幾筆。`mode=search` 自 v1.0.11 起改為分頁而非截斷：`output=files`（預設）每個命中檔案回一列 `{path, count, lines}` —— 自 v1.0.23 起 `lines` 帶前五個匹配的行號，可直接交給 `read_files` 的 `around` —— `output=content` 回帶行號的匹配行，`multiline=true`（v1.0.23）改以整份檔案比對 regex，讓 `.` 可跨越換行，並回報匹配涵蓋的每一行；`offset` / `limit`（預設 256）翻頁，`context` 附上前後文行數 —— 標記 `context: true` 且不計入 `offset` / `limit`。單一匹配行超過 512 bytes 會被截短。每頁結尾帶 `[files a-b of N ...]` / `[lines a-b of N ...]` 說明下一個 `offset`，或標示 `last page`；翻頁期間 query 與 `output` 必須維持不變 |
| `read_files` | 批次讀取一個或多個檔案（`files: [{path, offset, limit, around, context}]`）；支援文字、PDF、DOCX、PPTX、CSV/TSV、圖片，以及音訊 / 影片 —— 媒體檔會經由已設定的 speech-to-text 模型回傳逐字稿，因此不再有獨立的轉錄工具。預設最多讀 2048 行（文件上限 1 MiB、圖片 10 MiB），超過時以 `offset`/`limit` 分頁 —— PDF 以頁、PPTX 以投影片、CSV 以列為單位。自 v1.0.23 起 `around` 接受純文字檔的 1-based 行號，並在每行前後各讀 `context` 行（預設 20，`0` = 只讀該行），重疊的區段會合併、略過的內容以 `...` 行標示（此時忽略 `offset`/`limit`）；同一路徑可在 `files` 中出現多次，結果依序串接。自 v1.0.11 起被截斷的文字讀取會在結尾附上 `[lines a-b of N; call again with offset=... for more]`，接續的 offset 不必用猜的。文字行以 `"<row>\t<line>"` 形式回傳，行號由讀取端加上、不存在於檔案中，拿該行當 `edit_file` anchor 前必須先去除。`edit_file` 修改既有檔案前必須先呼叫：自 v1.0.23 起，檔案須在本次執行中讀過、且讀取後修改時間未變，編輯才會被接受。自 v1.3.11 起，設定 decision model 時，4096 字元以上且被判定與當前請求無關（信心 0.7 以上，與 `chat_history` `mode=read` 共用同一檢查）的檔案會被扣下：該項改回一行 `File withheld` 說明而非內容。同一檔案在同一 session 最多被扣下一次，第二次讀取即回傳內容；帶 `around` 的讀取不檢查；沒有 decision model 或檢查失敗時，內容照常回傳。**敏感檔案防護**：SSH keys、`.pem`、`.key`、`.env` 一律需要確認，無論是否處於 sudo 或 allowlist |
| `edit_file` | 對磁碟上檔案的所有變更。`mode=write` 建立首版或刻意整份覆寫；`mode=patch` 透過 `targets` 陣列做區域編輯 —— 每個 target 為 `{old_string, new_string}` 加上選用的 `replace_all`，所有 anchor 都在套用任何變更前對原始檔案內容定位。兩個 target 覆蓋同一區域，或某 target 的 `old_string` 出現在較早 target 的 `new_string` 內時，整次呼叫被拒絕、不寫入任何內容。以下情況同樣整次拒絕：`old_string` 匹配多處卻未設 `replace_all`、patch 會把非空檔案清空、把歷史紀錄的佔位字串當成內容貼回，或檔案超過 1 MiB。`new_string` 留空即為刪除；插入的寫法是把 `old_string` 原樣放在 `new_string` 開頭。以行號定位的 `row` / `insert_string` 形式已移除 —— 行號會把同一次呼叫中先前的 target 一併算入，而那些內容尚未寫入磁碟。只剩 `mode=write` 與 `mode=patch`，且 `path` 為必填：`mode=remove` 與 `mode=restore` 移除於 v1.3.11（改用 `remove_file` / `restore_file`）。省略 mode 時：有 `content` → write、有 `targets` → patch。自 v1.0.23 起，覆寫既有檔案的 `write` 與每一次 `patch` 都要通過讀取新鮮度檢查：檔案須在本次執行中以 `read_files` 讀過，且之後未在磁碟上被變更（使用者、formatter 或其他指令），否則不寫入任何內容，錯誤訊息要求重新讀取；成功寫入後即視為已重新讀取，可接著編輯。`patch` 的 anchor 若只在彎引號與直引號上與檔案不同仍可命中，取代內容會沿用檔案原本的引號樣式。工具描述會把未指定位置、為使用者產生的檔案導向 system prompt 所列的輸出目錄，並要求給完整路徑；`path` 留空會直接被拒絕，不會落到輸出目錄。`path` 可為絕對路徑或相對於工作目錄 |
| `remove_file` | v1.3.11 新增，取代 `edit_file(mode=remove)`。把單一檔案（`path`，必填；絕對路徑或相對於工作目錄）移到 `~/.config/agenvoy/.store/temp/` 而非刪除，在檔案歷史記下這次搬移，並回傳移到哪裡；`restore_file` 可放回。每次呼叫都要求確認，除非使用者已允許本輪所有呼叫。只在明確要求或 Skill 步驟中使用；skill 或 script tool 改用 `edit_skill` / `edit_tool` 的 `mode=remove`。subagent leg 不可用。tool-call 行顯示為 `Remove(<path>)` |
| `restore_file` | v1.3.11 新增，取代 `edit_file(mode=restore)`。以 `version`（`file_history` 某列的 id，同時指明檔案與狀態；優先於 `task_id`）放回一個紀錄版本，或以 `task_id`（`chat_history` 的 task id，或以 `current` 表示當前執行中的任務）回滾整個任務，把該任務動過的每個檔案還原到執行前；`path` 搭配 `task_id` 時只還原該檔。`version` / `task_id` 至少擇一。也能放回被 `remove_file` 移走的檔案。每次呼叫都要求確認，除非使用者已允許本輪所有呼叫。subagent leg 不可用。tool-call 行顯示為 `Restore(...)`，括號內為路徑、`version N` 或 task id |
| `file_history` | 工具動過的每個檔案的版本紀錄 —— 何時變更、當時任務目標為何、內容是什麼。`mode=list` 由新到舊列出版本，可用 `path`、`task_id`、`from`/`to` 本地時間與 `limit`（上限 24）過濾；`mode=read` 將每個路徑的最新紀錄版本與磁碟現況做 diff。這是 `restore_file` 還原時所依據的快照層 |
| `open_file` | 以 OS 預設處理程式開啟檔案或 URL（播放影片、檢視圖片、開啟 PDF 閱讀器；自 v1.2.1 起也可開啟連結或系統設定面板，如 `x-apple.systempreferences:...`）。URL 一律先請使用者確認。取代沙箱無法觸及的 `run_command` `open`/`xdg-open`。上限 10 秒 |
