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-in goal or 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, none or None (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 include none, roundedRectangle, capsule, circle, diamond, hexagon, etc.
  • node.contentType (String): The content type. Supported values include plainText, markdown, image, chart.
  • node.contentPayload / node.imagePath (String/Object): The universal data payload. When contentType is set to image, this specifies the local path or remote URL of the image; when set to chart, 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 global outputs object as a shorthand, e.g., outputs.score = 10 is equivalent to node.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:

  1. Direct Global Variables: Whether there is an upstream parameter named cost, or the current node itself has defined a custom property named cost, you can just type cost to get its value. If multiple nodes provide parameters with the same name, typing cost will 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.
  2. 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 the cost from the node with ID 1 (which could be an upstream node or the current node itself).
  3. Raw Collections: The system also injects an inputs array (containing all dictionary objects from upstream) and a self dictionary (specifically containing the custom properties of the current node), which you can iterate over for advanced operations (for example, using self.cost to strictly get the current node's cost).

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.
  • 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 specified url (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.