Getting started Community Training Tutorials Documentation APIs, AI & Tools
# @dialect: AGENTFABRIC=1.0
After you configure the assets and other elements of your agent network project, you build the rest of the workflow using Agent Script. Agent Script enables you to build predictable, context-aware agent workflows that don’t rely solely on interpretation by an LLM.
The following sections explain settings and configurations specific to MuleSoft agent network projects. To learn more about Agent Script, see the Agent Script documentation.
Agent Script files contain a header specifying the dialect and a version binding. SEMVER major and minor are used for fixing to a specific dialect version.
The dialect header specifies that the script is strictly bound to a specific version or later of the AGENTFABRIC dialect. Deploying an agent to a runtime that doesn’t support this version results in an error.
Using major.minor (for example, AGENTFABRIC=1.1) binds to version 1.1 or later
Using major only (for example, AGENTFABRIC=1) references the latest version within that major version
Example
# @dialect: AGENTFABRIC=1.0
This section defines the instructions attribute, which acts as a default system prompt used whenever an agentic node doesn’t define its own system.instructions.
Example
system:
instructions: "You are the onboarding agent"
The system section has these parameters.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Default system prompt used when an agentic node doesn’t define its own |
String |
Yes |
The config section is the standard Agent Script config section, with the addition of the optional default_llm field. This section defines metadata and default settings for the agent.
Example
config:
agent_name: "employee-onboarding"
label: "Employee Onboarding Agent"
description: "An Agent that performs employee onboarding"
The config section has these parameters.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The name identifier for the agent. |
String |
- |
|
A human-readable display name for the agent. |
String |
- |
|
A description of what the agent does. |
String |
- |
|
Specifies a default LLM to be used on all agentic nodes that don’t specify otherwise. |
@llm reference See LLM |
No |
The llm element is where you define the LLMs to use for reasoning and generation. Each target must use the llm:// URI scheme so the runtime binds to the correct governed connection.
Example
llm:
open-api-llm:
target: "llm://open_ai_connection"
kind: "OpenAI"
model: "gpt5-mini"
reasoning_effort: "LOW"
gemini-llm:
target: "llm://gemini_connection"
kind: "Gemini"
model: "gemini-3-flash-preview"
thinking_level: "HIGH"
top_p: 0.3
The OpenAI configuration has these properties.
Bedrock OpenAI uses the openai. prefix for model names (for example, openai.gpt-5.5), which differs from the model names used with OpenAI and Azure OpenAI.
|
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Governed LLM connection as a URI; must use the |
URI ( |
Yes |
|
Discriminator for the LLM provider; selects which provider-specific attributes apply |
String, |
Yes |
|
The name of the model to use |
String |
Yes |
|
Constrains effort on reasoning for reasoning models. gpt-5.1 defaults to |
enum['NONE', 'MINIMAL', 'LOW', 'MEDIUM', 'HIGH'] |
No |
|
Controls randomness in the output |
number |
No |
|
Nucleus sampling parameter |
number |
No |
|
Number of most likely tokens to return at each position |
integer |
No |
|
Maximum number of tokens to generate |
integer |
No |
The Gemini configuration has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Governed LLM connection as a URI; must use the |
URI ( |
Yes |
|
Discriminator for the LLM provider; selects which provider-specific attributes apply |
String, |
Yes |
|
The name of the model to use |
String |
Yes |
|
The level of thoughts tokens that the model should generate |
Enum['LOW', 'HIGH'] |
No |
|
Indicates the thinking budget in tokens. 0 is DISABLED. -1 is AUTOMATIC. The default values and allowed ranges are model dependent |
Number |
No |
|
Controls the degree of randomness in token selection. Lower temperatures are good for prompts that require a less open-ended or creative response, while higher temperatures can lead to more diverse or creative results |
Number |
No |
|
Tokens are selected from the most to least probable until the sum of their probabilities equals this value. Use a lower value for less random responses and a higher value for more random responses |
Number |
No |
|
Whether to return the log probabilities of the tokens that were chosen by the model at each step |
Boolean |
No |
|
Maximum number of tokens that can be generated in the response |
Integer |
No |
You define A2A and MCP actions in Agent Script under the top-level actions block. Each action target uses a URI whose scheme is the underlying protocol (for example a2a:// or mcp://), so the runtime can route the connection correctly.
A2A actions execute the message/send A2A method and do not specify inputs or outputs.
Example
actions:
hr_agent:
target: "a2a://hr_agent_connection"
kind: "a2a:send_message"
A2A actions have these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Governed A2A connection as a URI; must use the |
URI ( |
Yes |
|
Indicates that this executes the message/send A2A method. |
"a2a:send_message" |
Yes |
MCP actions invoke Model Context Protocol actions with optional input binding.
Example
actions:
send_slack_message:
target: "mcp://slack_mcp_connection"
kind: "mcp:tool"
tool_name: "send-message"
inputs:
channel: string = "my-default-channel"
message: string
MCP actions have these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Governed MCP connection as a URI; must use the |
URI ( |
Yes |
|
Constant indicating that this invokes an MCP tool |
"mcp:tool" |
Yes |
|
The name of the tool to call |
String |
Yes |
|
Define bindable arguments. Input arguments provided are not exhaustive. The tool will auto-discover additional arguments and consider them in slot filling mode. |
Object |
No |
Triggers reference one of the interfaces defined for a broker in the agent network. Each broker must have one—and only one—trigger per each interface declared in its agent network.
The A2A trigger reacts to send/message methods and automatically manages the task history, context ID and task IDs. The trigger also responds to various A2A protocol methods.
| Agent network only supports triggers using JSON-RPC or HTTP JSON transport. |
Example
trigger employeeOnboardingTrigger:
kind: "a2a"
target: "brokers://employee-onboarding/a2a"
on_message: -> transition to @orchestrator.hrSystemOnboard
The A2A trigger has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
Value that indicates this is an A2A trigger. |
|
Yes |
|
Broker interface entry point. Must use the |
URI ( |
Yes |
|
Procedure that executes when the A2A interface receives a new |
Procedure |
Yes |
Agent network and Agent Script support these node types.
Use this table to decide which node type fits your use case.
| Subagent | Orchestrator | Generator | Executor | |
|---|---|---|---|---|
Uses an LLM |
Yes (reasoning loop) |
Yes (reasoning loop) |
Yes (single call) |
No |
Calls actions (A2A/MCP) |
Yes—LLM chooses when and how |
Yes—LLM coordinates multiple agents/tools |
No |
Yes—deterministic, fully-bound arguments |
Number of LLM iterations |
Multiple (configurable loop) |
Multiple (configurable loop) |
Exactly one |
Zero |
Slot filling ( |
Yes |
Yes |
No |
No |
Structured output schema |
Yes |
Yes |
Yes |
No |
Best for |
Single-task reasoning: classification, extraction, semantic routing, human-in-the-loop decisions |
Multi-agent coordination: delegating to several agents/tools to achieve a complex goal |
One-shot text generation: summaries, formatting, templated responses |
Deterministic execution: calling actions with known arguments, setting variables, no LLM judgment needed |
Both the orchestrator and subagent nodes run an LLM reasoning loop with access to actions. These are the key differences.
Orchestrator is optimized for workflows where the LLM must coordinate multiple external agents and tools to achieve a goal. The LLM decides which agents to call, in what order, and how to combine their results. Use it when the node needs access to two or more actions and the sequencing between them requires judgment.
Subagent is a general-purpose reasoning node ideal for single-task work: classifying input, extracting structured data, making a routing decision, or interacting with one tool. It also supports human-in-the-loop patterns where the LLM can request clarification.
If the node coordinates multiple agents or tools toward a shared goal, use orchestrator. If it reasons about a single task (even if it uses one action), use subagent.
|
This node defines a generic agent loop node, made of a prompt and a set of actions. Because it can use actions and supports human-in-the-loop flows, this node is ideal for implementing patterns like classification, semantic routing, or LLM reasoning.
Example
- subagent profile-extractor:
description: "Extracts structured user profile data from text"
reasoning:
instructions: -> Extract the following information from the user's message: {!@request.payload.message.parts[0].text}
outputs:
properties:
name:
type: "string"
description: "Full name of the person"
minLength: 1
email:
type: "string"
description: "Email address"
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
age:
type: "integer"
description: "Person's age"
minimum: 0
maximum: 150
preferences:
type: "object"
description: "User preferences"
properties:
newsletter:
type: "boolean"
description: "Whether user wants newsletter"
default: "false"
category:
type: "string"
description: "Preferred category"
enum:
- "tech"
- "business"
- "sports"
tags:
type: "array"
description: "Interest tags"
items:
type: "string"
minItems: 1
maxItems: 10
max_number_of_loops: 5
max_consecutive_errors: 5
task_timeout_secs: 30
on_exit: -> transition to @orchestrator.process_profile
The subagent node has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
A procedure that executes when the node execution finishes. If |
Procedure, but only |
No |
|
Overrides the default LLM setting |
@llm reference See LLM Section |
No |
|
Overrides the global |
String |
No |
|
Session-specific query or instructions for this particular node, typically containing user provided or user related context |
String |
Yes |
|
The available actions |
Array[actions] |
No |
|
Schema definition describing the expected structure of the agent’s output |
Outputs See Node Outputs |
No |
|
The maximum number of loops an execution can take. Useful for keeping the execution from running too long and consuming too many tokens. Default: 25 |
Integer |
No |
|
The maximum number of consecutive errors allowed during execution. Useful for keeping the node from running too long and consuming too many tokens. |
Integer |
No |
|
A timeout (in seconds) for the total node execution. |
Integer |
No |
|
A schema definition for the agentic output. |
Object See Node Outputs |
No |
The orchestrator node is a specialization of the subagent node used for orchestrating multiple agents and MCP servers to achieve a specified goal. It is optimized for multi-agent orchestration. Use this node type for workflows that need to call multiple external agents or actions to achieve a goal.
Example
orchestrator flight-booking-agent:
description: books flights by looking for the best offer across approved partners
system:
instructions: "You are a flight booking agent. The process for flight booking is: 1. Ask the user for a destination and travel dates and present them with matching alternatives using available actions. 2. Allow the user to change or refine the search. 3. Once the user selects a flight, book it using the concur agent tool."
reasoning:
instructions: -> @request.payload.message.parts[0].text
actions:
search-flight: @actions.search-flight with companyId = @variables.companyId
get-flight-info: @actions.get-flight-info
concur: @actions.concur-agent with http_headers = {"Authorization": @request.headers["Authorization"]}
max_number_of_loops: 10
max_consecutive_errors: 10
task_timeout_secs: 60
outputs:
properties:
flightNumber:
type: "string"
description: "The flight identification number"
airline:
type: "string"
description: "The airline name"
on_exit: -> transition to @executor.send_summary
The orchestrator node has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
A procedure that executes when the node execution finishes. If |
Procedure, but only |
No |
|
Overrides the default LLM setting |
@llm reference See LLM Section |
No |
|
Overrides the global |
String |
No |
|
Session-specific query or instructions for this particular node, typically containing user provided or user related context |
String |
Yes |
|
The available actions |
Array[actions] |
No |
|
Schema definition describing the expected structure of the agent’s output |
Outputs See Node Outputs |
No |
|
The maximum number of loops an execution can take. Useful for keeping the execution from running too long and consuming too many tokens. Default: 25 |
Integer |
No |
|
The maximum number of consecutive errors allowed during execution. Useful for keeping the node from running too long and consuming too many tokens. |
Integer |
No |
|
A timeout (in seconds) for the total node execution. |
Integer |
No |
|
A schema definition for the agentic output. |
Object See Node Outputs |
No |
The generator node calls an LLM to generate text. It is not an agent loop, and it does not support human-in-the-loop learning or other actions. It performs exactly one LLM call. Use this node for summarization, formatting, or templated text generation.
Example
generator summarize-report:
description: "Generate a one-paragraph summary of the report."
prompt: "Summarize the following in one paragraph: {!@variables.report}"
on_exit: -> transition to ...
The generator node has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
A procedure that executes when the node execution finishes. If |
Procedure, but only |
No |
|
A reference to the LLM connection. |
@llm reference See LLM Section |
No |
|
Overrides the global |
String |
No |
|
Session-specific query or instructions for this particular node, typically containing user provided or user related context. |
String |
Yes |
|
A schema definition for the agentic output. |
Object See Node Outputs |
No |
The executor node executes Agent Script statements deterministically and no LLM is involved. Because there is no LLM reasoning loop, every action argument must be fully resolved at execution time (you cannot use slot filling … in an executor). Use this node when you need to call an action with known arguments, store a computed value in a variable, or chain multiple deterministic steps before transitioning.
Example
executor sendHrSlackUpdate:
do: -> run @actions.send_slack_message with text=@generator.generate-hr-slack-update-message.output with channel_id="my-onboarding-channel-id"
on_exit: -> transition to @router.countrySwitch
Example with multiple statements:
executor prepareAndNotify:
description: "Sets the ticket status variable and sends a Slack notification."
do: ->
set @variables.ticketStatus = "resolved"
run @actions.send_slack_message
with text="Ticket " + @generator.classifySeverity.output.ticket_id + " resolved"
with channel_id=@variables.notificationChannel
on_exit: -> transition to @echo.finalResponse
The executor node has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
A procedure that executes when the node execution finishes. If |
Procedure, but only |
No |
|
A procedure containing one or more Agent Script statements to execute deterministically. See Supported Statements in |
Procedure |
Yes |
doThe do block accepts a procedure (→) containing one or more of these statements:
| Statement | Description | Example |
|---|---|---|
|
Invoke a defined action. Use |
|
|
Store a value in a workflow variable for use in downstream nodes. |
|
The router node performs dynamic transitions based on deterministic conditions. This node doesn’t support transition to in its on_exit attribute. Use this node for branching based on structured output from a previous node.
Example
router countryRouter:
routes:
- target: @orchestrator.argentinaOnboard
when: @orchestrator.hrSystemOnboard.output.country == "ARG"
label: "Argentina"
- target: @orchestrator.usOnboard
when: @orchestrator.hrSystemOnboard.output.country == "USA"
label: "USA"
otherwise:
target: @echo.invalidCountryResponse
The router node has these properties.
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
An array of condition and target pairs, plus an optional label field for UI. Must define at least one route. Each route contains: |
Array |
Yes |
|
Defines a default transition when no route condition matches. Contains: |
Object |
Yes with |
The echo node sends a response back to the client. The number of responses depends on the trigger interface and its configuration. Use this node for the end of a workflow, or anytime you want to emit a response.
Example
echo addArtifact:
kind: "a2a:artifact_update_event"
artifact: a2a.artifact({
artifactId: uuid(),
name: "myArtifact",
description: "this is optional",
parts: [
a2a.textPart("You have been onboarded! Your employee ID is " + @orchestrator.hrSystemOnboard.output.employeeId)
],
metadata: {},
}),
append: false
lastChunk: false
echo setStatus:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED",
message: a2a.message({
messageId: uuid(),
parts: [
a2a.textPart("You have been onboarded! Your employee ID is " + @orchestrator.hrSystemOnboard.output.employeeId)
]
})
| Parameter | Description | Type | Required |
|---|---|---|---|
|
The node identifier, defined next to the node type. |
String |
Yes |
|
An optional short, human-readable display name for the node. |
String |
No |
|
A CommonMark string providing a description of the node. |
String |
No |
|
A procedure that executes when the node execution finishes. If |
Procedure, but only |
No |
|
Discriminator for the event type. Valid values: |
String |
Yes |
|
The task state. Used with |
String |
Yes (for |
|
A message object created via |
Message object |
Yes (for |
|
An artifact object created via |
Artifact object |
Yes (for |
|
Whether to append to an existing artifact. Used with |
Boolean |
No |
|
Whether this is the last chunk of the artifact. Used with |
Boolean |
No |
|
Optional metadata dictionary. |
dict |
No |
The following table summarizes echo node parameters organized by kind.
| Kind | Required Parameters | Optional Parameters |
|---|---|---|
|
|
|
|
|
|
The following table describes echo node behavior based on the A2A operation used by the client.
| Operation / Condition | Echo Behavior |
|---|---|
|
Each echo invocation updates the stored task. Each echo invocation emits a push notification payload for all created push notifications. A consolidated response is emitted when the graph ends or is suspended. |
|
An immediate response is sent before graph execution is triggered. The response includes the task and context ID. A stored task entry with the response already exists before graph execution begins. All echo invocations update the stored task atomically (including consolidated and individual events). Each echo invocation emits a push notification payload for all created push notifications. |
|
All echo invocations update the stored task atomically (including consolidated and individual events). All individual events are sent through the event stream. Each echo invocation emits a push notification payload for all created push notifications. |
|
This condition works on top of the scenarios above. Any task in a non-terminal state can be subscribed to. Whenever echo is executed, events are pushed to all subscribed clients. |
The a2a namespace provides a set of functions that support A2A Task object creation. Do not prefix these functions with @ as it’s reserved for references such as @variables, @actions, @request, and @orchestrator.<nodeId>.
| Function | Description | Input Arguments | Output | Example |
|---|---|---|---|---|
|
Builds an A2A Message object |
|
|
|
|
Builds a TextPart object (kind: "text") |
|
|
|
|
Builds a DataPart object (kind: "data") |
|
|
|
|
Builds a FilePart object (kind: "file") |
|
|
|
|
Builds an A2A Artifact object |
|
|
|
Usage notes:
Functions are designed to be composed: a2a.message and a2a.artifact accept parts created by a2a.textPart/a2a.dataPart/a2a.filePart.
a2a.filePart requires either uri OR bytes (base64-encoded), but not both.
a2a.artifact auto-generates artifactId if it’s not provided.
All metadata parameters are optional and accept arbitrary dictionaries.
For tasks, it’s not necessary to define the id, contextId and history attributes, those are automatically populated by the trigger.
Use these functions in expressions alongside references and interpolations. They include time and ID helpers (now, uuid), string utilities (strip, startswith, and endswith), JSON parsing (parse_json), and common numeric helpers (abs, round, and sum) for deterministic math-style logic without calling external tools.
| Function | Description | Input arguments | Output | Example |
|---|---|---|---|---|
|
Current UTC time in ISO 8601 format |
None |
String (ISO 8601) |
|
|
Random UUID v4 |
None |
String (UUID) |
|
|
Removes leading/trailing characters from a string |
String, optional chars (default: whitespace) |
String |
|
|
Whether a string starts with a prefix |
String, prefix |
Boolean |
|
|
Whether a string ends with a suffix |
String, suffix |
Boolean |
|
|
Absolute value |
Number |
Number |
|
|
Round to optional digit count |
Number, optional |
Number |
|
|
Sum of a numeric list |
List |
Number |
|
|
Parse a JSON string |
String (valid JSON) |
Object or array |
|
Use the outputs field to define the expected shape of the agent’s response using a schema notation similar to a JSON schema. When provided, the agent produces output matching the defined structure for downstream parsing and processing.
Each property maps to a field in the agent’s output. These types are supported.
Note: Advanced JSON schema features are not supported, so do not copy patterns from generic JSON Schema tutorials unless they match what is documented here.
| Type | Description |
|---|---|
String |
Text values with optional constraints like |
Number / Integer |
Numeric values with optional constraints like |
Boolean |
|
Array |
Lists of items, where |
Object |
Nested structures with their own |
Each property definition can include:
type: The data type (required).
description: A human-readable explanation of the property’s purpose.
default: A default value if the property is omitted.
The outputs definition doesn’t support:
additionalProperties or similar JSON Schema extensibility flags
Combinators such as anyOf, oneOf, or allOf
References or shared definitions ($ref, $defs)
Composition beyond nested object / array structures as described above
Nodes access data from other parts of the workflow using expressions.
These references are used.
| Prefix | Reference | Example |
|---|---|---|
|
LLM definitions |
|
|
action definitions |
|
|
Trigger request data |
|
|
HTTP headers (case-insensitive) |
|
|
Workflow variables |
|
|
Node references |
|
Every node has .output (the value it produced) and .input (the output of whichever node transitioned into it).
If a node doesn’t produce a value (for example, a router), its .output is None.
If the preceding node is a trigger, .input is None.
Example
@orchestrator.hrSystemOnboard.output.employeeId # returns the `employeeId` property of the object returned by the `hrSystemOnboard` node @generator.writeEmailContent.output # returns the string generated by the `writeEmailContent` node
.output vs .inputUse .output when you know exactly which upstream node you need data from. In a straight-line graph, .output is the simplest approach:
process ──► generate_email ──► send_email
generate_email reads @subagent.process.output as the source content.
send_email reads @generator.generate_email.output as its content.
An expression can target any preceding node in the graph, not only the node immediately before the current node.
To decouple a node from the path that reached it, use .input. In this example, @generator.generate_email.input returns the output from whichever of node_a, node_b, or node_c transitioned into generate_email:
node_a ──┐ node_b ──┼──► generate_email ──► send_email node_c ──┘
The @request namespace provides access to the trigger’s incoming request data. Use @request expressions to read the payload, headers, and other properties of the request that started the workflow.
@request.payload: Returns the request payload. For the on_message handler of the A2A trigger, this expression returns a SendMessageRequest object.
@request.interface: Returns the name of the interface that produced the message (for example, a2a).
For A2A triggers, these additional references are also available:
@request.headers: A case-insensitive dictionary of the HTTP request headers. For example, @request.headers["Authorization"] and @request.headers["authorization"] return the same value.
@request.taskId: The current A2A task ID, either provided in the request or automatically generated by the trigger.
@request.contextId: The current A2A context ID, either provided in the request or automatically generated by the trigger.
Example
reasoning:
instructions: -> @request.payload.message.parts[0].text
actions:
concur: @actions.concur-agent with http_headers = {"Authorization": @request.headers["Authorization"]}
Any actions that connect to an external system often need to set custom headers. Use cases range from propagating authorization headers (for example, in OBO authentication) to adding custom correlation information.
For this, both the MCP and A2A actions automatically get an implicit optional http_headers parameter object type that can be used to set those:
actions:
my_hr_agent: @actions.hr_agent with http_headers = {"Authorization": @request.headers["Authorization"], "X-CorrelationId": @variables.conversationId}
Use {!expression} to embed values inside strings.
Example
prompt: "The employee's country is {!@orchestrator.hrOnboard.output.country}"
Use slot filling (…) to tell an LLM to figure out a value.
Example
actions:
send_message: @actions.send_slack_message with message = ...
# LLM decides the message content
When you reference a tool inside a node, you can fix, default, or slot-fill its arguments using with.
Example
actions:
# All arguments via slot filling (LLM decides everything)
sendToDefault: @actions.send_slack
# Fix the channel, LLM fills the message
sendToFixed: @actions.send_slack with channel = "agent-fabric"
# Fix everything -- fully deterministic
fullyDeterministic: @actions.send_slack with message = @variables.calculatedMessage with channel = @variables.channelId