--- name: dispatch-webhook description: 發送任務 Payload 到指定 VPS 的 Webhook endpoint,支援同步等待與非同步模式。 triggers: [] tools: - web_fetch - exec internal: true --- # Dispatch Webhook Skill ## 功能說明 底層 Webhook 發送工具,由 `assign-task` 呼叫。 負責發送任務到 VPS-A 或 VPS-B,處理認證與錯誤重試。 ## Webhook 協議 ### 請求格式(OpenClaw → VPS) ```http POST Authorization: Bearer Content-Type: application/json X-OpenClaw-Version: 1.0 { "task_id": "uuid", "type": "project_development", "description": "任務描述", "priority": "high|normal|low", "callback_url": "https://oclaw.nature.edu.kg/webhook/callback", "created_at": "ISO8601" } ``` ### 即時回應格式(VPS → OpenClaw,HTTP 202) ```json { "task_id": "uuid", "status": "accepted", "message": "任務已接受,開始執行" } ``` ### Callback 格式(任務完成後,VPS → OpenClaw) ```http POST Authorization: Bearer Content-Type: application/json { "task_id": "uuid", "status": "completed|failed", "summary": "執行摘要", "artifacts": ["file1.py", "docs/README.md"], "error": null } ``` ## VPS 端接收端實作範例 ### Node.js / Express ```javascript app.post('/webhook/openclaw', (req, res) => { const token = req.headers.authorization?.replace('Bearer ', ''); if (token !== process.env.OPENCLAW_WEBHOOK_TOKEN) { return res.status(401).json({ error: 'Unauthorized' }); } const task = req.body; res.status(202).json({ task_id: task.task_id, status: 'accepted' }); // 非同步執行任務 processTask(task).then(result => { // 回傳結果給 OpenClaw fetch(task.callback_url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${CALLBACK_TOKEN}` }, body: JSON.stringify({ task_id: task.task_id, status: 'completed', ...result }), }); }); }); ``` ### 給 Claude Code 的提示詞(VPS-A) 任務接收後,PM agent 用這個提示詞啟動工作: ``` 你是專案經理,收到來自 OpenClaw 的任務指派。 Task ID: {task_id} 任務描述: {description} 優先級: {priority} 請: 1. 分析需求,制定實作計劃 2. 分派子任務給適合的模型(Sonnet 寫程式,Haiku 做測試) 3. 整合結果,確保品質 4. 完成後透過 callback_url 回報結果 ``` ## 錯誤處理 | 錯誤 | 處理方式 | |------|---------| | 連線失敗 | 重試 3 次,間隔 5s | | 401 Unauthorized | 立即失敗,提示設定 token | | 超時(> 30s) | 返回 accepted,等待 callback | | VPS 回傳 500 | 記錄錯誤,通知使用者 |