@fieldwangai/agentflow 0.1.90 → 0.1.92
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/ui-server.mjs +264 -16
- package/builtin/nodes/agent_subAgent.md +6 -1
- package/builtin/nodes/control_cd_workspace.md +22 -13
- package/builtin/web-ui/dist/assets/index-CSBbCP8S.css +1 -0
- package/builtin/web-ui/dist/assets/index-Dk3al84f.js +341 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-B-cW34KG.js +0 -340
- package/builtin/web-ui/dist/assets/index-CWJ7Mp9B.css +0 -1
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -2980,6 +2980,114 @@ function resolveWorkspaceScopeRoot(workspaceRoot, params = {}, opts = {}) {
|
|
|
2980
2980
|
return { root: path.resolve(result.path), flowId, flowSource, archived };
|
|
2981
2981
|
}
|
|
2982
2982
|
|
|
2983
|
+
function workspaceConversationsPath(scopedRoot) {
|
|
2984
|
+
return path.join(path.resolve(scopedRoot), ".workspace", "agentflow", "conversations.json");
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
function workspaceConversationText(value, max = 4000) {
|
|
2988
|
+
const text = String(value ?? "").trim();
|
|
2989
|
+
if (!text) return "";
|
|
2990
|
+
return text.length > max ? `${text.slice(0, max)}\n...[truncated ${text.length - max} chars]` : text;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
function normalizeWorkspaceConversationMessage(message = {}) {
|
|
2994
|
+
const text = workspaceConversationText(message?.text, 4000);
|
|
2995
|
+
if (!text) return null;
|
|
2996
|
+
const role = String(message?.role || "assistant").trim() === "user" ? "user" : "assistant";
|
|
2997
|
+
const kind = String(message?.kind || "").trim();
|
|
2998
|
+
return {
|
|
2999
|
+
role,
|
|
3000
|
+
...(kind ? { kind } : {}),
|
|
3001
|
+
text,
|
|
3002
|
+
...(message?.error ? { error: true } : {}),
|
|
3003
|
+
at: Number.isFinite(Number(message?.at)) ? Number(message.at) : Date.now(),
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
function normalizeWorkspaceConversationMessages(messages, limit = 80) {
|
|
3008
|
+
return (Array.isArray(messages) ? messages : [])
|
|
3009
|
+
.map(normalizeWorkspaceConversationMessage)
|
|
3010
|
+
.filter(Boolean)
|
|
3011
|
+
.slice(-limit);
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
function normalizeWorkspaceNodeChatSessions(nodeChats = {}) {
|
|
3015
|
+
const source = nodeChats && typeof nodeChats === "object" && !Array.isArray(nodeChats) ? nodeChats : {};
|
|
3016
|
+
const entries = Object.entries(source).slice(-80);
|
|
3017
|
+
const next = {};
|
|
3018
|
+
for (const [nodeId, session] of entries) {
|
|
3019
|
+
if (!session || typeof session !== "object" || Array.isArray(session)) continue;
|
|
3020
|
+
const id = String(nodeId || "").trim();
|
|
3021
|
+
if (!id) continue;
|
|
3022
|
+
const messages = normalizeWorkspaceConversationMessages(session.messages, 40);
|
|
3023
|
+
const draft = workspaceConversationText(session.draft || "", 2000);
|
|
3024
|
+
if (!messages.length && !draft) continue;
|
|
3025
|
+
next[id] = {
|
|
3026
|
+
sessionId: String(session.sessionId || `nodechat_${id}`).trim(),
|
|
3027
|
+
messages,
|
|
3028
|
+
...(draft ? { draft } : {}),
|
|
3029
|
+
candidateContent: "",
|
|
3030
|
+
running: false,
|
|
3031
|
+
error: "",
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
return next;
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
function normalizeWorkspaceComposerRunSessions(sessions = []) {
|
|
3038
|
+
return (Array.isArray(sessions) ? sessions : [])
|
|
3039
|
+
.map((session) => {
|
|
3040
|
+
if (!session || typeof session !== "object" || Array.isArray(session)) return null;
|
|
3041
|
+
const id = String(session.id || "").trim();
|
|
3042
|
+
if (!id) return null;
|
|
3043
|
+
const messages = normalizeWorkspaceConversationMessages(session.messages, 80);
|
|
3044
|
+
if (!messages.length) return null;
|
|
3045
|
+
const status = String(session.status || "done").trim();
|
|
3046
|
+
return {
|
|
3047
|
+
id,
|
|
3048
|
+
label: workspaceConversationText(session.label || id, 120),
|
|
3049
|
+
status: status === "failed" ? "failed" : "done",
|
|
3050
|
+
messages,
|
|
3051
|
+
};
|
|
3052
|
+
})
|
|
3053
|
+
.filter(Boolean)
|
|
3054
|
+
.slice(-20);
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
function normalizeWorkspaceConversations(raw = {}) {
|
|
3058
|
+
const data = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
3059
|
+
const composer = data.composer && typeof data.composer === "object" && !Array.isArray(data.composer) ? data.composer : {};
|
|
3060
|
+
const activeSessionId = String(composer.activeSessionId || "workspace").trim() || "workspace";
|
|
3061
|
+
return {
|
|
3062
|
+
version: 1,
|
|
3063
|
+
updatedAt: new Date().toISOString(),
|
|
3064
|
+
composer: {
|
|
3065
|
+
activeSessionId,
|
|
3066
|
+
messages: normalizeWorkspaceConversationMessages(composer.messages, 100),
|
|
3067
|
+
runSessions: normalizeWorkspaceComposerRunSessions(composer.runSessions),
|
|
3068
|
+
},
|
|
3069
|
+
nodeChats: normalizeWorkspaceNodeChatSessions(data.nodeChats),
|
|
3070
|
+
};
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
function readWorkspaceConversations(scopedRoot) {
|
|
3074
|
+
const filePath = workspaceConversationsPath(scopedRoot);
|
|
3075
|
+
if (!fs.existsSync(filePath)) return normalizeWorkspaceConversations({});
|
|
3076
|
+
try {
|
|
3077
|
+
return normalizeWorkspaceConversations(JSON.parse(fs.readFileSync(filePath, "utf-8")));
|
|
3078
|
+
} catch {
|
|
3079
|
+
return normalizeWorkspaceConversations({});
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
function writeWorkspaceConversations(scopedRoot, raw) {
|
|
3084
|
+
const filePath = workspaceConversationsPath(scopedRoot);
|
|
3085
|
+
const conversations = normalizeWorkspaceConversations(raw);
|
|
3086
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
3087
|
+
fs.writeFileSync(filePath, JSON.stringify(conversations, null, 2) + "\n", "utf-8");
|
|
3088
|
+
return conversations;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
2983
3091
|
function workspaceSearchGuardrailsBlock() {
|
|
2984
3092
|
return [
|
|
2985
3093
|
"## 检索约束",
|
|
@@ -4153,7 +4261,7 @@ function workspaceTargetSlotForEdge(graph, edge) {
|
|
|
4153
4261
|
function isWorkspaceSemanticInputSlot(slot) {
|
|
4154
4262
|
const name = String(slot?.name || "");
|
|
4155
4263
|
const type = String(slot?.type || "");
|
|
4156
|
-
return type === "node" || name === "prev" || name === "next" || name === "skillsContext" || name === "mcpContext" || name === "workspaceContext" || name === "gitContext";
|
|
4264
|
+
return type === "node" || name === "prev" || name === "next" || name === "skillsContext" || name === "mcpContext" || name === "knowledgeContext" || name === "workspaceContext" || name === "gitContext";
|
|
4157
4265
|
}
|
|
4158
4266
|
|
|
4159
4267
|
function workspaceAgentInputBlock(inputValues = {}, inputMounts = {}) {
|
|
@@ -4986,11 +5094,86 @@ function workspaceContextObjectFromText(text, baseCwd, scopedRoot) {
|
|
|
4986
5094
|
};
|
|
4987
5095
|
}
|
|
4988
5096
|
|
|
5097
|
+
function workspaceKnowledgeSourceFromObject(source = {}, baseCwd = "", scopedRoot = "") {
|
|
5098
|
+
if (!source || typeof source !== "object" || Array.isArray(source)) return null;
|
|
5099
|
+
const rawPath = String(source.path || source.repoPath || source.cwd || source.workspaceRoot || "").trim();
|
|
5100
|
+
if (!rawPath) return null;
|
|
5101
|
+
const resolvedPath = workspaceResolvePath(baseCwd || scopedRoot, rawPath) || rawPath;
|
|
5102
|
+
return {
|
|
5103
|
+
id: String(source.id || source.mountPath || source.label || path.basename(resolvedPath) || "").trim(),
|
|
5104
|
+
label: String(source.label || source.id || source.mountPath || path.basename(resolvedPath) || "知识库").trim(),
|
|
5105
|
+
kind: String(source.kind || (source.repoUrl ? "git" : "local")).trim() || "local",
|
|
5106
|
+
type: String(source.type || "").trim(),
|
|
5107
|
+
path: resolvedPath,
|
|
5108
|
+
repoPath: resolvedPath,
|
|
5109
|
+
mountPath: String(source.mountPath || "").trim(),
|
|
5110
|
+
repoUrl: String(source.repoUrl || "").trim(),
|
|
5111
|
+
branch: String(source.branch || "").trim(),
|
|
5112
|
+
readonly: source.readonly !== false,
|
|
5113
|
+
};
|
|
5114
|
+
}
|
|
5115
|
+
|
|
5116
|
+
function workspaceKnowledgeSourcesFromText(text, baseCwd = "", scopedRoot = "") {
|
|
5117
|
+
const raw = String(text || "").trim();
|
|
5118
|
+
if (!raw) return [];
|
|
5119
|
+
const parsed = parseJsonText(raw, null);
|
|
5120
|
+
const candidates = Array.isArray(parsed)
|
|
5121
|
+
? parsed
|
|
5122
|
+
: (parsed && typeof parsed === "object" && Array.isArray(parsed.sources)
|
|
5123
|
+
? parsed.sources
|
|
5124
|
+
: (parsed && typeof parsed === "object" && (parsed.path || parsed.repoPath || parsed.cwd || parsed.workspaceRoot) ? [parsed] : []));
|
|
5125
|
+
if (candidates.length) {
|
|
5126
|
+
return candidates
|
|
5127
|
+
.map((source) => workspaceKnowledgeSourceFromObject(source, baseCwd, scopedRoot))
|
|
5128
|
+
.filter(Boolean);
|
|
5129
|
+
}
|
|
5130
|
+
const resolved = workspaceResolvePath(baseCwd || scopedRoot, raw) || raw;
|
|
5131
|
+
return [{
|
|
5132
|
+
id: path.basename(resolved) || "knowledge",
|
|
5133
|
+
label: path.basename(resolved) || "知识库",
|
|
5134
|
+
kind: "local",
|
|
5135
|
+
type: "",
|
|
5136
|
+
path: resolved,
|
|
5137
|
+
repoPath: resolved,
|
|
5138
|
+
mountPath: "",
|
|
5139
|
+
repoUrl: "",
|
|
5140
|
+
branch: "",
|
|
5141
|
+
readonly: true,
|
|
5142
|
+
}];
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5145
|
+
function workspaceKnowledgeContextBlockFromSources(sources = []) {
|
|
5146
|
+
const valid = Array.isArray(sources) ? sources.filter((source) => source?.path || source?.repoPath) : [];
|
|
5147
|
+
if (!valid.length) return "";
|
|
5148
|
+
const lines = [
|
|
5149
|
+
"## 知识库上下文",
|
|
5150
|
+
"",
|
|
5151
|
+
"这些路径是只读知识库/上下文源,用于检索、阅读和分析;它们不代表当前执行 cwd。需要修改代码时,请先创建或使用可写工作区。",
|
|
5152
|
+
"",
|
|
5153
|
+
];
|
|
5154
|
+
valid.forEach((source, index) => {
|
|
5155
|
+
const label = String(source.label || source.id || source.mountPath || `知识库 ${index + 1}`).trim();
|
|
5156
|
+
const sourcePath = String(source.path || source.repoPath || "").trim();
|
|
5157
|
+
lines.push(`${index + 1}. ${label}`);
|
|
5158
|
+
if (source.kind) lines.push(` - 类型:${source.kind}${source.type ? `/${source.type}` : ""}`);
|
|
5159
|
+
if (sourcePath) lines.push(` - 路径:\`${sourcePath}\``);
|
|
5160
|
+
if (source.mountPath) lines.push(` - 挂载目录:${source.mountPath}`);
|
|
5161
|
+
if (source.repoUrl) lines.push(` - Git URL:${source.repoUrl}`);
|
|
5162
|
+
if (source.branch) lines.push(` - 分支:${source.branch}`);
|
|
5163
|
+
});
|
|
5164
|
+
return lines.join("\n");
|
|
5165
|
+
}
|
|
5166
|
+
|
|
4989
5167
|
function workspaceNodeWorkspaceContextBlock(graph, nodeId, outputs, scopedRoot = "", logicalCwd = "") {
|
|
4990
5168
|
const root = scopedRoot ? path.resolve(scopedRoot) : "";
|
|
4991
5169
|
const cwd = logicalCwd ? path.resolve(logicalCwd) : root;
|
|
5170
|
+
const knowledgeText = workspaceSemanticInputText(graph, nodeId, outputs, "knowledgeContext", scopedRoot);
|
|
5171
|
+
let knowledgeSources = workspaceKnowledgeSourcesFromText(knowledgeText, cwd || root, scopedRoot);
|
|
4992
5172
|
const workspaceText = workspaceSemanticInputText(graph, nodeId, outputs, "workspaceContext", scopedRoot);
|
|
4993
5173
|
let workspaceContext = workspaceContextObjectFromText(workspaceText, cwd || root, scopedRoot);
|
|
5174
|
+
if (!knowledgeSources.length && workspaceContext?.cwd) {
|
|
5175
|
+
knowledgeSources = workspaceKnowledgeSourcesFromText(JSON.stringify([workspaceContext]), cwd || root, scopedRoot);
|
|
5176
|
+
}
|
|
4994
5177
|
if (!workspaceContext && cwd && root && cwd !== root) {
|
|
4995
5178
|
workspaceContext = {
|
|
4996
5179
|
version: 1,
|
|
@@ -5002,7 +5185,8 @@ function workspaceNodeWorkspaceContextBlock(graph, nodeId, outputs, scopedRoot =
|
|
|
5002
5185
|
};
|
|
5003
5186
|
}
|
|
5004
5187
|
const gitContext = normalizeGitContext(workspaceSemanticInputText(graph, nodeId, outputs, "gitContext", scopedRoot));
|
|
5005
|
-
|
|
5188
|
+
const knowledgeBlock = workspaceKnowledgeContextBlockFromSources(knowledgeSources);
|
|
5189
|
+
if (!workspaceContext && !gitContext) return knowledgeBlock;
|
|
5006
5190
|
|
|
5007
5191
|
const contextCwd = workspaceContext?.cwd ? path.resolve(String(workspaceContext.cwd)) : "";
|
|
5008
5192
|
const workspaceRoot = workspaceContext?.workspaceRoot ? path.resolve(String(workspaceContext.workspaceRoot)) : contextCwd;
|
|
@@ -5025,7 +5209,7 @@ function workspaceNodeWorkspaceContextBlock(graph, nodeId, outputs, scopedRoot =
|
|
|
5025
5209
|
"- 读取、搜索、分析当前项目或资料时,优先从“当前工作目录上下文”开始;不要把节点的“当前执行目录”误认为项目根目录。",
|
|
5026
5210
|
"- 临时文件和正式产物仍必须按“文件边界”写入本节点的 `tmp/` 与 `outputs/`。",
|
|
5027
5211
|
].filter((line) => line !== "");
|
|
5028
|
-
return lines.join("\n");
|
|
5212
|
+
return [knowledgeBlock, lines.join("\n")].filter(Boolean).join("\n\n");
|
|
5029
5213
|
}
|
|
5030
5214
|
|
|
5031
5215
|
function workspaceDefaultWorkspaceContextBlock(scopedRoot = "", logicalCwd = "") {
|
|
@@ -5813,28 +5997,51 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
5813
5997
|
const pathSlot = inputSlots.find((slot) => String(slot?.name || "") === "path") ||
|
|
5814
5998
|
inputSlots.find((slot) => String(slot?.name || "") === "target");
|
|
5815
5999
|
const labelSlot = inputSlots.find((slot) => String(slot?.name || "") === "label");
|
|
6000
|
+
const knowledgeSlot = inputSlots.find((slot) => String(slot?.name || "") === "knowledgeContext");
|
|
5816
6001
|
const contextSlot = inputSlots.find((slot) => String(slot?.name || "") === "workspaceContext");
|
|
6002
|
+
const knowledgeText = workspaceSlotValue(knowledgeSlot);
|
|
6003
|
+
let knowledgeSources = workspaceKnowledgeSourcesFromText(knowledgeText, cwd || scopedRoot, scopedRoot);
|
|
5817
6004
|
const candidate = workspaceSlotValue(pathSlot) || workspaceInstanceText(instance) || inputText;
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
6005
|
+
if (!knowledgeSources.length && candidate) {
|
|
6006
|
+
const abs = path.resolve(scopedRoot, candidate);
|
|
6007
|
+
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
|
|
6008
|
+
throw new Error(`Load Knowledge path does not exist or is not a directory: ${abs}`);
|
|
6009
|
+
}
|
|
6010
|
+
knowledgeSources = [{
|
|
6011
|
+
id: path.basename(abs) || "knowledge",
|
|
6012
|
+
label: workspaceSlotValue(labelSlot) || path.basename(abs) || "知识库",
|
|
6013
|
+
kind: "local",
|
|
6014
|
+
type: "",
|
|
6015
|
+
path: abs,
|
|
6016
|
+
repoPath: abs,
|
|
6017
|
+
mountPath: "",
|
|
6018
|
+
repoUrl: "",
|
|
6019
|
+
branch: "",
|
|
6020
|
+
readonly: true,
|
|
6021
|
+
}];
|
|
5821
6022
|
}
|
|
5822
|
-
cwd = abs;
|
|
5823
6023
|
const parsedContext = parseJsonText(workspaceSlotValue(contextSlot), {});
|
|
5824
6024
|
const configuredContext = parsedContext && typeof parsedContext === "object" && !Array.isArray(parsedContext) ? parsedContext : {};
|
|
5825
|
-
const
|
|
6025
|
+
const primarySource = knowledgeSources[0] || null;
|
|
6026
|
+
const primaryPath = primarySource?.path ? path.resolve(String(primarySource.path)) : "";
|
|
6027
|
+
const knowledgeContext = {
|
|
6028
|
+
version: 1,
|
|
6029
|
+
sources: knowledgeSources,
|
|
6030
|
+
};
|
|
6031
|
+
const workspaceContext = primarySource ? {
|
|
5826
6032
|
...configuredContext,
|
|
5827
6033
|
version: 1,
|
|
5828
|
-
label: workspaceSlotValue(labelSlot) || path.basename(
|
|
5829
|
-
cwd,
|
|
5830
|
-
workspaceRoot:
|
|
6034
|
+
label: primarySource.label || workspaceSlotValue(labelSlot) || path.basename(primaryPath) || "知识库",
|
|
6035
|
+
cwd: primaryPath,
|
|
6036
|
+
workspaceRoot: primaryPath,
|
|
5831
6037
|
pipelineWorkspace: path.resolve(scopedRoot),
|
|
5832
6038
|
previous: null,
|
|
5833
|
-
};
|
|
5834
|
-
let nextInstance = workspaceSetOutputSlot(instance, "
|
|
5835
|
-
nextInstance = workspaceSetOutputSlot(nextInstance, "
|
|
6039
|
+
} : null;
|
|
6040
|
+
let nextInstance = workspaceSetOutputSlot(instance, "knowledgeContext", JSON.stringify(knowledgeContext));
|
|
6041
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", workspaceContext ? JSON.stringify(workspaceContext) : "");
|
|
6042
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "cwd", primaryPath);
|
|
5836
6043
|
graph.instances[nodeId] = nextInstance;
|
|
5837
|
-
publishNodeOutput(nodeId, JSON.stringify(
|
|
6044
|
+
publishNodeOutput(nodeId, JSON.stringify(knowledgeContext), { emitGraph: true });
|
|
5838
6045
|
emit({ type: "graph", nodeId, graph });
|
|
5839
6046
|
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
5840
6047
|
continue;
|
|
@@ -6207,7 +6414,7 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
6207
6414
|
}
|
|
6208
6415
|
const historyBlock = workspaceNodeHistoryBlock(nodeId, scopedRoot, runPackage);
|
|
6209
6416
|
let workspaceContextBlock = workspaceNodeWorkspaceContextBlock(graph, nodeId, outputs, scopedRoot, cwd);
|
|
6210
|
-
if (isContextRunNode && workspaceBoolSlot(instance, "includeWorkspaceContext", true) && !workspaceContextBlock) {
|
|
6417
|
+
if (!isContextRunNode && workspaceBoolSlot(instance, "includeWorkspaceContext", true) && !workspaceContextBlock) {
|
|
6211
6418
|
workspaceContextBlock = workspaceDefaultWorkspaceContextBlock(scopedRoot, cwd);
|
|
6212
6419
|
}
|
|
6213
6420
|
const prompt = workspaceNodePrompt(graph, nodeId, promptUpstreamText, promptSkillsBlock, promptMcpBlock, runtimeInputValues, runPackage, historyBlock, workspaceContextBlock);
|
|
@@ -8710,6 +8917,47 @@ export function startUiServer({
|
|
|
8710
8917
|
return;
|
|
8711
8918
|
}
|
|
8712
8919
|
|
|
8920
|
+
if (url.pathname === "/api/workspace/conversations") {
|
|
8921
|
+
let payload = {};
|
|
8922
|
+
if (req.method === "POST") {
|
|
8923
|
+
try {
|
|
8924
|
+
payload = JSON.parse(await readBody(req));
|
|
8925
|
+
} catch {
|
|
8926
|
+
json(res, 400, { error: "Invalid JSON body" });
|
|
8927
|
+
return;
|
|
8928
|
+
}
|
|
8929
|
+
} else if (req.method !== "GET") {
|
|
8930
|
+
json(res, 405, { error: "Method not allowed" });
|
|
8931
|
+
return;
|
|
8932
|
+
}
|
|
8933
|
+
try {
|
|
8934
|
+
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
8935
|
+
flowId: req.method === "POST" ? (payload.flowId || "") : (url.searchParams.get("flowId") || ""),
|
|
8936
|
+
flowSource: req.method === "POST" ? (payload.flowSource || "user") : (url.searchParams.get("flowSource") || "user"),
|
|
8937
|
+
archived: req.method === "POST"
|
|
8938
|
+
? (payload.archived === true || payload.flowArchived === true)
|
|
8939
|
+
: (url.searchParams.get("archived") === "1" || url.searchParams.get("flowArchived") === "1"),
|
|
8940
|
+
}, userCtx);
|
|
8941
|
+
if (scoped.error) {
|
|
8942
|
+
json(res, 400, { error: scoped.error });
|
|
8943
|
+
return;
|
|
8944
|
+
}
|
|
8945
|
+
if (req.method === "GET") {
|
|
8946
|
+
json(res, 200, { ok: true, conversations: readWorkspaceConversations(scoped.root) });
|
|
8947
|
+
return;
|
|
8948
|
+
}
|
|
8949
|
+
if (scoped.archived || isReadonlyBuiltinFlowSource(scoped.flowSource)) {
|
|
8950
|
+
json(res, 400, { error: "Cannot write conversations for builtin or archived pipeline workspace" });
|
|
8951
|
+
return;
|
|
8952
|
+
}
|
|
8953
|
+
const conversations = writeWorkspaceConversations(scoped.root, payload.conversations || payload);
|
|
8954
|
+
json(res, 200, { ok: true, conversations });
|
|
8955
|
+
} catch (e) {
|
|
8956
|
+
json(res, 500, { error: (e && e.message) || String(e) });
|
|
8957
|
+
}
|
|
8958
|
+
return;
|
|
8959
|
+
}
|
|
8960
|
+
|
|
8713
8961
|
if (req.method === "POST" && url.pathname === "/api/workspace/generate") {
|
|
8714
8962
|
let payload;
|
|
8715
8963
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
# 内置节点:子 Agent
|
|
3
|
-
description: 利用子 Agent 执行任务;可接收 workspaceContext 切换执行工作区,并接收 skillsContext / mcpContext 注入已加载 skills 与 MCP 工具清单。
|
|
3
|
+
description: 利用子 Agent 执行任务;可接收 knowledgeContext 读取知识库,可接收 workspaceContext 切换执行工作区,并接收 skillsContext / mcpContext 注入已加载 skills 与 MCP 工具清单。
|
|
4
4
|
displayName: 子 Agent
|
|
5
5
|
input:
|
|
6
6
|
- type: node
|
|
@@ -12,9 +12,14 @@ input:
|
|
|
12
12
|
- type: text
|
|
13
13
|
name: skillsContext
|
|
14
14
|
default: ""
|
|
15
|
+
showOnNode: true
|
|
15
16
|
- type: text
|
|
16
17
|
name: mcpContext
|
|
17
18
|
default: ""
|
|
19
|
+
- type: text
|
|
20
|
+
name: knowledgeContext
|
|
21
|
+
default: ""
|
|
22
|
+
showOnNode: true
|
|
18
23
|
output:
|
|
19
24
|
- type: node
|
|
20
25
|
name: next
|
|
@@ -1,47 +1,56 @@
|
|
|
1
1
|
---
|
|
2
|
-
#
|
|
2
|
+
# 内置节点:加载知识库
|
|
3
3
|
description: |
|
|
4
|
-
|
|
4
|
+
Load one or more read-only knowledge sources for downstream Agent nodes.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
`path` supports `${workspaceRoot}`, `${pipelineWorkspace}`, `${flowDir}`, absolute paths, and paths relative to the input workspace context.
|
|
12
|
-
displayName: CD Workspace
|
|
6
|
+
This node does not change the runtime cwd. It publishes `knowledgeContext`
|
|
7
|
+
for reading/searching referenced repos or folders. `workspaceContext` and
|
|
8
|
+
`cwd` are retained as legacy compatibility outputs for the first source.
|
|
9
|
+
displayName: 加载知识库
|
|
13
10
|
input:
|
|
14
11
|
- type: node
|
|
15
12
|
name: prev
|
|
16
13
|
default: ""
|
|
14
|
+
- type: text
|
|
15
|
+
name: knowledgeContext
|
|
16
|
+
default: ""
|
|
17
|
+
showOnNode: false
|
|
17
18
|
- type: text
|
|
18
19
|
name: path
|
|
19
20
|
default: ""
|
|
20
|
-
|
|
21
|
-
showOnNode: true
|
|
21
|
+
showOnNode: false
|
|
22
22
|
- type: text
|
|
23
23
|
name: mode
|
|
24
24
|
default: "set"
|
|
25
|
+
showOnNode: false
|
|
25
26
|
- type: text
|
|
26
27
|
name: label
|
|
27
28
|
default: ""
|
|
29
|
+
showOnNode: false
|
|
28
30
|
- type: text
|
|
29
31
|
name: workspaceContext
|
|
30
32
|
default: ""
|
|
33
|
+
showOnNode: false
|
|
31
34
|
output:
|
|
32
35
|
- type: node
|
|
33
36
|
name: next
|
|
34
37
|
default: ""
|
|
35
38
|
- type: text
|
|
36
|
-
name:
|
|
39
|
+
name: knowledgeContext
|
|
37
40
|
default: ""
|
|
38
41
|
required: true
|
|
39
42
|
showOnNode: true
|
|
43
|
+
- type: text
|
|
44
|
+
name: workspaceContext
|
|
45
|
+
default: ""
|
|
46
|
+
showOnNode: false
|
|
40
47
|
- type: file
|
|
41
48
|
name: cwd
|
|
42
49
|
default: ""
|
|
50
|
+
showOnNode: false
|
|
43
51
|
- type: text
|
|
44
52
|
name: previous
|
|
45
53
|
default: ""
|
|
54
|
+
showOnNode: false
|
|
46
55
|
---
|
|
47
|
-
|
|
56
|
+
Load selected knowledge sources for downstream agents.
|