8. Entity Scripts and Advanced Extensions
On top of the built-in mathematical formula engine, MindLogic provides an even more powerful feature: Entity Scripts. You can write native JavaScript code to dynamically intercept and modify the state of a node during inference calculation, enabling high-level logic interactions.
What is an Entity Script?
At the very bottom of the Inspector panel, you will see a multi-line code input box named "Entity Script". During the forward propagation of the graph, after the engine aggregates all upstream input variables, and after executing the current node's output formulas, it will automatically execute this script. This means your script can easily read the aggregated results calculated by the built-in Math Engine.
The node Object
Within the context of the entity script, the system exposes a global proxy object: node. This object represents the "entity currently being calculated".
By reading and assigning values to the properties of the node object, you can utilize upstream variables to change the node's display and behavior.
Supported Writable Properties
node.id(Number): The unique ID of the current node (Read-only).node.title(String): The main title of the node.node.customClassName(String): The custom class name of the node.node.classID(String): The underlying category ID of the node. For example, a built-ingoalor the unique ID of a custom category (which can be viewed and copied in the Domain Inspector on the right). Modifying this property allows you to dynamically change the node's category.node.confidence(Number, 0~1): The confidence state of the node.node.annotation(String): The notes/annotations of the node.node.symbolName(String): The node's icon (SF Symbols name, e.g.,star.fill).node.statusIcon(String): The status icon at the bottom right of the node. Supported built-in shortcuts include:uncheck,check,complete,error,warning,loading,noneorNone(to hide). In addition, it also supports any valid SF Symbols name (e.g.,heart.fill).node.frameType(String): The shape of the frame. Supported values includenone,roundedRectangle,capsule,circle,diamond,hexagon, etc.node.contentType(String): The content type. Supported values includeplainText,markdown,image,chart.node.contentPayload/node.imagePath(String/Object): The universal data payload. WhencontentTypeis set toimage, this specifies the local path or remote URL of the image; when set tochart, you can directly assign a native JavaScript dictionary or array object, and the underlying engine will automatically serialize and render it as a chart.node.outputs(Dictionary Object): Store any new variables you want to pass downstream through the script! You can also use the globaloutputsobject as a shorthand, e.g.,outputs.score = 10is equivalent tonode.outputs['score'] = 10.
Accessing Input Parameters
Properties passed down from upstream nodes (Outputs) or custom properties of the current node are automatically injected into the JS engine as global variables. You can read them directly by their variable names:
- Direct Global Variables: Whether there is an upstream parameter named
cost, or the current node itself has defined a custom property namedcost, you can just typecostto get its value. If multiple nodes provide parameters with the same name, typingcostwill yield their sum (for numbers) or the first encountered value (for strings). The custom properties of the current node are also aggregated into this total. - ID Indexing: These global variables also act as objects. You can precisely fetch the value passed from a specific node by its display ID (the number in the top right corner). For example,
cost[1]gets thecostfrom the node with ID 1 (which could be an upstream node or the current node itself). - Raw Collections: The system also injects an
inputsarray (containing all dictionary objects from upstream) and aselfdictionary (specifically containing the custom properties of the current node), which you can iterate over for advanced operations (for example, usingself.costto strictly get the current node'scost).
Note: If you want to access the current node's basic information (such as title, shape, etc.), please read the properties of the node object directly (e.g., node.title).
The system Object
Within the context of entity scripts and plugin scripts, the system also provides a global system object for executing low-level native operations (such as network requests and file reads). Note: Remember to use await when calling asynchronous methods.
Supported Methods
system.request(url, options): Asynchronous HTTP network request. This is the recommended way to make network calls.- Example:
let res = await system.request("https://api.example.com", { method: "POST", body: JSON.stringify({...}) }) - Returns: The string body of the response.
- Example:
system.fetch(url): Simple synchronous HTTP GET request. Returns the response string.system.readFile(path): Synchronously reads a file from the local file system and returns its string contents.system.openFileDialog(): Opens a system file dialog allowing the user to select a file, and returns the selected file path (String).system.extractPDF(url): Asynchronously reads and extracts text from a PDF file located at the specifiedurl(local or remote). Returns a string containing all text.system.sleep(ms): Asynchronously waits for a specified amount of time (in milliseconds). Example:await system.sleep(1000)pauses execution for 1 second.
Script Examples
1. Dynamic Warning State
When the sum of the upstream cost parameters exceeds a threshold, automatically turn the current node into a danger warning node:
// Assuming an upstream variable named 'cost' flows in
if (SUM(cost) > 1000) {
node.title = "π¨ Cost Overrun Alert!";
node.confidence = 0.9;
node.frameType = "diamond"; // Change shape to diamond
node.outputs["isOverBudget"] = true; // Pass judgment to downstream
} else {
node.title = "Cost Safe";
node.outputs["isOverBudget"] = false; // equivalent to outputs.isOverBudget = ...
}
2. Dynamic Display Format
If a specific external input exists, convert the node to a rich text markdown display:
if (ISBLANK(reportData)) {
node.title = "No Report Data";
} else {
node.contentType = "markdown";
node.outputs["markdownOutput"] = "# Report Summary\nThe data is very healthy!"; // equivalent to outputs.markdownOutput = ...
}
3. Dynamic Chart Rendering and Data Injection
Through scripts, you can directly render business data coming from upstream as a native chart.
The engine supports directly assigning native JavaScript objects or arrays to node.contentPayload. The underlying system automatically handles all serialization and data binding, completely eliminating the need for tedious JSON.stringify logic.
Supported Chart Types (chartType):
bar(Bar Chart)line(Line Chart)area(Area Chart)point(Scatter Point Chart)pie(Pie Chart)
Example Script: Direct Object Assignment
// Assume this is the data object we dynamically calculated based on upstream variables
let data = {
chartType: "bar",
xAxisTitle: "Quarter",
yAxisTitle: "Revenue (k)",
series: [
{ x: "Q1", y: 120, category: "Product A" },
{ x: "Q1", y: 80, category: "Product B" },
{ x: "Q2", y: 150, category: "Product A" },
{ x: "Q2", y: 90, category: "Product B" }
]
};
// 1. Switch the node's display mode to chart
node.contentType = "chart";
// 2. Minimalist assignment: simply drop the JS object right in
node.contentPayload = data;
(Note: If you only need the simplest basic chart, you can even omit the outer structure and directly assign an array containing {x, y} elements to node.contentPayload. The engine's smart fallback mode will attempt to parse it automatically.)
Important Notes
- Side-Effect Overwrite Mechanism: If you hardcode
node.title = "Something"in your script, every time the canvas refreshes or recalculates, the script's assignment will forcefully overwrite any title you manually edited on the canvas. Therefore, it is recommended to use conditional statements (if...else) to precisely control when to change properties. - Environment Isolation: The script for each node runs in a completely isolated scope containing only the current calculation context. You cannot directly manipulate other nodes on the canvas; you can only pass data downstream via
node.outputs. This ensures absolute unidirectional data flow and determinism for the inference engine.
