feat(cypher-executor): 同步查詢 trigger + graph_neighbors 查詢面 workflow 示範

Part 1(框架,cypher-executor webhooks-named.ts):加同步查詢 trigger。
現有 named webhook /trigger 回 {success,data,trace,duration_ms} 信封、只有 POST;
查詢面(console/MCP 打 graph neighbors/traverse)要 GET + 直接拿最終節點輸出當 response。
新端點同步 await 執行 workflow graph → 回 result.data(最終節點輸出)本身當 body(非 202):
  - GET  /q/:ns/:name                    (namespace 走 path,input 走 query string)
  - GET  /webhooks/named/:name/query     (X-Arcrun-API-Key header,input 走 query string)
  - POST /webhooks/named/:name/query     (header,input 走 body)
  - POST /webhooks/named/:ns/:name/query (namespace 走 path,input 走 body)
認證沿用 X-Arcrun-API-Key。誠實(mindset §7):節點失敗回 error+trace(500,非假綠);
paused 工作流無法同步回答 → 409 明講;輸出 5 MiB 硬上限(超過 413);duration 走 header 不污染 body。

Part 2(A 類 workflow.yaml):registry/examples/graph-neighbors/。
http_request 打 base custom domain kbdb.finally.click(避 CF 1042)撈 triplet records
→ code 零件記憶體 BFS(對照 kbdb-graph-plugin graph-traverse.ts)→ 同步回鄰居。
把 graph plugin 內建 GET /graph/neighbors 泛化成查詢面 workflow 的示範。

測試:cypher-executor/tests/query-trigger.test.ts(7 測,全綠)——同步回輸出(非 202)、
GET/POST × header/path 四端點、節點失敗回錯+trace、缺 key 401、不存在 404。
用內建 comp_uppercase(純記憶體)證明 Part 1 同步 trigger 機制本身可用。

待驗:graph_neighbors 需 code 零件部署 leo21c 後才能 live 端到端(另線處理);
triplet template id 上線前對一次(workflow 已參數化未寫死)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
This commit is contained in:
2026-07-07 08:16:17 +00:00
parent b13b4dfe49
commit 313aeb13bf
6 changed files with 435 additions and 0 deletions
@@ -0,0 +1,59 @@
# graph-neighbors
## 解決什麼問題
把 graph plugin 內建的 `GET /graph/neighbors`(同步 request→response 拿鄰居)**改寫成一條 workflow**。
示範「查詢面工作流」:查詢端點不必是框架寫死的 route,可以是一條 `workflow.yaml` —— 撈 triplet
記錄 → 記憶體 BFS → 同步回鄰居。任何唯讀查詢都能這樣泛化成 workflow。
## 依賴的框架能力(本 PR 補上的)
**同步查詢 trigger**cypher-executor `webhooks-named.ts`):現有 named webhook 的 `/trigger`
回的是 `{success,data,trace,duration_ms}` 信封、且只有 POST。查詢面要 **GET + 直接拿最終節點輸出**
新端點同步 `await` 執行 graph → 把 `result.data`(最終節點輸出)本身當 response body 回(非 202):
- `GET /q/:ns/:name`namespace 走 pathinput 走 query string
- `GET /webhooks/named/:name/query`X-Arcrun-API-Key headerinput 走 query string
- `POST /webhooks/named/:name/query`headerinput 走 body
- `POST /webhooks/named/:ns/:name/query`namespace 走 pathinput 走 body
## 怎麼觸發
```bash
# GET(最像原本的 /graph/neighbors
curl "https://cypher.arcrun.dev/q/{namespace}/graph_neighbors?node=Arcrun&depth=2&template=graph_triplet&namespace={namespace}"
# POSTheader 認證)
curl -X POST https://cypher.arcrun.dev/webhooks/named/graph_neighbors/query \
-H "X-Arcrun-API-Key: {namespace}" \
-d '{"node":"Arcrun","depth":2,"template":"graph_triplet","namespace":"{namespace}"}'
```
回傳(最終節點輸出本身,非信封):
```json
{ "success": true, "start": "Arcrun", "depth": 2, "directed": false,
"neighbors": [ { "node": "cypher-executor", "predicate": "包含", "from": "Arcrun", "depth": 1 } ],
"count": 1 }
```
## 參數
- `node`(必填):BFS 起點節點名
- `depth`(預設 1):最大跳數
- `template`(必填):triplet 記錄的 base template id(⚠️ 以實際部署的 kbdb-graph-plugin triplet template 為準)
- `namespace`(必填):租戶 owner_idself-hosted 明碼 namespace
- `directed`(預設 false):`true` 只走 subject→object;否則把 triplet 當雙向邊(無向鄰居)
## 為什麼走 kbdb.finally.clickbase custom domain
cypher-executor 對 kbdb 發 fetch,若打同 zone `*.workers.dev` 會踩 CF 1042same-zone self-fetch)。
打 base 的對外 custom domain `kbdb.finally.click` 屬跨 zone、走公網前門,避開 1042。
## ⚠️ 尚未 live 驗(待辦)
- **`code` 零件尚未部署到 leo21c**(另線處理)→ 本工作流無法端到端 live 跑。
workflow.yaml 已寫好放這裡待驗。
- **同步查詢 trigger 本身已驗**`cypher-executor/tests/query-trigger.test.ts`7 測)用內建零件
comp_uppercase,純記憶體、無外部 fetch)證明「確實同步回最終節點輸出而非 202」。
- 上線前另需對一次實際 triplet template id(本檔用 `{{input.template}}` 參數化,未寫死)。
## 對照
記憶體 BFS 對照 `kbdb-graph-plugin``graph-traverse.ts:23-51`triplet 當有向邊
`subject --predicate--> object`,從起點逐跳擴張到 depth 上限,收集首次訪到的節點當鄰居。
## 學到什麼
- 查詢端點可以是 workflow,不必是框架寫死的 route(同步查詢 trigger 讓這件事成立)
- `code` 零件(sandbox inline JS)承載「非 call-api 的純計算」(BFS),不必為此鑄 domain 零件
- 單一 `{{ref}}` pass-through 保留陣列型別 → `{{fetch_triplets.data.records}}` 拿到真陣列餵給 code