@fieldwangai/agentflow 0.1.76 → 0.1.78

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.
@@ -66,6 +66,7 @@ import {
66
66
  import { clearSkillRegistryCache } from "./skill-registry.mjs";
67
67
  import { COMPOSER_NODE_SPEC_FILENAME } from "./composer-planner.mjs";
68
68
  import { listRecentRunsFromDisk } from "./recent-runs.mjs";
69
+ import { parseBool } from "../pipeline/parse-bool.mjs";
69
70
  import {
70
71
  unzipAndNormalizePipelineZip,
71
72
  validateImportedFlowYaml,
@@ -3421,6 +3422,13 @@ function workspaceIsControlEdge(graph, edge) {
3421
3422
  workspaceIsControlInputSlot(workspaceTargetSlotForEdge(graph, edge));
3422
3423
  }
3423
3424
 
3425
+ function workspaceControlIfBranchToSourceHandle(branch) {
3426
+ const text = String(branch || "").trim().toLowerCase();
3427
+ if (text === "true" || text === "next1") return "output-0";
3428
+ if (text === "false" || text === "next2") return "output-1";
3429
+ return null;
3430
+ }
3431
+
3424
3432
  function workspaceNeedsUpstreamExecutionForEdge(graph, edge, scopedRoot = "") {
3425
3433
  if (workspaceIsControlEdge(graph, edge)) return true;
3426
3434
  return !workspaceEdgeHasCachedOutput(graph, edge, scopedRoot);
@@ -4645,6 +4653,30 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
4645
4653
  const runtimeEnv = (extra = {}) => runtimeEnvForUser(userCtx, { ...runEnv, ...(extra || {}) });
4646
4654
  const autoCleanupWorktrees = [];
4647
4655
  const runTmpRoot = workspaceCreateRunTmpRoot(scopedRoot, runNodeId);
4656
+ const controlBranches = new Map();
4657
+ const skippedNodes = new Set();
4658
+ const incomingControlEdgesByTarget = new Map();
4659
+ for (const edge of Array.isArray(graph?.edges) ? graph.edges : []) {
4660
+ const target = String(edge?.target || "");
4661
+ if (!target || !workspaceIsControlEdge(graph, edge)) continue;
4662
+ if (!incomingControlEdgesByTarget.has(target)) incomingControlEdgesByTarget.set(target, []);
4663
+ incomingControlEdgesByTarget.get(target).push(edge);
4664
+ }
4665
+ const skipReasonForNode = (nodeId) => {
4666
+ for (const edge of incomingControlEdgesByTarget.get(nodeId) || []) {
4667
+ const sourceId = String(edge?.source || "");
4668
+ if (!sourceId) continue;
4669
+ if (skippedNodes.has(sourceId)) return `上游 ${sourceId} 已被分支跳过`;
4670
+ const sourceDefId = String(graph.instances?.[sourceId]?.definitionId || "");
4671
+ if (sourceDefId !== "control_if" || !controlBranches.has(sourceId)) continue;
4672
+ const expectedHandle = workspaceControlIfBranchToSourceHandle(controlBranches.get(sourceId));
4673
+ const actualHandle = String(edge?.sourceHandle || "output-0");
4674
+ if (expectedHandle && actualHandle !== expectedHandle) {
4675
+ return `control_if ${sourceId} 分支为 ${controlBranches.get(sourceId)},跳过 ${actualHandle}`;
4676
+ }
4677
+ }
4678
+ return "";
4679
+ };
4648
4680
 
4649
4681
  try {
4650
4682
  for (const nodeId of order) {
@@ -4652,6 +4684,13 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
4652
4684
  const instance = graph.instances[nodeId];
4653
4685
  if (!instance) continue;
4654
4686
  const defId = String(instance.definitionId || "");
4687
+ const skipReason = skipReasonForNode(nodeId);
4688
+ if (skipReason) {
4689
+ skippedNodes.add(nodeId);
4690
+ emit({ type: "status", nodeId, line: `Skipped: ${skipReason}` });
4691
+ emit({ type: "node-done", nodeId, definitionId: defId, skipped: true });
4692
+ continue;
4693
+ }
4655
4694
  emit({ type: "node-start", nodeId, definitionId: defId });
4656
4695
 
4657
4696
  if (defId === "workspace_run" || defId === "workspace_scheduled_run") {
@@ -4707,6 +4746,23 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
4707
4746
  continue;
4708
4747
  }
4709
4748
 
4749
+ if (defId === "control_if") {
4750
+ const inputValues = workspaceInputValues(graph, nodeId, outputs, scopedRoot);
4751
+ const boolSlot = (Array.isArray(instance.input) ? instance.input : [])
4752
+ .find((slot) => String(slot?.type || "").trim().toLowerCase() === "bool");
4753
+ const boolSlotName = String(boolSlot?.name || "").trim();
4754
+ const rawValue = boolSlotName && Object.prototype.hasOwnProperty.call(inputValues, boolSlotName)
4755
+ ? inputValues[boolSlotName]
4756
+ : workspaceSlotValue(boolSlot);
4757
+ const boolValue = parseBool(rawValue);
4758
+ const branch = boolValue ? "true" : "false";
4759
+ controlBranches.set(nodeId, branch);
4760
+ outputs.set(nodeId, branch);
4761
+ emit({ type: "status", nodeId, line: `control_if branch: ${branch}` });
4762
+ emit({ type: "node-done", nodeId, definitionId: defId, branch });
4763
+ continue;
4764
+ }
4765
+
4710
4766
  if (defId === "provide_str" || defId === "provide_password") {
4711
4767
  const content = workspaceInstanceText(instance);
4712
4768
  outputs.set(nodeId, content);