8. 节点脚本与高级扩展 (Entity Scripts)

MindLogic 在内置的数学公式引擎之上,提供了更为强大的 节点脚本 (Entity Script) 支持。您可以通过编写原生的 JavaScript 代码,在推演计算时动态拦截和修改节点的状态,从而实现高阶的逻辑交互。

什么是节点脚本?

在属性面板(Inspector)的最底部,您会看到一个名为 “节点脚本 (Script)” 的多行代码输入框。 当图谱进行正向计算时,引擎在汇总完所有上游的输入变量之后、在执行当前节点的输出公式之前,会自动执行这段脚本。

node 对象

在节点脚本的上下文中,系统暴露了一个全局的代理对象:node。这个对象代表了“当前正在被计算的节点实体”。 通过对 node 对象属性的读取和赋值,您可以利用上游变量改变当前节点的显示和行为。

支持动态读写的属性列表

  • node.id (数字): 节点的唯一编号(只读)。
  • node.title (字符串): 节点的主标题。
  • node.customClassName (字符串): 节点的自定义类名。
  • node.classID (字符串): 节点的底层分类 ID。例如内置的 goal 或自定义类别的专属 ID(可在右侧域(Domain)面板中查看并在名称后复制)。通过修改此属性,可以动态改变节点所属的分类。
  • node.confidence (数字,0~1): 节点的置信度状态。
  • node.annotation (字符串): 节点的备注/注释。
  • node.symbolName (字符串): 节点图标(SF Symbols名称,如 star.fill)。
  • node.frameType (字符串): 边框形状。支持的值包括 none, roundedRectangle, capsule, circle, diamond, hexagon 等。
  • node.contentType (字符串): 内容形式。支持的值包括 plainText, markdown, image
  • node.imagePath (字符串): 当 node.contentType 设为 image 时,指定要显示的图片本地路径或远端 URL(例如 https://example.com/img.png)。
  • node.outputs (字典对象): 存放任何你想通过脚本传递给下游的新变量!

获取输入参数

上游节点传递过来的属性(Outputs)或当前节点的自定义属性,会自动作为全局变量注入到 JS 引擎中。你可以直接通过变量名来读取:

  1. 直接读取全局变量:无论是上游有一个叫做 cost 的参数,还是当前节点自己定义了一个名叫 cost 的自定义属性,你都可以直接写 cost 获取它的值。如果有多个上游传入同名参数,直接写 cost 会得到它们的总和(数字类型)或首次出现的值(字符串类型)。当前节点自身的自定义属性也会一并汇总在内。
  2. 按节点编号读取 (ID Indexing):这些全局变量同时也是一个对象,你可以通过节点的编号(右上角的数字 ID)来精确获取对应节点传入的值。例如:cost[1] 表示获取编号为 1 的节点的值(可以是上游节点,也可以是当前节点自己)。
  3. 获取原生集合:系统还会注入 inputs 数组(包含所有上游传来的字典对象)以及 self 字典(专门包含当前节点的自定义属性),您可以遍历它们进行高级操作(例如使用 self.cost 专门获取当前节点的 cost 属性)。

注:如果要获取当前节点的基础信息(如标题、形状等),请直接读取 node 对象的属性(如 node.title)。

脚本的使用范例

1. 动态警告状态

当上游传入的成本参数总和超过阈值时,自动将当前节点变成危险警告节点:

// 假设上游流入了一个名叫 'cost' 的变量
if (SUM(cost) > 1000) {
    node.title = "🚨 成本超标警报!"; 
    node.confidence = 0.9;
    node.frameType = "diamond"; // 将形状修改为菱形
    node.outputs["isOverBudget"] = true; // 给下游传递判断结果
} else {
    node.title = "成本安全";
    node.outputs["isOverBudget"] = false;
}

2. 动态改变显示形式

如果存在某个特定的外部输入,将节点转换为富文本显示:

if (ISBLANK(reportData)) {
    node.title = "无报告数据";
} else {
    node.contentType = "markdown";
    node.outputs["markdownOutput"] = "# 报告概要\n数据非常健康!";
}

注意事项

  • 副作用覆盖机制:如果您的脚本内硬编码了 node.title = "某某",那么每次画布刷新、重新计算时,脚本的赋值会强制覆盖您在画布上手动修改的标题。因此,推荐使用条件语句(if...else)来精确控制何时改变属性。
  • 环境隔离:每个节点的脚本运行在一个完全隔离且仅包含当前计算上下文的作用域中,无法直接操纵画布上的其他节点,只能通过 node.outputs 向下流转数据。这确保了推演引擎绝对的单向数据流与确定性。