diff --git a/mcp/src/mcp-handler.ts b/mcp/src/mcp-handler.ts index ccd92d8..9492bd2 100644 --- a/mcp/src/mcp-handler.ts +++ b/mcp/src/mcp-handler.ts @@ -15,10 +15,35 @@ export async function handleMcpRequest( //(選型理由見 lib/library-map.ts 檔頭);任何失敗回 null → 靜默略過,絕不擋 MCP 連線(鐵律)。 const mapInstructions = await buildLibraryMapInstructions(env); + // 2026-07-30(leo 問「人類說『幫我用 arcrun 寫 xxx』,Haiku 會知道要用這些資源嗎? + // 如果不會,要寫什麼在外面讓它一聽到就知道?」): + // 實測答案是**不會**——AI 只看到 41 個工具名,會自己猜(很可能直接跳到 push_workflow + // 瞎編,或去讀 registry/examples 那 8/13 引用不存在零件的壞範例)。 + // instructions 是唯一「AI 一連上就必看」的欄位 ⇒ 開場就指路,不依賴任何查詢成功。 + // ⚠️ 這段是靜態常數:即使 KBDB 掛了、藏書地圖抓不到,它也必須出現(鐵律:不擋連線)。 + const startHere = [ + "【先讀這裡】要在 Arcrun 上做任何事(用戶說「幫我用 Arcrun 做 X」),**照這個順序**:", + "", + "1. `arcrun_get_skill('write_intent_workflow')` — **必讀第一支**。", + " 教你用 `>>` 寫「意圖工作流」。你**不需要先知道有哪些零件**,先寫意圖。", + "2. `arcrun_whoami()` — 確認連到哪個帳號(勿自行 curl 猜帳號 URL)。", + "3. 把意圖丟 `POST /cypher/search` 或 `arcrun_validate_yaml` — 系統告訴你哪些零件存在。", + "4. `arcrun_list_skills()` — 看有沒有更貼近你這件事的 skill(watcher/RAG/debug…)。", + "5. 缺零件時:缺 API → 寫 recipe(`arcrun_recipe_push`);缺能力 → 投稿零件 PR。", + " 🔴 **不要因為查不到零件就改寫成 `code` 節點**——那叫「腹語術」(表面用 Arcrun、", + " 實際全寫 JS)。`code` 只用於局部整形(例:剝掉 LLM 回應的雜訊)。", + "", + "邊只有兩種:`ON_SUCCESS` 與 `對每個 <變數>`(FOREACH)。", + "**沒有** `ON_TRUE`/`ON_FALSE`/`ON_FAILURE`——引擎目前不支援條件分支。", + "第一個節點固定是 `input`。", + ].join("\n"); + + const instructions = mapInstructions ? `${startHere}\n\n---\n\n${mapInstructions}` : startHere; + const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); const server = new McpServer( { name: "arcrun-mcp-server", version: "1.0.0" }, - mapInstructions ? { instructions: mapInstructions } : undefined, + { instructions }, ); registerAllTools(server, env, orgNamespace, partnerToken); diff --git a/registry/skills/write_intent_workflow.md b/registry/skills/write_intent_workflow.md new file mode 100644 index 0000000..a84d92b --- /dev/null +++ b/registry/skills/write_intent_workflow.md @@ -0,0 +1,153 @@ +# Skill: Write Intent Workflow(寫意圖工作流) + +## 何時用這個 skill + +**用戶說「幫我用 Arcrun 做 X」時,第一個讀這支。** 其他 skill 都是它的下游。 + +- 「幫我用 Arcrun 寫一個…」 +- 「用 Arcrun 做 X」 +- 你要在 Arcrun 上做任何事,但不知道有哪些零件可用 + +> **你不需要知道有哪些零件。** 先把意圖寫出來丟去查,系統會告訴你哪些存在、哪些不存在。 + +## 核心 pattern + +``` +input >> ON_SUCCESS >> <第一步> >> ... → 丟 /cypher/search → 系統回哪些零件存在 +``` + +--- + +## 1. 意圖工作流的語法 + +一串「誰接誰」,每行一個關係: + +``` +<節點A> >> <邊> >> <節點B> +``` + +- **節點**=一個步驟。用你想得到的名字(中文可以),**不必是真實零件名** +- **邊**=什麼情況下往下走 + +## 2. 邊只有兩種(真範本裡出現過的) + +| 邊 | 意思 | 真例 | +|---|---|---| +| `ON_SUCCESS` | 上一步成功就往下 | `input >> ON_SUCCESS >> prep` | +| `對每個 <變數>` | 上一步產出清單,逐項處理(FOREACH)| `parse_card >> 對每個 block >> post_block` | + +⚠️ **不要寫 `ON_FAILURE`/`ON_TRUE`/`ON_FALSE`**——引擎目前**沒有條件分支** +(實測 `grep ON_TRUE|ON_FALSE` 於 cypher-executor = 0;見 Gitea Arcrun#5)。 +需要判斷時:**寫成一個獨立節點**(例 `check_amount`)再接 `ON_SUCCESS`, +讓查詢告訴你有沒有零件可用。 + +## 3. 第一個節點固定是 `input` + +所有真範本都以 `input` 起頭——那是「觸發時帶進來的資料」。 + +--- + +## 4. 真範本(照抄結構、改內容) + +> 以下四份**全部是實際部署且 `verdict=success` 的 workflow**,不是簡化示範。 +> 用 `arcrun_get_workflow()` 可以拿完整定義。 + +### A. 最短:取資料 → 處理 (`graph_neighbors`) +``` +input >> ON_SUCCESS >> fetch_triplets +fetch_triplets >> ON_SUCCESS >> bfs_neighbors +``` + +### B. 長鏈:多次查詢 → 組裝 → 問 AI → 收尾 (`rag_chat`) +``` +input >> ON_SUCCESS >> prep +prep >> ON_SUCCESS >> kw_search +kw_search >> ON_SUCCESS >> sem_search +sem_search >> ON_SUCCESS >> fetch_triplets +fetch_triplets >> ON_SUCCESS >> fetch_blocks_a +fetch_blocks_a >> ON_SUCCESS >> assemble +assemble >> ON_SUCCESS >> ask_llm +ask_llm >> ON_SUCCESS >> finalize +``` +`prep` 前處理/`assemble` 組 prompt/`finalize` 收拾回應——三個常見的整形節點。 + +### C. 一節點分岔兩條 FOREACH (`rag_ingest_card`) +``` +input >> ON_SUCCESS >> parse_card +parse_card >> 對每個 block >> post_block +parse_card >> 對每個 rel >> post_triplet +``` +同一節點可有多條出邊,各自處理不同清單。 + +### D. 混合:直線 + 兩段 FOREACH (`rag_takedown_direct`) +``` +input >> ON_SUCCESS >> prep +prep >> ON_SUCCESS >> list_dead_blocks +list_dead_blocks >> ON_SUCCESS >> build_deprecations +build_deprecations >> 對每個 dead_entry >> deprecate_entry +build_deprecations >> ON_SUCCESS >> list_triplets +list_triplets >> ON_SUCCESS >> pick_dead_triplets +pick_dead_triplets >> 對每個 dead_record >> deprecate_triplet +``` +`build_deprecations` 同時有 FOREACH 出邊與 `ON_SUCCESS` 出邊—— +前者處理清單、後者繼續主線。 + +--- + +## 5. 節點怎麼命名(照真範本的模式,查詢較容易媒合) + +| 意圖 | 模式 | 真例 | +|---|---|---| +| 前處理/正規化 | `prep` | `rag_chat.prep` | +| 取一批資料 | `fetch_*`/`list_*` | `fetch_triplets`/`list_dead_blocks` | +| 搜尋 | `*_search` | `kw_search`/`sem_search` | +| 解析/切塊 | `parse_*` | `parse_card` | +| 寫入 | `post_*` | `post_block`/`post_triplet` | +| 組裝 | `assemble`/`build_*` | `assemble`/`build_deprecations` | +| 問 AI | `ask_llm` | `rag_chat.ask_llm` | +| 收尾整形 | `finalize` | `rag_chat.finalize` | + +--- + +## 6. 寫完一定要查(**不要直接部署**) + +```bash +curl -s -X POST https://arcrun-cypher-executor..workers.dev/cypher/search \ + -H 'content-type: application/json' -H 'X-Arcrun-API-Key: ' \ + -d '{"triplets":["input >> ON_SUCCESS >> fetch_data","fetch_data >> ON_SUCCESS >> notify"]}' +``` + +回應的每個節點會有: + +| status | 意思 | 你該做什麼 | +|---|---|---| +| `found` | 有零件,附 `input_schema`(怎麼填 payload)與 `success_rate` | **只填 payload** | +| `missing` | 沒有這個零件 | 缺 API → 寫 recipe;缺能力 → 投稿零件 PR | +| `unknown` | 查不到 registry | **不代表不存在**,別據此改寫成 code | + +⚠️ **2026-07-30 已知限制**:`/cypher/search` 目前對**任何**節點名都回 `found` +(不查 registry)⇒ **這個 status 現在不可信**。修復中(CP `arcrun-usable` 步驟 3)。 +在它修好前:用 `arcrun_list_components` / `arcrun_search_components` 自己確認零件是否存在。 + +--- + +## 7. 常犯的錯 + +1. **用不存在的邊**(`ON_FAILURE`/`ON_TRUE`)→ 只有 `ON_SUCCESS` 與 `對每個 X` +2. **第一個節點不是 `input`** +3. **把 recipe 當零件寫**——`telegram_send`/`gmail`/`kbdb_get` 是 **recipe** 不是零件 + → 寫成 `http_request` + 該 recipe +4. 🔴 **查詢回 `missing` 就改寫成 `code` 節點** + → 那叫「腹語術」(表面用 Arcrun、實際全寫 JS)。正解:缺 API 寫 recipe、缺能力投稿零件。 + `code` 只用在**局部整形**(例:剝掉 LLM 回應的雜訊),不用來取代零件與流程控制。 + +--- + +## 8. 相關 + +- 完整版指引與十題考卷(含 haiku 實測 10/10): + 頂層 repo `system-dev/docs/3-specs/arcrun-usable/` +- 下一步該讀哪支 skill:`arcrun_list_skills()` + - 定期掃資料 → `build_watcher_workflow` + - RAG 檢索問答 → `rag_with_arcrun` + - workflow 卡住不動 → `debug_paused_workflow`