@fieldwangai/agentflow 0.1.74 → 0.1.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/lib/locales/en.json +12 -0
- package/bin/lib/locales/zh.json +12 -0
- package/bin/lib/paths.mjs +4 -0
- package/bin/lib/ui-server.mjs +187 -34
- package/builtin/nodes/provide_password.md +13 -0
- package/builtin/nodes/tool_display_share_link.md +46 -0
- package/builtin/nodes/tool_set_run_env.md +37 -0
- package/builtin/web-ui/dist/assets/index-CcJdQ_Bw.css +1 -0
- package/builtin/web-ui/dist/assets/index-vPAmygSb.js +297 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-Z19bIbFa.js +0 -297
- package/builtin/web-ui/dist/assets/index-fQlSZjeW.css +0 -1
package/bin/lib/locales/en.json
CHANGED
|
@@ -297,6 +297,10 @@
|
|
|
297
297
|
"displayName": "WeCom App Markdown",
|
|
298
298
|
"description": "Send a Markdown message to users through a WeCom enterprise application"
|
|
299
299
|
},
|
|
300
|
+
"tool_display_share_link": {
|
|
301
|
+
"displayName": "Display Share Link",
|
|
302
|
+
"description": "Publish upstream Display nodes as a shareable link and output the URL"
|
|
303
|
+
},
|
|
300
304
|
"tool_nodejs": {
|
|
301
305
|
"displayName": "Node.js Script",
|
|
302
306
|
"description": "Execute Node.js script, success determined by exit code, stdout as result"
|
|
@@ -309,6 +313,10 @@
|
|
|
309
313
|
"displayName": "Get Env",
|
|
310
314
|
"description": "Get environment variable value"
|
|
311
315
|
},
|
|
316
|
+
"tool_set_run_env": {
|
|
317
|
+
"displayName": "Set Run Env",
|
|
318
|
+
"description": "Set temporary environment variables for downstream nodes in the current run"
|
|
319
|
+
},
|
|
312
320
|
"tool_save_key": {
|
|
313
321
|
"displayName": "Save Key",
|
|
314
322
|
"description": "Save key-value pair to global storage"
|
|
@@ -353,6 +361,10 @@
|
|
|
353
361
|
"displayName": "File",
|
|
354
362
|
"description": "Provide file path or content directly, value will be passed to downstream as-is"
|
|
355
363
|
},
|
|
364
|
+
"provide_password": {
|
|
365
|
+
"displayName": "Password",
|
|
366
|
+
"description": "Provide a password or secret text value without showing it on the node card"
|
|
367
|
+
},
|
|
356
368
|
"provide_bool": {
|
|
357
369
|
"displayName": "Boolean",
|
|
358
370
|
"description": "Provide a true/false boolean value directly to downstream bool pins"
|
package/bin/lib/locales/zh.json
CHANGED
|
@@ -297,6 +297,10 @@
|
|
|
297
297
|
"displayName": "企业微信应用 Markdown",
|
|
298
298
|
"description": "通过企业微信应用消息接口发送 Markdown 给用户"
|
|
299
299
|
},
|
|
300
|
+
"tool_display_share_link": {
|
|
301
|
+
"displayName": "展示分享链接",
|
|
302
|
+
"description": "将上游 Display 节点发布为可分享链接,并输出 URL"
|
|
303
|
+
},
|
|
300
304
|
"tool_nodejs": {
|
|
301
305
|
"displayName": "Node.js 脚本",
|
|
302
306
|
"description": "执行 Node.js 脚本,以 exit code 判断成败,stdout 作为结果"
|
|
@@ -309,6 +313,10 @@
|
|
|
309
313
|
"displayName": "获取环境变量",
|
|
310
314
|
"description": "获取环境变量值"
|
|
311
315
|
},
|
|
316
|
+
"tool_set_run_env": {
|
|
317
|
+
"displayName": "设置 Run Env",
|
|
318
|
+
"description": "为当前运行设置临时环境变量,只影响后续节点"
|
|
319
|
+
},
|
|
312
320
|
"tool_save_key": {
|
|
313
321
|
"displayName": "保存键值",
|
|
314
322
|
"description": "保存键值对到全局存储"
|
|
@@ -353,6 +361,10 @@
|
|
|
353
361
|
"displayName": "文件",
|
|
354
362
|
"description": "直接提供文件路径或内容,value 会原样供下游引用"
|
|
355
363
|
},
|
|
364
|
+
"provide_password": {
|
|
365
|
+
"displayName": "密码",
|
|
366
|
+
"description": "直接提供密码或密钥文本,默认不在节点卡片上展示"
|
|
367
|
+
},
|
|
356
368
|
"provide_bool": {
|
|
357
369
|
"displayName": "布尔",
|
|
358
370
|
"description": "直接提供 true/false 布尔值,value 会供下游 bool 引脚引用"
|
package/bin/lib/paths.mjs
CHANGED
|
@@ -332,11 +332,14 @@ export const LOCAL_ONLY_DEFINITION_IDS = new Set([
|
|
|
332
332
|
"tool_gitlab_create_mr",
|
|
333
333
|
"tool_wecom_send_group_markdown",
|
|
334
334
|
"tool_wecom_send_app_markdown",
|
|
335
|
+
"tool_display_share_link",
|
|
336
|
+
"tool_set_run_env",
|
|
335
337
|
"tool_print",
|
|
336
338
|
"tool_user_check",
|
|
337
339
|
"tool_user_ask",
|
|
338
340
|
"provide_str",
|
|
339
341
|
"provide_file",
|
|
342
|
+
"provide_password",
|
|
340
343
|
"provide_bool",
|
|
341
344
|
]);
|
|
342
345
|
|
|
@@ -347,5 +350,6 @@ export const LOCAL_ONLY_TERMINAL_SUCCESS_IDS = new Set([
|
|
|
347
350
|
"tool_print",
|
|
348
351
|
"provide_str",
|
|
349
352
|
"provide_file",
|
|
353
|
+
"provide_password",
|
|
350
354
|
"provide_bool",
|
|
351
355
|
]);
|
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -1249,8 +1249,11 @@ function sanitizeWorkspaceUploadName(filename) {
|
|
|
1249
1249
|
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
1250
1250
|
.replace(/^-+|-+$/g, "")
|
|
1251
1251
|
.slice(0, 80) || "image";
|
|
1252
|
-
const ext = String(parsed.ext || "")
|
|
1253
|
-
|
|
1252
|
+
const ext = String(parsed.ext || "")
|
|
1253
|
+
.toLowerCase()
|
|
1254
|
+
.replace(/[^a-z0-9.]+/g, "")
|
|
1255
|
+
.slice(0, 24);
|
|
1256
|
+
return `${stem}${ext}`;
|
|
1254
1257
|
}
|
|
1255
1258
|
|
|
1256
1259
|
function uniqueWorkspaceRelPath(workspaceRoot, relPath) {
|
|
@@ -1434,8 +1437,6 @@ function readWorkspaceFilesRecursive(dir, root, depth = 0, maxDepth = 3, budget
|
|
|
1434
1437
|
budget.count++;
|
|
1435
1438
|
} else if (entry.isFile()) {
|
|
1436
1439
|
if (WORKSPACE_FILE_SKIP_FILES.has(entry.name)) continue;
|
|
1437
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
1438
|
-
if (!WORKSPACE_TEXT_EXTS.has(ext) && !WORKSPACE_IMAGE_EXTS.has(ext)) continue;
|
|
1439
1440
|
let size = 0;
|
|
1440
1441
|
try { size = fs.statSync(abs).size; } catch {}
|
|
1441
1442
|
budget.count++;
|
|
@@ -1964,6 +1965,102 @@ function normalizeDisplayShareNodeIds(ids, graph) {
|
|
|
1964
1965
|
return out;
|
|
1965
1966
|
}
|
|
1966
1967
|
|
|
1968
|
+
function normalizeDisplayShareLayout(layout, fallback = "canvas") {
|
|
1969
|
+
const text = String(layout || "").trim();
|
|
1970
|
+
return ["canvas", "gallery", "slides", "document", "single"].includes(text) ? text : fallback;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function createDisplayShareRecord({ userId, flowId, flowSource, archived, title, layout, nodeIds }) {
|
|
1974
|
+
const shares = readDisplayShares();
|
|
1975
|
+
let id = createDisplayShareId();
|
|
1976
|
+
while (shares[id]) id = createDisplayShareId();
|
|
1977
|
+
const nowDate = new Date();
|
|
1978
|
+
const now = nowDate.toISOString();
|
|
1979
|
+
const share = {
|
|
1980
|
+
id,
|
|
1981
|
+
userId: String(userId || ""),
|
|
1982
|
+
flowId: String(flowId || ""),
|
|
1983
|
+
flowSource: String(flowSource || "user"),
|
|
1984
|
+
archived: archived === true,
|
|
1985
|
+
title: String(title || "").trim() || "AgentFlow Display",
|
|
1986
|
+
layout: normalizeDisplayShareLayout(layout, "canvas"),
|
|
1987
|
+
nodeIds: Array.isArray(nodeIds) ? nodeIds : [],
|
|
1988
|
+
createdAt: now,
|
|
1989
|
+
updatedAt: now,
|
|
1990
|
+
expiresAt: displayShareExpiresAt(nowDate),
|
|
1991
|
+
};
|
|
1992
|
+
shares[id] = share;
|
|
1993
|
+
writeDisplayShares(shares);
|
|
1994
|
+
return share;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
function parseDisplayShareNodeIdInput(value) {
|
|
1998
|
+
return String(value || "")
|
|
1999
|
+
.split(/[\s,,]+/g)
|
|
2000
|
+
.map((id) => id.trim())
|
|
2001
|
+
.filter(Boolean);
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
function inferUpstreamDisplayNodeIds(graph, nodeId) {
|
|
2005
|
+
const instances = graph?.instances && typeof graph.instances === "object" ? graph.instances : {};
|
|
2006
|
+
const edges = Array.isArray(graph?.edges) ? graph.edges : [];
|
|
2007
|
+
const ids = [];
|
|
2008
|
+
const seen = new Set();
|
|
2009
|
+
for (const edge of edges) {
|
|
2010
|
+
if (String(edge?.target || "") !== String(nodeId || "")) continue;
|
|
2011
|
+
const sourceId = String(edge?.source || "").trim();
|
|
2012
|
+
if (!sourceId || seen.has(sourceId)) continue;
|
|
2013
|
+
if (!workspaceDisplayKind(instances[sourceId]?.definitionId)) continue;
|
|
2014
|
+
seen.add(sourceId);
|
|
2015
|
+
ids.push(sourceId);
|
|
2016
|
+
}
|
|
2017
|
+
return ids;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
function displayShareOutputUrl(shareId, baseUrl = "") {
|
|
2021
|
+
const pathPart = `/display/${encodeURIComponent(String(shareId || ""))}`;
|
|
2022
|
+
const base = String(baseUrl || "").trim();
|
|
2023
|
+
if (!base) return pathPart;
|
|
2024
|
+
try {
|
|
2025
|
+
return new URL(pathPart, base.endsWith("/") ? base : `${base}/`).href;
|
|
2026
|
+
} catch {
|
|
2027
|
+
return pathPart;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
function normalizeRunEnvKey(key) {
|
|
2032
|
+
const text = String(key || "").trim();
|
|
2033
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(text) ? text : "";
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
function parseRunEnvAssignments(raw = "") {
|
|
2037
|
+
const text = String(raw || "").trim();
|
|
2038
|
+
if (!text) return {};
|
|
2039
|
+
if (text.startsWith("{")) {
|
|
2040
|
+
const parsed = JSON.parse(text);
|
|
2041
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Run Env JSON must be an object");
|
|
2042
|
+
const out = {};
|
|
2043
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
2044
|
+
const normalizedKey = normalizeRunEnvKey(key);
|
|
2045
|
+
if (!normalizedKey) throw new Error(`Invalid env key: ${key}`);
|
|
2046
|
+
out[normalizedKey] = String(value ?? "");
|
|
2047
|
+
}
|
|
2048
|
+
return out;
|
|
2049
|
+
}
|
|
2050
|
+
const out = {};
|
|
2051
|
+
for (const line of text.split(/\r?\n/g)) {
|
|
2052
|
+
const trimmed = line.trim();
|
|
2053
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
2054
|
+
const normalized = trimmed.replace(/^export\s+/i, "");
|
|
2055
|
+
const eq = normalized.indexOf("=");
|
|
2056
|
+
if (eq <= 0) throw new Error(`Invalid env assignment: ${trimmed}`);
|
|
2057
|
+
const key = normalizeRunEnvKey(normalized.slice(0, eq));
|
|
2058
|
+
if (!key) throw new Error(`Invalid env key: ${normalized.slice(0, eq).trim()}`);
|
|
2059
|
+
out[key] = normalized.slice(eq + 1);
|
|
2060
|
+
}
|
|
2061
|
+
return out;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1967
2064
|
function publicDisplayPayloadFromShare(root, share) {
|
|
1968
2065
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
1969
2066
|
flowId: share.flowId || "",
|
|
@@ -3341,7 +3438,7 @@ function workspaceEdgeHasCachedOutput(graph, edge, scopedRoot = "") {
|
|
|
3341
3438
|
}
|
|
3342
3439
|
const defId = String(source.definitionId || "");
|
|
3343
3440
|
if (workspaceDisplayKind(defId) && String(source.body || "").trim()) return true;
|
|
3344
|
-
if (defId === "provide_str" || defId === "provide_bool" || defId === "provide_file") {
|
|
3441
|
+
if (defId === "provide_str" || defId === "provide_bool" || defId === "provide_file" || defId === "provide_password") {
|
|
3345
3442
|
return Boolean(String(workspaceInstanceText(source) || "").trim());
|
|
3346
3443
|
}
|
|
3347
3444
|
return false;
|
|
@@ -4396,6 +4493,7 @@ async function workspaceRunToolNodejsScript({
|
|
|
4396
4493
|
inputValues,
|
|
4397
4494
|
runPackage,
|
|
4398
4495
|
userCtx,
|
|
4496
|
+
envOverlay = {},
|
|
4399
4497
|
emit,
|
|
4400
4498
|
}) {
|
|
4401
4499
|
const scriptRef = String(instance?.scriptRef || "").trim();
|
|
@@ -4431,6 +4529,7 @@ async function workspaceRunToolNodejsScript({
|
|
|
4431
4529
|
emit?.({ type: "status", line: `Run script: ${scriptRef || command.slice(0, 120)}` });
|
|
4432
4530
|
|
|
4433
4531
|
const env = runtimeEnvForUser(userCtx, {
|
|
4532
|
+
...envOverlay,
|
|
4434
4533
|
AGENTFLOW_WORKSPACE_ROOT: path.resolve(scopedRoot),
|
|
4435
4534
|
AGENTFLOW_NODE_RUN_DIR: runPackage.nodeRunDir,
|
|
4436
4535
|
AGENTFLOW_NODE_TMP_DIR: runPackage.nodeTmpDir,
|
|
@@ -4542,6 +4641,8 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4542
4641
|
};
|
|
4543
4642
|
let cwd = scopedRoot;
|
|
4544
4643
|
const modelKey = typeof payload?.model === "string" ? payload.model.trim() : "";
|
|
4644
|
+
const runEnv = {};
|
|
4645
|
+
const runtimeEnv = (extra = {}) => runtimeEnvForUser(userCtx, { ...runEnv, ...(extra || {}) });
|
|
4545
4646
|
const autoCleanupWorktrees = [];
|
|
4546
4647
|
const runTmpRoot = workspaceCreateRunTmpRoot(scopedRoot, runNodeId);
|
|
4547
4648
|
|
|
@@ -4606,7 +4707,7 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4606
4707
|
continue;
|
|
4607
4708
|
}
|
|
4608
4709
|
|
|
4609
|
-
if (defId === "provide_str") {
|
|
4710
|
+
if (defId === "provide_str" || defId === "provide_password") {
|
|
4610
4711
|
const content = workspaceInstanceText(instance);
|
|
4611
4712
|
outputs.set(nodeId, content);
|
|
4612
4713
|
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
@@ -4633,6 +4734,26 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4633
4734
|
continue;
|
|
4634
4735
|
}
|
|
4635
4736
|
|
|
4737
|
+
if (defId === "tool_set_run_env") {
|
|
4738
|
+
const inputValues = workspaceInputValues(graph, nodeId, outputs, scopedRoot);
|
|
4739
|
+
const assignments = {
|
|
4740
|
+
...parseRunEnvAssignments(inputValues.variables || workspaceSlotValue(workspaceSlotByName(instance, "variables"))),
|
|
4741
|
+
};
|
|
4742
|
+
const key = normalizeRunEnvKey(inputValues.key || workspaceSlotValue(workspaceSlotByName(instance, "key")));
|
|
4743
|
+
if (key) assignments[key] = String(inputValues.value ?? workspaceSlotValue(workspaceSlotByName(instance, "value")) ?? "");
|
|
4744
|
+
const keys = Object.keys(assignments);
|
|
4745
|
+
if (!keys.length) throw new Error("Set Run Env requires key/value or variables");
|
|
4746
|
+
Object.assign(runEnv, assignments);
|
|
4747
|
+
let nextInstance = workspaceSetOutputSlot(instance, "keys", keys.join(", "));
|
|
4748
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "count", String(keys.length));
|
|
4749
|
+
graph.instances[nodeId] = nextInstance;
|
|
4750
|
+
outputs.set(nodeId, keys.join(", "));
|
|
4751
|
+
emit({ type: "status", nodeId, line: `Set run env: ${keys.join(", ")}`, envKeys: keys });
|
|
4752
|
+
emit({ type: "graph", nodeId, graph });
|
|
4753
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
4754
|
+
continue;
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4636
4757
|
if (defId === "control_cd_workspace") {
|
|
4637
4758
|
const inputText = workspaceUpstreamText(graph, nodeId, outputs, scopedRoot);
|
|
4638
4759
|
const inputSlots = Array.isArray(instance.input) ? instance.input : [];
|
|
@@ -4829,7 +4950,7 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4829
4950
|
gitlabApiBase: workspaceSlotValue(workspaceSlotByName(instance, "gitlabApiBase")),
|
|
4830
4951
|
removeSourceBranch: workspaceSlotValue(workspaceSlotByName(instance, "removeSourceBranch")),
|
|
4831
4952
|
squash: workspaceSlotValue(workspaceSlotByName(instance, "squash")),
|
|
4832
|
-
},
|
|
4953
|
+
}, runtimeEnv());
|
|
4833
4954
|
let nextInstance = workspaceSetOutputSlot(instance, "mrUrl", result.mrUrl);
|
|
4834
4955
|
nextInstance = workspaceSetOutputSlot(nextInstance, "created", result.created ? "true" : "false");
|
|
4835
4956
|
nextInstance = workspaceSetOutputSlot(nextInstance, "mrIid", result.mrIid ?? "");
|
|
@@ -4856,12 +4977,12 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4856
4977
|
corpSecret: inputValues.corpSecret || workspaceSlotValue(workspaceSlotByName(instance, "corpSecret")),
|
|
4857
4978
|
agentId: inputValues.agentId || workspaceSlotValue(workspaceSlotByName(instance, "agentId")),
|
|
4858
4979
|
accessToken: inputValues.accessToken || workspaceSlotValue(workspaceSlotByName(instance, "accessToken")),
|
|
4859
|
-
},
|
|
4980
|
+
}, runtimeEnv())
|
|
4860
4981
|
: await sendWecomGroupMarkdown({
|
|
4861
4982
|
markdown,
|
|
4862
4983
|
webhookUrl: inputValues.webhookUrl || workspaceSlotValue(workspaceSlotByName(instance, "webhookUrl")),
|
|
4863
4984
|
webhookKey: inputValues.webhookKey || workspaceSlotValue(workspaceSlotByName(instance, "webhookKey")),
|
|
4864
|
-
},
|
|
4985
|
+
}, runtimeEnv());
|
|
4865
4986
|
let nextInstance = workspaceSetOutputSlot(instance, "sent", "true");
|
|
4866
4987
|
nextInstance = workspaceSetOutputSlot(nextInstance, "message", result.message);
|
|
4867
4988
|
nextInstance = workspaceSetOutputSlot(nextInstance, "response", JSON.stringify(result.response || {}));
|
|
@@ -4872,6 +4993,52 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4872
4993
|
continue;
|
|
4873
4994
|
}
|
|
4874
4995
|
|
|
4996
|
+
if (defId === "tool_display_share_link") {
|
|
4997
|
+
const inputValues = workspaceInputValues(graph, nodeId, outputs, scopedRoot);
|
|
4998
|
+
const explicitNodeIds = parseDisplayShareNodeIdInput(inputValues.nodeIds || workspaceSlotValue(workspaceSlotByName(instance, "nodeIds")));
|
|
4999
|
+
const inferredNodeIds = explicitNodeIds.length ? explicitNodeIds : inferUpstreamDisplayNodeIds(graph, nodeId);
|
|
5000
|
+
const nodeIds = normalizeDisplayShareNodeIds(inferredNodeIds, graph);
|
|
5001
|
+
if (nodeIds.length === 0) throw new Error("Display Share Link requires at least one connected display node or nodeIds input");
|
|
5002
|
+
|
|
5003
|
+
const layout = normalizeDisplayShareLayout(inputValues.layout || workspaceSlotValue(workspaceSlotByName(instance, "layout")), "single");
|
|
5004
|
+
const title = inputValues.title || workspaceSlotValue(workspaceSlotByName(instance, "title"));
|
|
5005
|
+
const env = runtimeEnv();
|
|
5006
|
+
const baseUrl = inputValues.baseUrl ||
|
|
5007
|
+
workspaceSlotValue(workspaceSlotByName(instance, "baseUrl")) ||
|
|
5008
|
+
env.AGENTFLOW_PUBLIC_BASE_URL ||
|
|
5009
|
+
env.AGENTFLOW_BASE_URL ||
|
|
5010
|
+
env.PUBLIC_BASE_URL ||
|
|
5011
|
+
"";
|
|
5012
|
+
|
|
5013
|
+
const graphPath = workspaceGraphPath(scopedRoot);
|
|
5014
|
+
try {
|
|
5015
|
+
const currentGraph = readWorkspaceGraph(scopedRoot).graph;
|
|
5016
|
+
const mergedGraph = mergeWorkspaceRunGraph(currentGraph, graph, new Set([nodeId, ...nodeIds]));
|
|
5017
|
+
fs.writeFileSync(graphPath, JSON.stringify(mergedGraph, null, 2) + "\n", "utf-8");
|
|
5018
|
+
} catch (e) {
|
|
5019
|
+
emit({ type: "natural", kind: "warning", text: `保存分享展示内容失败:${(e && e.message) || String(e)}` });
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
const share = createDisplayShareRecord({
|
|
5023
|
+
userId: userCtx.userId,
|
|
5024
|
+
flowId: payload.flowId || "",
|
|
5025
|
+
flowSource: payload.flowSource || "user",
|
|
5026
|
+
archived: payload.archived === true || payload.flowArchived === true,
|
|
5027
|
+
title,
|
|
5028
|
+
layout,
|
|
5029
|
+
nodeIds,
|
|
5030
|
+
});
|
|
5031
|
+
const url = displayShareOutputUrl(share.id, baseUrl);
|
|
5032
|
+
let nextInstance = workspaceSetOutputSlot(instance, "url", url);
|
|
5033
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "shareId", share.id);
|
|
5034
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "expiresAt", share.expiresAt);
|
|
5035
|
+
graph.instances[nodeId] = nextInstance;
|
|
5036
|
+
outputs.set(nodeId, url);
|
|
5037
|
+
emit({ type: "graph", nodeId, graph, displayNodeIds: nodeIds });
|
|
5038
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
5039
|
+
continue;
|
|
5040
|
+
}
|
|
5041
|
+
|
|
4875
5042
|
if (defId === "tool_nodejs") {
|
|
4876
5043
|
const prepareStartedAt = Date.now();
|
|
4877
5044
|
const inputValues = workspaceInputValues(graph, nodeId, outputs, scopedRoot);
|
|
@@ -4893,6 +5060,7 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4893
5060
|
inputValues: runtimeInputValues,
|
|
4894
5061
|
runPackage,
|
|
4895
5062
|
userCtx,
|
|
5063
|
+
envOverlay: runEnv,
|
|
4896
5064
|
emit: (event) => emit({ ...event, nodeId }),
|
|
4897
5065
|
});
|
|
4898
5066
|
const normalizedAgentOutput = workspacePublishAgentOutputFiles(workspaceStructuredAgentOutput(content), runPackage);
|
|
@@ -4974,12 +5142,12 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
4974
5142
|
prompt,
|
|
4975
5143
|
modelKey,
|
|
4976
5144
|
agentflowUserId: userCtx.userId || "",
|
|
4977
|
-
extraEnv: {
|
|
5145
|
+
extraEnv: runtimeEnv({
|
|
4978
5146
|
AGENTFLOW_WORKSPACE_TMP_ROOT: runTmpRoot,
|
|
4979
5147
|
AGENTFLOW_NODE_RUN_DIR: runPackage.nodeRunDir,
|
|
4980
5148
|
AGENTFLOW_NODE_TMP_DIR: runPackage.nodeTmpDir,
|
|
4981
5149
|
AGENTFLOW_OUTPUTS_DIR: runPackage.outputsDir,
|
|
4982
|
-
},
|
|
5150
|
+
}),
|
|
4983
5151
|
onStreamEvent: (ev) => {
|
|
4984
5152
|
if (!firstAgentEventSeen) {
|
|
4985
5153
|
firstAgentEventSeen = true;
|
|
@@ -6363,27 +6531,16 @@ export function startUiServer({
|
|
|
6363
6531
|
json(res, 400, { error: "请选择至少一个 display 节点" });
|
|
6364
6532
|
return;
|
|
6365
6533
|
}
|
|
6366
|
-
const
|
|
6367
|
-
let id = createDisplayShareId();
|
|
6368
|
-
while (shares[id]) id = createDisplayShareId();
|
|
6369
|
-
const nowDate = new Date();
|
|
6370
|
-
const now = nowDate.toISOString();
|
|
6371
|
-
const share = {
|
|
6372
|
-
id,
|
|
6534
|
+
const share = createDisplayShareRecord({
|
|
6373
6535
|
userId: authUser.userId,
|
|
6374
6536
|
flowId: scoped.flowId || "",
|
|
6375
6537
|
flowSource: scoped.flowSource || "user",
|
|
6376
6538
|
archived: scoped.archived === true,
|
|
6377
|
-
title:
|
|
6378
|
-
layout:
|
|
6539
|
+
title: payload.title,
|
|
6540
|
+
layout: payload.layout,
|
|
6379
6541
|
nodeIds,
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
expiresAt: displayShareExpiresAt(nowDate),
|
|
6383
|
-
};
|
|
6384
|
-
shares[id] = share;
|
|
6385
|
-
writeDisplayShares(shares);
|
|
6386
|
-
json(res, 200, { ok: true, share, url: `/display/${encodeURIComponent(id)}` });
|
|
6542
|
+
});
|
|
6543
|
+
json(res, 200, { ok: true, share, url: `/display/${encodeURIComponent(share.id)}` });
|
|
6387
6544
|
} catch (e) {
|
|
6388
6545
|
json(res, 500, { error: (e && e.message) || String(e) });
|
|
6389
6546
|
}
|
|
@@ -6897,13 +7054,9 @@ export function startUiServer({
|
|
|
6897
7054
|
return;
|
|
6898
7055
|
}
|
|
6899
7056
|
const safeName = sanitizeWorkspaceUploadName(parsed.filename);
|
|
6900
|
-
const
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
return;
|
|
6904
|
-
}
|
|
6905
|
-
const targetDir = String(parsed.fields.dir || "img").trim().replace(/^[/\\]+/, "") || "img";
|
|
6906
|
-
const target = uniqueWorkspaceRelPath(scoped.root, path.posix.join(targetDir.replace(/\\/g, "/"), safeName));
|
|
7057
|
+
const targetDir = String(parsed.fields.dir ?? "").trim().replace(/^[/\\]+/, "").replace(/\\/g, "/");
|
|
7058
|
+
const targetRel = targetDir ? path.posix.join(targetDir, safeName) : safeName;
|
|
7059
|
+
const target = uniqueWorkspaceRelPath(scoped.root, targetRel);
|
|
6907
7060
|
fs.mkdirSync(path.dirname(target.abs), { recursive: true });
|
|
6908
7061
|
fs.writeFileSync(target.abs, parsed.file);
|
|
6909
7062
|
json(res, 200, {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: directly provide a hidden password/secret value
|
|
3
|
+
description: Provide a secret text value without showing it on the node card
|
|
4
|
+
displayName: Password
|
|
5
|
+
input: []
|
|
6
|
+
output:
|
|
7
|
+
- type: text
|
|
8
|
+
name: value
|
|
9
|
+
default: ""
|
|
10
|
+
required: true
|
|
11
|
+
showOnNode: true
|
|
12
|
+
---
|
|
13
|
+
${USER_PROMPT}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: create share link for Display nodes
|
|
3
|
+
description: Create a public share link for upstream Display nodes
|
|
4
|
+
displayName: Display Share Link
|
|
5
|
+
input:
|
|
6
|
+
- type: node
|
|
7
|
+
name: prev
|
|
8
|
+
default: ""
|
|
9
|
+
- type: text
|
|
10
|
+
name: title
|
|
11
|
+
default: ""
|
|
12
|
+
description: "分享页标题;为空时使用 AgentFlow Display。"
|
|
13
|
+
showOnNode: true
|
|
14
|
+
- type: text
|
|
15
|
+
name: layout
|
|
16
|
+
default: "single"
|
|
17
|
+
description: "分享布局:single、gallery、slides、document、canvas。"
|
|
18
|
+
showOnNode: true
|
|
19
|
+
- type: text
|
|
20
|
+
name: nodeIds
|
|
21
|
+
default: ""
|
|
22
|
+
description: "可选。逗号或空格分隔的 Display 节点 ID;为空时自动使用连接到本节点的上游 Display 节点。"
|
|
23
|
+
showOnNode: false
|
|
24
|
+
- type: text
|
|
25
|
+
name: baseUrl
|
|
26
|
+
default: ""
|
|
27
|
+
description: "可选。输出绝对链接的站点地址,例如 https://agentflow.example.com;为空时输出 /display/<id>。"
|
|
28
|
+
showOnNode: false
|
|
29
|
+
output:
|
|
30
|
+
- type: node
|
|
31
|
+
name: next
|
|
32
|
+
default: ""
|
|
33
|
+
- type: text
|
|
34
|
+
name: url
|
|
35
|
+
default: ""
|
|
36
|
+
showOnNode: true
|
|
37
|
+
- type: text
|
|
38
|
+
name: shareId
|
|
39
|
+
default: ""
|
|
40
|
+
showOnNode: false
|
|
41
|
+
- type: text
|
|
42
|
+
name: expiresAt
|
|
43
|
+
default: ""
|
|
44
|
+
showOnNode: false
|
|
45
|
+
---
|
|
46
|
+
Create a share link for connected Display nodes.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: set environment variables for the current run only
|
|
3
|
+
description: Set environment variables for downstream nodes in the current workspace run
|
|
4
|
+
displayName: Set Run Env
|
|
5
|
+
input:
|
|
6
|
+
- type: node
|
|
7
|
+
name: prev
|
|
8
|
+
default: ""
|
|
9
|
+
- type: text
|
|
10
|
+
name: key
|
|
11
|
+
default: ""
|
|
12
|
+
description: "单个环境变量名,例如 IMAP_USER。"
|
|
13
|
+
showOnNode: true
|
|
14
|
+
- type: text
|
|
15
|
+
name: value
|
|
16
|
+
default: ""
|
|
17
|
+
description: "单个环境变量值。"
|
|
18
|
+
showOnNode: true
|
|
19
|
+
- type: text
|
|
20
|
+
name: variables
|
|
21
|
+
default: ""
|
|
22
|
+
description: "批量设置,支持多行 KEY=VALUE 或 JSON object。"
|
|
23
|
+
showOnNode: false
|
|
24
|
+
output:
|
|
25
|
+
- type: node
|
|
26
|
+
name: next
|
|
27
|
+
default: ""
|
|
28
|
+
- type: text
|
|
29
|
+
name: keys
|
|
30
|
+
default: ""
|
|
31
|
+
showOnNode: false
|
|
32
|
+
- type: text
|
|
33
|
+
name: count
|
|
34
|
+
default: ""
|
|
35
|
+
showOnNode: false
|
|
36
|
+
---
|
|
37
|
+
Set environment variables for downstream nodes in this run only.
|