5cadc60e36
📋 SDD:workflow-discovery(本 commit 同時執行 D35 交接:portal-auth 26/26 完成 → closed superseded_by workflow-discovery;workflow-discovery paused → active。單一活性已驗=1 份) 🎯 對應 task:3.x 搜尋端誠實化(CP2-B) 病灶(leo 2026-07-30 定性「腹語術」): search-nodes.ts 無條件回 status:'found'、missingNodes 永遠 []—— 型別宣告了 'missing' 但程式碼從不使用。實測「完全不存在的東西xyz」也回 found。 ⇒ AI 拿到假信號 → 以為零件存在 → 部署才發現沒有 → 改寫 code ⇒ 正式 workflow 只用 2 個零件、8 個 code 節點含 if×61。 修法: - 查 registry 判真實存在(走 HTTP,守 D28 禁新增 service binding; URL 用既有 wasmWorkerUrl() 慣例組,不自創) - found 時附 input_schema/success_rate/stability ⇒ AI 才填得出 payload、才看得到「測過幾次」(leo:AI 只要填 payload) - 查不通回 'unknown' 而非 'missing'——**誠實限制**: 不能因查詢失敗就宣告零件不存在(那會讓 AI 誤判而重寫 code) - missing 真的回傳出去(原本寫死 []) ⚠️ 實測發現 registry **沒有列表端點**(GET /components → 404,只有 /components/<id>) ⇒ 改為逐個查(節點數通常 <10、5s timeout)。補列表端點後可改抓一次=CP2-B 待辦。 驗:tsc 零錯誤;vitest 9 failed/179 passed=**與改動前 stash 對帳完全相同**(既有債非本次造成)。 ⏳ 待部署到實例後跑 arcrun-usable/verify.sh 驗 01 那組轉綠。
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import type { Bindings } from '../types';
|
||
import { graphSchema } from '../lib/schemas';
|
||
import { parseTriplets } from './triplet-parser';
|
||
import { searchNodes } from './search-nodes';
|
||
import { buildExecutionGraph } from './graph-builder';
|
||
|
||
export async function resolveWebhookGraph(
|
||
body: Record<string, unknown>,
|
||
description: string,
|
||
env: Bindings,
|
||
): Promise<{ resolvedGraph: Record<string, unknown>; error?: string }> {
|
||
// 路徑 A:triplets 格式
|
||
if (Array.isArray(body.triplets) && body.triplets.length > 0) {
|
||
const parsed = parseTriplets(body.triplets as unknown[]);
|
||
if (!parsed) return { resolvedGraph: {}, error: '無法解析 triplets' };
|
||
|
||
const { nodeResults } = await searchNodes(parsed);
|
||
|
||
const graphId = `webhook-${Date.now()}`;
|
||
const graphName = description || `Webhook ${new Date().toISOString()}`;
|
||
const graph = buildExecutionGraph(parsed, nodeResults, graphId, graphName) as Record<string, unknown>;
|
||
|
||
const parseResult = graphSchema.safeParse(graph);
|
||
if (!parseResult.success) {
|
||
return { resolvedGraph: {}, error: '圖定義產生失敗' };
|
||
}
|
||
|
||
return { resolvedGraph: graph };
|
||
}
|
||
|
||
// 路徑 B:graph 格式
|
||
if (body.graph && typeof body.graph === 'object') {
|
||
const graphWithDefaults = {
|
||
id: `webhook-${Date.now()}`,
|
||
name: description || `Webhook ${new Date().toISOString()}`,
|
||
...(body.graph as Record<string, unknown>),
|
||
};
|
||
const parsed = graphSchema.safeParse(graphWithDefaults);
|
||
if (!parsed.success) {
|
||
return { resolvedGraph: {}, error: '圖定義驗證失敗' };
|
||
}
|
||
return { resolvedGraph: graphWithDefaults };
|
||
}
|
||
|
||
// 路徑 C:body 直接就是 graph
|
||
if (body.nodes && body.edges) {
|
||
const graphWithDefaults = {
|
||
id: `webhook-${Date.now()}`,
|
||
name: description || `Webhook ${new Date().toISOString()}`,
|
||
...body,
|
||
};
|
||
const parsed = graphSchema.safeParse(graphWithDefaults);
|
||
if (!parsed.success) {
|
||
return { resolvedGraph: {}, error: '圖定義驗證失敗' };
|
||
}
|
||
return { resolvedGraph: graphWithDefaults };
|
||
}
|
||
|
||
return { resolvedGraph: {}, error: '需提供 graph 物件或 triplets 陣列' };
|
||
}
|