- 首頁
- Documentation
- 執行階段工具
- 任務代理探索與選擇
任務代理探索與選擇
本文件描述任務子系統如何探索代理定義、合併多個來源,以及在執行時解析請求的代理。
內容涵蓋目前已實作的執行時期行為,包括優先順序、無效定義處理,以及可能使代理實際上不可用的生成/深度限制。
src/task/discovery.tssrc/task/agents.tssrc/task/types.tssrc/task/index.tssrc/task/commands.tssrc/prompts/agents/task.mdsrc/prompts/tools/task.mdsrc/discovery/helpers.tssrc/config.tssrc/task/executor.ts
代理定義結構
Section titled “代理定義結構”任務代理正規化為 AgentDefinition(src/task/types.ts):
name、description、systemPrompt(載入有效代理時為必要欄位)- 選用的
tools、spawns、model、thinkingLevel、output source:"bundled" | "user" | "project"- 選用的
filePath
解析來自透過 parseAgentFields()(src/discovery/helpers.ts)處理的 frontmatter:
- 缺少
name或description=> 無效(null),呼叫端視為解析失敗 tools接受 CSV 或陣列;若有提供,會自動加入submit_resultspawns接受*、CSV 或陣列- 向後相容行為:若
spawns缺失但tools包含task,spawns會變為* output作為不透明的 schema 資料直接傳遞
內建代理在建置時嵌入(src/task/agents.ts),使用文字匯入。
EMBEDDED_AGENT_DEFS 定義:
explore、plan、designer、reviewer來自提示詞檔案task和quick_task來自共用的task.md本體加上注入的 frontmatter
載入路徑:
loadBundledAgents()使用parseAgent(..., "bundled", "fatal")解析嵌入的 markdown- 結果快取在記憶體中(
bundledAgentsCache) clearBundledAgentsCache()僅供測試用的快取重設
因為內建解析使用 level: "fatal",格式錯誤的內建 frontmatter 會拋出例外,可能導致整個探索程序失敗。
檔案系統與外掛探索
Section titled “檔案系統與外掛探索”discoverAgents(cwd, home)(src/task/discovery.ts)在附加內建定義之前,會合併來自多個位置的代理。
- 來自
getConfigDirs("agents", { project: false })的使用者設定代理目錄 - 來自
findAllNearestProjectConfigDirs("agents", cwd)的最近專案代理目錄 - Claude 外掛根目錄(
listClaudePluginRoots(home))及其agents/子目錄 - 內建代理(
loadBundledAgents())
實際來源順序
Section titled “實際來源順序”來源家族順序來自 getConfigDirs("", { project: false }),其衍生自 src/config.ts 中的 priorityList:
.xcsh.claude.codex.gemini
對於每個來源家族,探索順序為:
- 該來源的最近專案目錄(若找到的話)
- 該來源的使用者目錄
在所有來源家族目錄之後,附加外掛 agents/ 目錄(專案範圍的外掛優先,然後是使用者範圍的)。
內建代理最後附加。
重要注意事項:過時的註解與目前程式碼
Section titled “重要注意事項:過時的註解與目前程式碼”discovery.ts 的標頭註解仍然提到 .pi,且未提到 .codex/.gemini。實際執行時期順序由 src/config.ts 驅動,目前使用 .xcsh、.claude、.codex、.gemini。
合併與衝突規則
Section titled “合併與衝突規則”探索使用依精確 agent.name 的先到先贏去重:
- 一個
Set<string>追蹤已見過的名稱。 - 載入的代理按目錄順序展平,僅在名稱未見過時保留。
- 內建代理對照同一集合過濾,僅在名稱仍未見過時加入。
影響:
- 對於相同的來源家族,專案覆寫使用者。
- 較高優先順序的來源家族覆寫較低的(
.xcsh在.claude之前,依此類推)。 - 非內建代理覆寫同名的內建代理。
- 名稱比對區分大小寫(
Task和task視為不同)。 - 在同一目錄內,markdown 檔案在去重前按檔名字典序讀取。
無效/缺失代理檔案行為
Section titled “無效/缺失代理檔案行為”按目錄(loadAgentsFromDir):
- 無法讀取/缺失的目錄:視為空(
readdir(...).catch(() => [])) - 檔案讀取或解析失敗:記錄警告,跳過檔案
- 解析路徑使用
parseAgent(..., level: "warn")
Frontmatter 失敗行為來自 parseFrontmatter:
warn層級的解析錯誤會記錄警告- 解析器退回至簡單的
key: value逐行解析器 - 若必要欄位仍然缺失,
parseAgentFields失敗,然後拋出AgentParsingError並由呼叫端捕獲(跳過檔案)
淨效果:一個有問題的自訂代理檔案不會中止其他檔案的探索。
代理查詢與選擇
Section titled “代理查詢與選擇”查詢是精確名稱的線性搜尋:
getAgent(agents, name)=>agents.find(a => a.name === name)
在任務執行中(TaskTool.execute):
- 在呼叫時重新探索代理(
discoverAgents(this.session.cwd)) - 請求的
params.agent透過getAgent解析 - 找不到代理時回傳立即的工具回應:
Unknown agent "...". Available: ...- 不執行子程序
描述與執行時期探索的差異
Section titled “描述與執行時期探索的差異”TaskTool.create() 在初始化時從探索結果建置工具描述(buildDescription)。
execute() 會再次重新探索代理。因此若代理檔案在工作階段中途變更,執行時期的集合可能與先前工具描述中列出的不同。
結構化輸出防護機制與 schema 優先順序
Section titled “結構化輸出防護機制與 schema 優先順序”TaskTool.execute 中的執行時期輸出 schema 優先順序:
- 代理 frontmatter 的
output - 任務呼叫的
params.schema - 父工作階段的
outputSchema
(effectiveOutputSchema = effectiveAgent.output ?? outputSchema ?? this.session.outputSchema)
src/prompts/tools/task.md 中的提示詞防護文字警告結構化輸出代理(explore、reviewer)的不匹配行為:散文中的輸出格式指示可能與內建 schema 衝突,產生 null 輸出。
這是指導性質的,不是 discoverAgents 中的硬性執行時期驗證邏輯。
命令探索互動
Section titled “命令探索互動”src/task/commands.ts 是工作流程命令(非代理定義)的平行基礎設施,但它遵循相同的整體模式:
- 首先從能力提供者探索
- 以先到先贏方式按名稱去重
- 若仍未見過則附加內建命令
- 透過
getCommand進行精確名稱查詢
在 src/task/index.ts 中,命令輔助函式與代理探索輔助函式一起重新匯出。代理探索本身在執行時期不依賴命令探索。
超出探索範圍的可用性限制
Section titled “超出探索範圍的可用性限制”代理可能是可探索的,但由於執行防護機制仍然無法執行。
父代生成策略
Section titled “父代生成策略”TaskTool.execute 檢查 session.getSessionSpawns():
"*"=> 允許任何""=> 拒絕全部- CSV 列表 => 僅允許列出的名稱
若被拒絕:立即回應 Cannot spawn '...'. Allowed: ...。
阻止自我遞迴的環境變數防護
Section titled “阻止自我遞迴的環境變數防護”PI_BLOCKED_AGENT 在工具建構時讀取。若請求匹配,執行會被拒絕並回傳遞迴預防訊息。
遞迴深度閘控(子工作階段中的任務工具可用性)
Section titled “遞迴深度閘控(子工作階段中的任務工具可用性)”在 runSubprocess(src/task/executor.ts)中:
- 深度從
taskDepth計算 task.maxRecursionDepth控制截止點- 達到最大深度時:
task工具從子工具列表中移除- 子代的
spawns環境變數設為空
因此更深層級無法生成進一步的任務,即使代理定義包含 spawns。
計畫模式注意事項(目前實作)
Section titled “計畫模式注意事項(目前實作)”TaskTool.execute 為計畫模式計算一個 effectiveAgent(前置計畫模式提示詞、強制唯讀工具子集、清除 spawns),但 runSubprocess 使用的是 agent 而非 effectiveAgent。
目前的效果:
- 模型覆寫 / 思考層級 / 輸出 schema 衍生自
effectiveAgent - 來自
effectiveAgent的系統提示詞和工具/生成限制在此呼叫路徑中未被傳遞
這是閱讀計畫模式行為預期時值得了解的實作注意事項。