Просмотр исходного кода

docs(variable): reorganize variable docs, add global scope, output multiple variables (#212)

Yiwei Mao 8 месяцев назад
Родитель
Сommit
e2e80efb7a

+ 8 - 0
apps/docs/scripts/translate.ts

@@ -105,6 +105,11 @@ async function translateFiles() {
         const sourceFile = path.join(sourceLangFolder, file);
         const targetFile = path.join(targetLangFolder, file);
 
+        if (!fs.existsSync(sourceFile)) {
+          console.error(`Source file not found: ${sourceFile}`);
+          continue;
+        }
+
         // 2.1. Read the file
         const sourceContent = fs.readFileSync(sourceFile, 'utf-8');
 
@@ -124,6 +129,9 @@ async function translateFiles() {
         );
 
         // 2.3. Write the translated file
+        if (!fs.existsSync(path.dirname(targetFile))) {
+          fs.mkdirSync(path.dirname(targetFile), { recursive: true });
+        }
         fs.writeFileSync(targetFile, targetContent);
 
         console.log(`Translated: ${targetFile}`);

+ 5 - 1
apps/docs/src/en/guide/advanced/_meta.json

@@ -11,7 +11,11 @@
   },
   "form",
   "without-form",
-  "variable",
+  {
+    "type": "dir",
+    "name": "variable",
+    "label": "Variable"
+  },
   "history",
   "shortcuts",
   "minimap",

+ 0 - 282
apps/docs/src/en/guide/advanced/variable.mdx

@@ -1,282 +0,0 @@
-# Use Variables
-
-## Business Background
-
-In Workflow orchestration, information needs to be passed between nodes. To achieve this, we use **variables** to store and manage this information.
-
-:::warning A variable consists of three main parts:
-
-1. **Unique Identifier**: The name of the variable, used to distinguish different variables so that they can be accurately referenced and used in the program. For example: `userName` or `totalAmount`.
-2. **Value**: The data stored by the variable. The value can be of various types, such as numbers (e.g., `42`), strings (e.g., `"Hello!"`), boolean values (e.g., `true`), etc.
-3. **Type**: The kind of data that the variable can store. The type determines what kind of values the variable can accept. For example, a variable can be an integer, float, string, or boolean, etc.
-
-:::
-
-Here is an example of a workflow orchestration: The WebSearch node retrieves knowledge and passes it to the LLM node for analysis through the `natural_language_desc`.
-
-<div style={{display: 'flex', gap: '20px'}}>
-  <img style={{width: "50%"}} loading="lazy" src="/variable/variable-biz-context-websearch-llm.png" />
-  <div>
-    In this example:
-    <p style={{marginTop: 10}}>1. The WebSearch node stores the information (value) in a variable with the unique identifier `natural_language_desc`.</p>
-    <p style={{marginTop: 5}}>2. The LLM node retrieves the information (value) from the knowledge base using the unique identifier `natural_language_desc` and passes it to the LLM node for analysis.</p>
-    <p style={{marginTop: 5}}>3. The type of the `natural_language_desc` variable is a string, representing the content of the information retrieved from the web, such as "DeepSeek has released a new model today."</p>
-  </div>
-</div>
-
-## What is the Variable Engine?
-
-The Variable Engine is an optional built-in feature provided by Flowgram that helps to efficiently implement **variable information orchestration** during workflow design. It can achieve the following functions:
-
-<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "25px" }}>
-  <div style={{ gridColumn: "span 2" }}>
-    <b>Scope Constraint Control</b>
-    <p className="rs-tip">With the Variable Engine, you can control the scope of variables, ensuring that variables are available within the appropriate range and avoiding unnecessary conflicts.</p>
-    <div style={{display: "flex", gap: "25px"}}>
-      <div>
-        <img loading="lazy" src="/variable/variable-scope-feature-1.png" />
-        <p style={{marginTop: '10px'}}>In the image, the query variable of the Start node can be accessed by the subsequent LLM node and End node.</p>
-      </div>
-      <div>
-        <img loading="lazy" src="/variable/variable-scope-feature-2.png" />
-        <p style={{marginTop: '10px'}}>In the image, the LLM node is within the Condition branch, while the End node is outside the Condition branch; therefore, the variable selector of the End node cannot select the result variable from the LLM node.</p>
-      </div>
-    </div>
-  </div>
-  <div>
-    <b>Maintenance of Variable Information Tree</b>
-    <p className="rs-tip">The Variable Engine can help you build a clear variable information tree, making it easier to view and manage the status and relationships of all variables.</p>
-    <img loading="lazy" src="/variable/variable-tree-management.gif" />
-    <p style={{marginTop: '10px'}}>The image shows multiple nodes + global configuration output variables; some variables contain multiple sub-variables, forming a tree structure.</p>
-  </div>
-  <div>
-    <b>Automatic Type Inference of Variables</b>
-    <p className="rs-tip">The Variable Engine can automatically infer the type of variables based on context, reducing the workload of manually specifying types and improving development efficiency.</p>
-    <img loading="lazy" src="/variable/variable-batch-auto-infer.gif" />
-    <p style={{marginTop: '10px'}}>In the image, the Batch node processes the arr variable from the Start node; when the type of the arr variable changes, the type of the item variable output by the Batch node also changes accordingly.</p>
-  </div>
-</div>
-
-## Enable Variable Engine
-
-[> API Detail](https://flowgram.ai/auto-docs/editor/interfaces/VariablePluginOptions.html)
-
-```tsx pure title="use-editor-props.ts" {3}
-
-// EditorProps
-{
-  variableEngine: {
-    /**
-     * Need to enable the variable engine to use
-     */
-    enable: true
-  }
-}
-```
-
-## Node Output Variables
-
-[> Demo Detail](https://github.com/bytedance/flowgram.ai/blob/main/apps/demo-fixed-layout/src/plugins/sync-variable-plugin/sync-variable-plugin.ts#L25)
-
-### Set Output Variables through FlowNodeVariableData
-
-```tsx pure title="sync-variable-plugin.tsx"
-import {
-  FlowNodeVariableData,
-  ASTFactory,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-flowDocument.onNodeCreate(({ node }) => {
-  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
-
-  // ....
-
-  // 1. Clear VariableData if No value
-  variableData.clearVar()
-
-  // 2. Set a String Variable as output
-  variableData.setVar(
-    ASTFactory.createVariableDeclaration({
-      meta: {
-        title: `Your Output Variable Title`,
-      },
-      key: `your_variable_global_unique_key_${node.id}`,
-      type: ASTFactory.createString(),
-    })
-  )
-
-  // 3. Set a Complicated Variable Data as output
-  variableData.setVar(
-    ASTFactory.createVariableDeclaration({
-      meta: {
-        title: `Your Output Variable Title`,
-      },
-      key: `your_variable_global_unique_key_${node.id}`,
-      type: ASTFactory.createArray({
-        items: ASTFactory.createObject({
-          properties: [
-            ASTFactory.createProperty({
-              key: 'stringType',
-              type: ASTFactory.createString(),
-            }),
-            ASTFactory.createProperty({
-              key: 'booleanType',
-              type: ASTFactory.createBoolean(),
-            }),
-            ASTFactory.createProperty({
-              key: 'numberType',
-              type: ASTFactory.createNumber(),
-            }),
-            ASTFactory.createProperty({
-              key: 'integerType',
-              type: ASTFactory.createInteger(),
-            }),
-          ],
-        }),
-      }),
-    })
-  );
-
-  // ....
-})
-
-// ....
-
-```
-
-More usage, see: [Class: FlowNodeVariableData](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
-
-### Set Output Variables through Form Effect
-
-
-```tsx pure title="node-registries.ts"
-import {
-  FlowNodeRegistry,
-  createEffectFromVariableProvider,
-  ASTFactory,
-  type ASTNodeJSON
-} from '@flowgram.ai/fixed-layout-editor';
-
-export function createTypeFromValue(value: string): ASTNodeJSON | undefined {
-  switch (value) {
-    case 'string':
-      return ASTFactory.createString();
-    case 'number':
-      return ASTFactory.createNumber();
-    case 'boolean':
-      return ASTFactory.createBoolean();
-    case 'integer':
-      return ASTFactory.createInteger();
-
-    default:
-      return;
-  }
-}
-
-export const nodeRegistries: FlowNodeRegistry[] = [
-  {
-    type: 'start',
-    formMeta: {
-      effect: {
-        'path.to.value': createEffectFromVariableProvider({
-          // parse form value to variable
-          parse(v: string) {
-            return {
-              meta: {
-                title: `Your Output Variable Title`,
-              },
-              key: `your_variable_global_unique_key_${node.id}`,
-              type: createTypeFromValue(v)
-            }
-          }
-        }),
-      },
-      render: () => (
-       // ...
-      )
-    },
-  }
-]
-
-```
-
-
-## Node Consumes Variables
-
-### Get Variable List
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  useScopeAvailable,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// .... Inside react hooks or component
-
-const available = useScopeAvailable()
-
-const renderVariable = (variable: BaseVariableField) => {
-  // ....
-}
-
-return available.variables.map(renderVariable)
-
-// ....
-
-
-```
-
-### Get Drilldown of Object Type Variable
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  ASTMatch,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-const renderVariable = (variable: BaseVariableField) => ({
-  title: variable.meta?.title,
-  key: variable.key,
-  // Only Object Type can drilldown
-  children: ASTMatch.isObject(type) ? type.properties.map(renderVariable) : [],
-});
-
-// ....
-
-```
-
-### Get Drilldown of Array Type Variable
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  type BaseType,
-  ASTMatch,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-const getTypeChildren = (type?: BaseType): BaseVariableField[] => {
-  if (!type) return [];
-
-  // get properties of Object
-  if (ASTMatch.isObject(type)) return type.properties;
-
-  // get items type of Array
-  if (ASTMatch.isArray(type)) return getTypeChildren(type.items);
-};
-
-const renderVariable = (variable: BaseVariableField) => ({
-  title: variable.meta?.title,
-  key: variable.key,
-  // Only Object Type can drilldown
-  children: getTypeChildren(variable.type).map(renderVariable),
-});
-
-// ....
-
-```

+ 5 - 0
apps/docs/src/en/guide/advanced/variable/_meta.json

@@ -0,0 +1,5 @@
+[
+  "basic",
+  "variable-output",
+  "variable-consume"
+]

+ 75 - 0
apps/docs/src/en/guide/advanced/variable/basic.mdx

@@ -0,0 +1,75 @@
+# Variable Basics
+
+## Business Context
+
+In workflow orchestration, information needs to be passed between nodes. To achieve this, we use **variables** to store and manage this information.
+
+:::warning A variable consists of three main components:
+
+1. **Unique Identifier**: The name of the variable, used to distinguish between different variables so they can be accurately referenced and used in the program. Examples: `userName` or `totalAmount`.
+2. **Value**: The data stored in the variable. Values can be of various types, such as numbers (e.g., `42`), strings (e.g., `"Hello!"`), booleans (e.g., `true`), etc.
+3. **Type**: The kind of data the variable can store. The type determines what values the variable can accept. For example, a variable can be an integer, float, string, boolean, etc.
+
+:::
+
+Here’s an example of workflow orchestration: The WebSearch node retrieves knowledge and passes it to the LLM node for analysis via `natural_language_desc`.
+
+<div style={{display: 'flex', gap: '20px'}}>
+  <img style={{width: "50%"}} loading="lazy" src="/variable/variable-biz-context-websearch-llm.png" />
+  <div>
+    In this example:
+    <p style={{marginTop: 10}}>1. The WebSearch node stores the information (value) in a variable with the unique identifier `natural_language_desc`.</p>
+    <p style={{marginTop: 5}}>2. The LLM node retrieves the knowledge base information (value) via the `natural_language_desc` identifier and passes it to the LLM node for analysis.</p>
+    <p style={{marginTop: 5}}>3. The `natural_language_desc` variable is of type string, representing the content retrieved from the web, such as "DeepSeek released a new model today."</p>
+  </div>
+</div>
+
+## What is the Variable Engine?
+
+The variable engine is an optional built-in feature provided by Flowgram to help streamline **variable information orchestration** in workflow design more efficiently. It enables the following functionalities:
+
+<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "25px" }}>
+  <div style={{ gridColumn: "span 2" }}>
+    <b>Scope Constraint Control</b>
+    <p className="rs-tip">With the variable engine, you can control the scope of variables, ensuring they are available within the appropriate range and avoiding unnecessary conflicts.</p>
+    <div style={{display: "flex", gap: "25px"}}>
+      <div>
+        <img loading="lazy" src="/variable/variable-scope-feature-1.png" />
+        <p style={{marginTop: '10px'}}>In the diagram, the `query` variable from the Start node can be accessed by subsequent LLM and End nodes.</p>
+      </div>
+      <div>
+        <img loading="lazy" src="/variable/variable-scope-feature-2.png" />
+        <p style={{marginTop: '10px'}}>In the diagram, the LLM node is inside a Condition branch, while the End node is outside. Thus, the End node's variable selector cannot access the `result` variable from the LLM node.</p>
+      </div>
+    </div>
+  </div>
+  <div>
+    <b>Variable Information Tree Maintenance</b>
+    <p className="rs-tip">The variable engine helps you build a clear variable information tree, making it easier to view and manage the state and relationships of all variables.</p>
+    <img loading="lazy" src="/variable/variable-tree-management.gif" />
+    <p style={{marginTop: '10px'}}>The diagram shows output variables from multiple nodes and global configurations, with some variables containing multiple sub-variables forming a tree structure.</p>
+  </div>
+  <div>
+    <b>Automatic Type Inference</b>
+    <p className="rs-tip">The variable engine can automatically infer variable types based on context, reducing the need for manual type specification and improving development efficiency.</p>
+    <img loading="lazy" src="/variable/variable-batch-auto-infer.gif" />
+    <p style={{marginTop: '10px'}}>In the diagram, the Batch node processes the `arr` variable from the Start node. When the type of the `arr` variable changes, the type of the `item` variable output by the Batch node also changes accordingly.</p>
+  </div>
+</div>
+
+## Enabling the Variable Engine
+
+[> API Detail](https://flowgram.ai/auto-docs/editor/interfaces/VariablePluginOptions.html)
+
+```tsx pure title="use-editor-props.ts" {3}
+
+// EditorProps
+{
+  variableEngine: {
+    /**
+     * The variable engine must be enabled to use this feature.
+     */
+    enable: true
+  }
+}
+```

+ 78 - 0
apps/docs/src/en/guide/advanced/variable/variable-consume.mdx

@@ -0,0 +1,78 @@
+# Consume Variables
+
+## Accessing Variable Tree Within a Node
+
+### Retrieving Variable List
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  useScopeAvailable,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// .... Inside react hooks or component
+
+const available = useScopeAvailable()
+
+const renderVariable = (variable: BaseVariableField) => {
+  // ....
+}
+
+return available.variables.map(renderVariable)
+
+// ....
+
+```
+
+### Drilling Down into Object Type Variables
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  ASTMatch,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+const renderVariable = (variable: BaseVariableField) => ({
+  title: variable.meta?.title,
+  key: variable.key,
+  // Only Object Type can drilldown
+  children: ASTMatch.isObject(type) ? type.properties.map(renderVariable) : [],
+});
+
+// ....
+
+```
+
+### Drilling Down into Array Type Variables
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  type BaseType,
+  ASTMatch,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+const getTypeChildren = (type?: BaseType): BaseVariableField[] => {
+  if (!type) return [];
+
+  // get properties of Object
+  if (ASTMatch.isObject(type)) return type.properties;
+
+  // get items type of Array
+  if (ASTMatch.isArray(type)) return getTypeChildren(type.items);
+};
+
+const renderVariable = (variable: BaseVariableField) => ({
+  title: variable.meta?.title,
+  key: variable.key,
+  // Only Object Type can drilldown
+  children: getTypeChildren(variable.type).map(renderVariable),
+});
+
+// ....
+
+```

+ 324 - 0
apps/docs/src/en/guide/advanced/variable/variable-output.mdx

@@ -0,0 +1,324 @@
+# Output Variables
+
+## Node Output Variables
+
+### FlowNodeVariableData Output Variables
+
+`Flowgram` manages node information based on [`ECS`](https://flowgram.ai/guide/concepts/ecs.html) (Entity-Component-System).
+
+The [`FlowNodeVariableData`](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html) is a `Component` on the `FlowNodeEntity` node, specifically designed to handle **variable information** output from nodes.
+
+The following demo shows: How to obtain `FlowNodeVariableData` and use it to output variables from nodes.
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  FlowNodeVariableData,
+  ASTFactory,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+flowDocument.onNodeCreate(({ node }) => {
+  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
+
+  // ....
+
+  // 1. Clear VariableData if No value
+  variableData.clearVar()
+
+  // 2. Set a String Variable as output
+  variableData.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  // 3. Set a Complicated Variable Data as output
+  variableData.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createArray({
+        items: ASTFactory.createObject({
+          properties: [
+            ASTFactory.createProperty({
+              key: 'stringType',
+              type: ASTFactory.createString(),
+            }),
+            ASTFactory.createProperty({
+              key: 'booleanType',
+              type: ASTFactory.createBoolean(),
+            }),
+            ASTFactory.createProperty({
+              key: 'numberType',
+              type: ASTFactory.createNumber(),
+            }),
+            ASTFactory.createProperty({
+              key: 'integerType',
+              type: ASTFactory.createInteger(),
+            }),
+          ],
+        }),
+      }),
+    })
+  );
+
+  // 4. Get Variable for current Node
+  console.log(variableData.getVar())
+
+  // ....
+})
+
+// ....
+
+```
+
+See: [> Demo Detail](https://github.com/bytedance/flowgram.ai/blob/main/apps/demo-fixed-layout/src/plugins/sync-variable-plugin/sync-variable-plugin.ts#L25)
+
+### Setting Multiple Output Variables for a Node
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  FlowNodeVariableData,
+  ASTFactory,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+flowDocument.onNodeCreate(({ node }) => {
+  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
+
+  // ...
+  // 1. Create, Update, Read, Delete Variable in namespace_1
+  variableData.setVar(
+    'namespace_1',
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(variableData.getVar('namespace_1'))
+
+  variableData.clearVar('namespace_1')
+
+  // ....
+
+  // 2. Create, Update, Read, Delete Variable in namespace_2
+  variableData.setVar(
+    'namespace_2',
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title 2`,
+      },
+      key: `your_variable_global_unique_key_${node.id}_2`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(variableData.getVar('namespace_2'))
+
+  variableData.clearVar('namespace_2')
+
+  // ....
+})
+
+// ....
+
+```
+
+For more usage, see: [Class: FlowNodeVariableData](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
+
+### Setting Output Variables via Form Side Effects
+
+```tsx pure title="node-registries.ts"
+import {
+  FlowNodeRegistry,
+  createEffectFromVariableProvider,
+  ASTFactory,
+  type ASTNodeJSON
+} from '@flowgram.ai/fixed-layout-editor';
+
+export function createTypeFromValue(value: string): ASTNodeJSON | undefined {
+  switch (value) {
+    case 'string':
+      return ASTFactory.createString();
+    case 'number':
+      return ASTFactory.createNumber();
+    case 'boolean':
+      return ASTFactory.createBoolean();
+    case 'integer':
+      return ASTFactory.createInteger();
+
+    default:
+      return;
+  }
+}
+
+export const nodeRegistries: FlowNodeRegistry[] = [
+  {
+    type: 'start',
+    formMeta: {
+      effect: {
+        // Create first variable
+        // = variableData.setVar('path.to.value', ASTFactory.createVariableDeclaration(parse(v)))
+        'path.to.value': createEffectFromVariableProvider({
+          // parse form value to variable
+          parse(v: string) {
+            return {
+              meta: {
+                title: `Your Output Variable Title`,
+              },
+              key: `your_variable_global_unique_key_${node.id}`,
+              type: createTypeFromValue(v)
+            }
+          }
+        }),
+        // Create second variable
+        // = variableData.setVar('path.to.value2', ASTFactory.createVariableDeclaration(parse(v)))
+        'path.to.value2': createEffectFromVariableProvider({
+          // parse form value to variable
+          parse(v: string) {
+            return {
+              meta: {
+                title: `Your Output Variable Title 2`,
+              },
+              key: `your_variable_global_unique_key_${node.id}_2`,
+              type: createTypeFromValue(v)
+            }
+          }
+        }),
+      },
+      render: () => (
+       // ...
+      )
+    },
+  }
+]
+
+```
+
+## Global Output Variables
+
+### Obtaining Global Variable Scope
+
+The global scope can be obtained via `ctx` in a Plugin:
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  GlobalScope,
+  definePluginCreator,
+  PluginCreator
+} from '@flowgram.ai/fixed-layout-editor';
+
+
+export const createSyncVariablePlugin: PluginCreator<SyncVariablePluginOptions> =
+  definePluginCreator<SyncVariablePluginOptions, FixedLayoutPluginContext>({
+    onInit(ctx, options) {
+      const globalScope = ctx.get(GlobalScope)
+
+      globalScope.setVar(
+         ASTFactory.createVariableDeclaration({
+          meta: {
+            title: `Your Output Variable Title`,
+          },
+          key: `your_variable_global_unique_key`,
+          type: ASTFactory.createString(),
+        })
+      )
+    }
+  })
+
+```
+
+It can also be obtained in React components within the canvas via `useService`:
+
+```tsx pure title="global-variable-component.tsx"
+import {
+  GlobalScope,
+  useService,
+} from '@flowgram.ai/fixed-layout-editor';
+
+function GlobalVariableComponent() {
+
+  const globalScope = useService(GlobalScope)
+
+  // ...
+
+  const handleChange = (v: string) => {
+    globalScope.setVar(
+      ASTFactory.createVariableDeclaration({
+        meta: {
+          title: `Your Output Variable Title`,
+        },
+        key: `your_variable_global_unique_key_${v}`,
+        type: ASTFactory.createString(),
+      })
+    )
+  }
+
+  return <Input onChange={handleChange}/>
+}
+
+```
+
+### Outputting Variables in Global Scope
+
+The API for outputting variables in [`GlobalScope`](https://flowgram.ai/auto-docs/editor/classes/GlobalScope.html) is similar to `FlowNodeVariableData`:
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  GlobalScope,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ...
+
+onInit(ctx, options) {
+  const globalScope = ctx.get(GlobalScope);
+
+  // 1. Create, Update, Read, Delete Variable in GlobalScope
+  globalScope.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(globalScope.getVar())
+
+  globalScope.clearVar()
+
+
+  // 2.  Create, Update, Read, Delete Variable in GlobalScope's namespace: 'namespace_1'
+    globalScope.setVar(
+      'namespace_1',
+      ASTFactory.createVariableDeclaration({
+        meta: {
+          title: `Your Output Variable Title 2`,
+        },
+        key: `your_variable_global_unique_key_2`,
+        type: ASTFactory.createString(),
+      })
+  )
+
+  console.log(globalScope.getVar('namespace_1'))
+
+  globalScope.clearVar('namespace_1')
+
+  // ...
+}
+```
+
+See: [Class: GlobalScope](https://flowgram.ai/auto-docs/editor/classes/GlobalScope.html)

+ 5 - 1
apps/docs/src/zh/guide/advanced/_meta.json

@@ -11,7 +11,11 @@
   },
   "form",
   "without-form",
-  "variable",
+  {
+    "type": "dir",
+    "name": "variable",
+    "label": "变量"
+  },
   "history",
   "shortcuts",
   "minimap",

+ 0 - 284
apps/docs/src/zh/guide/advanced/variable.mdx

@@ -1,284 +0,0 @@
-# 变量的使用
-
-## 业务背景
-
-在 Workflow 编排中,节点与节点之间需要传递信息。为了实现这一点,我们使用**变量**来存储和管理这些信息。
-
-:::warning 一个变量由三个主要部分组成:
-
-1. **唯一标识符**:变量的名字,用于区分不同的变量,以便在程序中可以准确地引用和使用它。如:`userName` 或 `totalAmount`。
-2. **值**:变量存储的数据。值可以是多种类型,比如数字(如 `42`)、字符串(如 `"Hello!"`)、布尔值(如 `true`)等。
-3. **类型**:变量可以存储的数据种类。类型决定了变量可以接受什么样的值。例如,一个变量可以是整数、浮点数、字符串或布尔值等。
-
-:::
-
-下面是一个流程编排的例子:WebSearch 节点获取到知识,通过 natural_language_desc 传递到 LLM 节点进行分析
-
-<div style={{display: 'flex', gap: '20px'}}>
-  <img style={{width: "50%"}} loading="lazy" src="/variable/variable-biz-context-websearch-llm.png" />
-  <div>
-    在该例子中:
-    <p style={{marginTop: 10}}>1. WebSearch 节点将信息(值)存在 natural_language_desc 为唯一标识符的变量内</p>
-    <p style={{marginTop: 5}}>2. LLM 节点通过 natural_language_desc 唯一标识符获取到知识库检索的信息(值),并传入 LLM 节点进行分析</p>
-    <p style={{marginTop: 5}}>3. natural_language_desc 变量的类型为字符串,代表在网络中检索到的信息内容,例如 "DeepSeek 今日有新模型发布"</p>
-  </div>
-</div>
-
-
-## 什么是变量引擎?
-
-变量引擎是 Flowgram 提供的一个可选内置功能,可以帮助 Workflow 设计时更高效地实现**变量信息编排**。它可以实现以下功能:
-
-<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "25px" }}>
-  <div style={{ gridColumn: "span 2" }}>
-    <b>作用域约束控制</b>
-    <p className="rs-tip">通过变量引擎,你可以控制变量的作用域,确保变量在合适的范围内可用,避免不必要的冲突。</p>
-    <div style={{display: "flex", gap: "25px"}}>
-      <div>
-        <img loading="lazy" src="/variable/variable-scope-feature-1.png" />
-        <p style={{marginTop: '10px'}}>图中 Start 节点的 query 变量,可被后续的 LLM 节点和 End 节点访问</p>
-      </div>
-      <div>
-        <img loading="lazy" src="/variable/variable-scope-feature-2.png" />
-        <p style={{marginTop: '10px'}}>图中 LLM 节点在 Condition 分支内,End 节点在 Condition 分支外;因此 End 节点的变量选择器无法选择到 LLM 节点上的 result 变量</p>
-      </div>
-    </div>
-  </div>
-  <div>
-    <b>变量信息树的维护</b>
-    <p className="rs-tip">变量引擎可以帮助你构建一个清晰的变量信息树,方便你查看和管理所有变量的状态和关系。</p>
-    <img loading="lazy" src="/variable/variable-tree-management.gif" />
-    <p style={{marginTop: '10px'}}>图中展示了多个节点 + 全局配置的输出变量;其中部分变量包含了多个子变量,形成了一棵树的结构</p>
-  </div>
-  <div>
-    <b>变量类型自动联动推导</b>
-    <p className="rs-tip">变量引擎能够根据上下文自动推导变量的类型,减少手动指定类型的工作量,提高开发效率。</p>
-    <img loading="lazy" src="/variable/variable-batch-auto-infer.gif" />
-    <p style={{marginTop: '10px'}}>图中的 Batch 节点对 Start 节点的 arr 变量进行了批处理,当 arr 变量的类型变动时,Batch 节点批处理输出的 item 变量类型也随之变动</p>
-  </div>
-</div>
-
-
-## 开启变量引擎
-
-[> API Detail](https://flowgram.ai/auto-docs/editor/interfaces/VariablePluginOptions.html)
-
-```tsx pure title="use-editor-props.ts" {3}
-
-// EditorProps
-{
-  variableEngine: {
-    /**
-     * 需要开启变量引擎才能使用
-     */
-    enable: true
-  }
-}
-```
-
-## 节点输出变量
-
-[> Demo Detail](https://github.com/bytedance/flowgram.ai/blob/main/apps/demo-fixed-layout/src/plugins/sync-variable-plugin/sync-variable-plugin.ts#L25)
-
-### 通过 FlowNodeVariableData 设置输出变量
-
-```tsx pure title="sync-variable-plugin.tsx"
-import {
-  FlowNodeVariableData,
-  ASTFactory,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-flowDocument.onNodeCreate(({ node }) => {
-  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
-
-  // ....
-
-  // 1. Clear VariableData if No value
-  variableData.clearVar()
-
-  // 2. Set a String Variable as output
-  variableData.setVar(
-    ASTFactory.createVariableDeclaration({
-      meta: {
-        title: `Your Output Variable Title`,
-      },
-      key: `your_variable_global_unique_key_${node.id}`,
-      type: ASTFactory.createString(),
-    })
-  )
-
-  // 3. Set a Complicated Variable Data as output
-  variableData.setVar(
-    ASTFactory.createVariableDeclaration({
-      meta: {
-        title: `Your Output Variable Title`,
-      },
-      key: `your_variable_global_unique_key_${node.id}`,
-      type: ASTFactory.createArray({
-        items: ASTFactory.createObject({
-          properties: [
-            ASTFactory.createProperty({
-              key: 'stringType',
-              type: ASTFactory.createString(),
-            }),
-            ASTFactory.createProperty({
-              key: 'booleanType',
-              type: ASTFactory.createBoolean(),
-            }),
-            ASTFactory.createProperty({
-              key: 'numberType',
-              type: ASTFactory.createNumber(),
-            }),
-            ASTFactory.createProperty({
-              key: 'integerType',
-              type: ASTFactory.createInteger(),
-            }),
-          ],
-        }),
-      }),
-    })
-  );
-
-  // ....
-})
-
-// ....
-
-```
-
-更多用法,详见:[Class: FlowNodeVariableData](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
-
-### 通过表单副作用设置输出变量
-
-
-```tsx pure title="node-registries.ts"
-import {
-  FlowNodeRegistry,
-  createEffectFromVariableProvider,
-  ASTFactory,
-  type ASTNodeJSON
-} from '@flowgram.ai/fixed-layout-editor';
-
-export function createTypeFromValue(value: string): ASTNodeJSON | undefined {
-  switch (value) {
-    case 'string':
-      return ASTFactory.createString();
-    case 'number':
-      return ASTFactory.createNumber();
-    case 'boolean':
-      return ASTFactory.createBoolean();
-    case 'integer':
-      return ASTFactory.createInteger();
-
-    default:
-      return;
-  }
-}
-
-export const nodeRegistries: FlowNodeRegistry[] = [
-  {
-    type: 'start',
-    formMeta: {
-      effect: {
-        'path.to.value': createEffectFromVariableProvider({
-          // parse form value to variable
-          parse(v: string) {
-            return {
-              meta: {
-                title: `Your Output Variable Title`,
-              },
-              key: `your_variable_global_unique_key_${node.id}`,
-              type: createTypeFromValue(v)
-            }
-          }
-        }),
-      },
-      render: () => (
-       // ...
-      )
-    },
-  }
-]
-
-```
-
-
-## 节点消费变量
-
-### 获取变量列表
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  useScopeAvailable,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// .... Inside react hooks or component
-
-const available = useScopeAvailable()
-
-const renderVariable = (variable: BaseVariableField) => {
-  // ....
-}
-
-return available.variables.map(renderVariable)
-
-// ....
-
-
-```
-
-### 获取 Object 类型变量的下钻
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  ASTMatch,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-const renderVariable = (variable: BaseVariableField) => ({
-  title: variable.meta?.title,
-  key: variable.key,
-  // Only Object Type can drilldown
-  children: ASTMatch.isObject(type) ? type.properties.map(renderVariable) : [],
-});
-
-// ....
-
-```
-
-### 获取 Array 类型变量的下钻
-
-```tsx pure title="use-variable-tree.tsx"
-import {
-  type BaseVariableField,
-  type BaseType,
-  ASTMatch,
-} from '@flowgram.ai/fixed-layout-editor';
-
-// ....
-
-const getTypeChildren = (type?: BaseType): BaseVariableField[] => {
-  if (!type) return [];
-
-  // get properties of Object
-  if (ASTMatch.isObject(type)) return type.properties;
-
-  // get items type of Array
-  if (ASTMatch.isArray(type)) return getTypeChildren(type.items);
-};
-
-const renderVariable = (variable: BaseVariableField) => ({
-  title: variable.meta?.title,
-  key: variable.key,
-  // Only Object Type can drilldown
-  children: getTypeChildren(variable.type).map(renderVariable),
-});
-
-// ....
-
-```

+ 5 - 0
apps/docs/src/zh/guide/advanced/variable/_meta.json

@@ -0,0 +1,5 @@
+[
+  "basic",
+  "variable-output",
+  "variable-consume"
+]

+ 80 - 0
apps/docs/src/zh/guide/advanced/variable/basic.mdx

@@ -0,0 +1,80 @@
+# 变量基础
+
+## 业务背景
+
+在 Workflow 编排中,节点与节点之间需要传递信息。为了实现这一点,我们使用**变量**来存储和管理这些信息。
+
+:::warning 一个变量由三个主要部分组成:
+
+1. **唯一标识符**:变量的名字,用于区分不同的变量,以便在程序中可以准确地引用和使用它。如:`userName` 或 `totalAmount`。
+2. **值**:变量存储的数据。值可以是多种类型,比如数字(如 `42`)、字符串(如 `"Hello!"`)、布尔值(如 `true`)等。
+3. **类型**:变量可以存储的数据种类。类型决定了变量可以接受什么样的值。例如,一个变量可以是整数、浮点数、字符串或布尔值等。
+
+:::
+
+下面是一个流程编排的例子:WebSearch 节点获取到知识,通过 natural_language_desc 传递到 LLM 节点进行分析
+
+<div style={{display: 'flex', gap: '20px'}}>
+  <img style={{width: "50%"}} loading="lazy" src="/variable/variable-biz-context-websearch-llm.png" />
+  <div>
+    在该例子中:
+    <p style={{marginTop: 10}}>1. WebSearch 节点将信息(值)存在 natural_language_desc 为唯一标识符的变量内</p>
+    <p style={{marginTop: 5}}>2. LLM 节点通过 natural_language_desc 唯一标识符获取到知识库检索的信息(值),并传入 LLM 节点进行分析</p>
+    <p style={{marginTop: 5}}>3. natural_language_desc 变量的类型为字符串,代表在网络中检索到的信息内容,例如 "DeepSeek 今日有新模型发布"</p>
+  </div>
+</div>
+
+
+## 什么是变量引擎?
+
+变量引擎是 Flowgram 提供的一个可选内置功能,可以帮助 Workflow 设计时更高效地实现**变量信息编排**。它可以实现以下功能:
+
+<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "25px" }}>
+  <div style={{ gridColumn: "span 2" }}>
+    <b>作用域约束控制</b>
+    <p className="rs-tip">通过变量引擎,你可以控制变量的作用域,确保变量在合适的范围内可用,避免不必要的冲突。</p>
+    <div style={{display: "flex", gap: "25px"}}>
+      <div>
+        <img loading="lazy" src="/variable/variable-scope-feature-1.png" />
+        <p style={{marginTop: '10px'}}>图中 Start 节点的 query 变量,可被后续的 LLM 节点和 End 节点访问</p>
+      </div>
+      <div>
+        <img loading="lazy" src="/variable/variable-scope-feature-2.png" />
+        <p style={{marginTop: '10px'}}>图中 LLM 节点在 Condition 分支内,End 节点在 Condition 分支外;因此 End 节点的变量选择器无法选择到 LLM 节点上的 result 变量</p>
+      </div>
+    </div>
+  </div>
+  <div>
+    <b>变量信息树的维护</b>
+    <p className="rs-tip">变量引擎可以帮助你构建一个清晰的变量信息树,方便你查看和管理所有变量的状态和关系。</p>
+    <img loading="lazy" src="/variable/variable-tree-management.gif" />
+    <p style={{marginTop: '10px'}}>图中展示了多个节点 + 全局配置的输出变量;其中部分变量包含了多个子变量,形成了一棵树的结构</p>
+  </div>
+  <div>
+    <b>变量类型自动联动推导</b>
+    <p className="rs-tip">变量引擎能够根据上下文自动推导变量的类型,减少手动指定类型的工作量,提高开发效率。</p>
+    <img loading="lazy" src="/variable/variable-batch-auto-infer.gif" />
+    <p style={{marginTop: '10px'}}>图中的 Batch 节点对 Start 节点的 arr 变量进行了批处理,当 arr 变量的类型变动时,Batch 节点批处理输出的 item 变量类型也随之变动</p>
+  </div>
+</div>
+
+
+## 开启变量引擎
+
+[> API Detail](https://flowgram.ai/auto-docs/editor/interfaces/VariablePluginOptions.html)
+
+```tsx pure title="use-editor-props.ts" {3}
+
+// EditorProps
+{
+  variableEngine: {
+    /**
+     * 需要开启变量引擎才能使用
+     */
+    enable: true
+  }
+}
+```
+
+
+

+ 79 - 0
apps/docs/src/zh/guide/advanced/variable/variable-consume.mdx

@@ -0,0 +1,79 @@
+# 消费变量
+
+## 在节点内获取变量树
+
+### 获取变量列表
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  useScopeAvailable,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// .... Inside react hooks or component
+
+const available = useScopeAvailable()
+
+const renderVariable = (variable: BaseVariableField) => {
+  // ....
+}
+
+return available.variables.map(renderVariable)
+
+// ....
+
+
+```
+
+### 获取 Object 类型变量的下钻
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  ASTMatch,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+const renderVariable = (variable: BaseVariableField) => ({
+  title: variable.meta?.title,
+  key: variable.key,
+  // Only Object Type can drilldown
+  children: ASTMatch.isObject(type) ? type.properties.map(renderVariable) : [],
+});
+
+// ....
+
+```
+
+### 获取 Array 类型变量的下钻
+
+```tsx pure title="use-variable-tree.tsx"
+import {
+  type BaseVariableField,
+  type BaseType,
+  ASTMatch,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+const getTypeChildren = (type?: BaseType): BaseVariableField[] => {
+  if (!type) return [];
+
+  // get properties of Object
+  if (ASTMatch.isObject(type)) return type.properties;
+
+  // get items type of Array
+  if (ASTMatch.isArray(type)) return getTypeChildren(type.items);
+};
+
+const renderVariable = (variable: BaseVariableField) => ({
+  title: variable.meta?.title,
+  key: variable.key,
+  // Only Object Type can drilldown
+  children: getTypeChildren(variable.type).map(renderVariable),
+});
+
+// ....
+
+```

+ 330 - 0
apps/docs/src/zh/guide/advanced/variable/variable-output.mdx

@@ -0,0 +1,330 @@
+# 输出变量
+
+## 输出节点变量
+
+### FlowNodeVariableData 输出变量
+
+`Flowgram` 基于 [`ECS`](https://flowgram.ai/guide/concepts/ecs.html) (Entity-Component-System) 来实现节点信息的管理。
+
+其中 [`FlowNodeVariableData`](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html) 是节点 `FlowNodeEntity` 上的一个 `Component`,专门用于处理节点上输出的 **变量信息**。
+
+
+下面的 Demo 展示了:如何拿到 `FlowNodeVariableData`, 并且通过 `FlowNodeVariableData` 实现在节点上输出变量
+
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  FlowNodeVariableData,
+  ASTFactory,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+flowDocument.onNodeCreate(({ node }) => {
+  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
+
+  // ....
+
+  // 1. Clear VariableData if No value
+  variableData.clearVar()
+
+  // 2. Set a String Variable as output
+  variableData.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  // 3. Set a Complicated Variable Data as output
+  variableData.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createArray({
+        items: ASTFactory.createObject({
+          properties: [
+            ASTFactory.createProperty({
+              key: 'stringType',
+              type: ASTFactory.createString(),
+            }),
+            ASTFactory.createProperty({
+              key: 'booleanType',
+              type: ASTFactory.createBoolean(),
+            }),
+            ASTFactory.createProperty({
+              key: 'numberType',
+              type: ASTFactory.createNumber(),
+            }),
+            ASTFactory.createProperty({
+              key: 'integerType',
+              type: ASTFactory.createInteger(),
+            }),
+          ],
+        }),
+      }),
+    })
+  );
+
+  // 4. Get Variable for current Node
+  console.log(variableData.getVar())
+
+  // ....
+})
+
+// ....
+
+```
+
+详见: [> Demo Detail](https://github.com/bytedance/flowgram.ai/blob/main/apps/demo-fixed-layout/src/plugins/sync-variable-plugin/sync-variable-plugin.ts#L25)
+
+### 一个节点设置多个输出变量
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  FlowNodeVariableData,
+  ASTFactory,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ....
+
+flowDocument.onNodeCreate(({ node }) => {
+  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);
+
+  // ...
+  // 1. Create, Update, Read, Delete Variable in namespace_1
+  variableData.setVar(
+    'namespace_1',
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key_${node.id}`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(variableData.getVar('namespace_1'))
+
+  variableData.clearVar('namespace_1')
+
+  // ....
+
+  // 2. Create, Update, Read, Delete Variable in namespace_2
+  variableData.setVar(
+    'namespace_2',
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title 2`,
+      },
+      key: `your_variable_global_unique_key_${node.id}_2`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(variableData.getVar('namespace_2'))
+
+  variableData.clearVar('namespace_2')
+
+  // ....
+})
+
+// ....
+
+```
+
+更多用法,详见:[Class: FlowNodeVariableData](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)
+
+### 表单副作用设置输出变量
+
+```tsx pure title="node-registries.ts"
+import {
+  FlowNodeRegistry,
+  createEffectFromVariableProvider,
+  ASTFactory,
+  type ASTNodeJSON
+} from '@flowgram.ai/fixed-layout-editor';
+
+export function createTypeFromValue(value: string): ASTNodeJSON | undefined {
+  switch (value) {
+    case 'string':
+      return ASTFactory.createString();
+    case 'number':
+      return ASTFactory.createNumber();
+    case 'boolean':
+      return ASTFactory.createBoolean();
+    case 'integer':
+      return ASTFactory.createInteger();
+
+    default:
+      return;
+  }
+}
+
+export const nodeRegistries: FlowNodeRegistry[] = [
+  {
+    type: 'start',
+    formMeta: {
+      effect: {
+        // Create first variable
+        // = variableData.setVar('path.to.value', ASTFactory.createVariableDeclaration(parse(v)))
+        'path.to.value': createEffectFromVariableProvider({
+          // parse form value to variable
+          parse(v: string) {
+            return {
+              meta: {
+                title: `Your Output Variable Title`,
+              },
+              key: `your_variable_global_unique_key_${node.id}`,
+              type: createTypeFromValue(v)
+            }
+          }
+        }),
+        // Create second variable
+        // = variableData.setVar('path.to.value2', ASTFactory.createVariableDeclaration(parse(v)))
+        'path.to.value2': createEffectFromVariableProvider({
+          // parse form value to variable
+          parse(v: string) {
+            return {
+              meta: {
+                title: `Your Output Variable Title 2`,
+              },
+              key: `your_variable_global_unique_key_${node.id}_2`,
+              type: createTypeFromValue(v)
+            }
+          }
+        }),
+      },
+      render: () => (
+       // ...
+      )
+    },
+  }
+]
+
+```
+
+## 输出全局变量
+
+### 获取全局变量作用域
+
+全局作用域可以在 Plugin 中通过 `ctx` 获取:
+
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  GlobalScope,
+  definePluginCreator,
+  PluginCreator
+} from '@flowgram.ai/fixed-layout-editor';
+
+
+export const createSyncVariablePlugin: PluginCreator<SyncVariablePluginOptions> =
+  definePluginCreator<SyncVariablePluginOptions, FixedLayoutPluginContext>({
+    onInit(ctx, options) {
+      const globalScope = ctx.get(GlobalScope)
+
+      globalScope.setVar(
+         ASTFactory.createVariableDeclaration({
+          meta: {
+            title: `Your Output Variable Title`,
+          },
+          key: `your_variable_global_unique_key`,
+          type: ASTFactory.createString(),
+        })
+      )
+    }
+  })
+
+```
+
+
+也可以在画布中的 React 组件内,通过 `useService` 获取全局作用域:
+
+```tsx pure title="global-variable-component.tsx"
+import {
+  GlobalScope,
+  useService,
+} from '@flowgram.ai/fixed-layout-editor';
+
+function GlobalVariableComponent() {
+
+  const globalScope = useService(GlobalScope)
+
+  // ...
+
+  const handleChange = (v: string) => {
+    globalScope.setVar(
+      ASTFactory.createVariableDeclaration({
+        meta: {
+          title: `Your Output Variable Title`,
+        },
+        key: `your_variable_global_unique_key_${v}`,
+        type: ASTFactory.createString(),
+      })
+    )
+  }
+
+  return <Input onChange={handleChange}/>
+}
+
+```
+
+
+
+### 全局作用域输出变量
+
+[`GlobalScope`](https://flowgram.ai/auto-docs/editor/classes/GlobalScope.html) 输出变量的 API 和 `FlowNodeVariableData` 类似:
+
+```tsx pure title="sync-variable-plugin.tsx"
+import {
+  GlobalScope,
+} from '@flowgram.ai/fixed-layout-editor';
+
+// ...
+
+onInit(ctx, options) {
+  const globalScope = ctx.get(GlobalScope);
+
+  // 1. Create, Update, Read, Delete Variable in GlobalScope
+  globalScope.setVar(
+    ASTFactory.createVariableDeclaration({
+      meta: {
+        title: `Your Output Variable Title`,
+      },
+      key: `your_variable_global_unique_key`,
+      type: ASTFactory.createString(),
+    })
+  )
+
+  console.log(globalScope.getVar())
+
+  globalScope.clearVar()
+
+
+  // 2.  Create, Update, Read, Delete Variable in GlobalScope's namespace: 'namespace_1'
+    globalScope.setVar(
+      'namespace_1',
+      ASTFactory.createVariableDeclaration({
+        meta: {
+          title: `Your Output Variable Title 2`,
+        },
+        key: `your_variable_global_unique_key_2`,
+        type: ASTFactory.createString(),
+      })
+  )
+
+  console.log(globalScope.getVar('namespace_1'))
+
+  globalScope.clearVar('namespace_1')
+
+  // ...
+}
+```
+
+详见:[Class: GlobalScope](https://flowgram.ai/auto-docs/editor/classes/GlobalScope.html)