Tip: How Does the Event Mesh Entrypoint Work in Solace Agent Mesh?
Solace Agent Mesh is an event-driven framework for building distributed ecosystems of collaborative AI agents, powered by the Solace Event Mesh for enterprise-grade agent orchestration. Agents do the thinking. But what if the trigger for an agent task is not a human typing a prompt, but a business event flowing through your message broker? That is where the Event Mesh Entrypoint comes in.
The Event Mesh Entrypoint is a plugin that bridges your Solace event mesh (the data plane) with the Agent Mesh ecosystem (the control plane). External systems publish events to Solace topics. The Entrypoint picks them up, transforms them into agent tasks, and publishes agent responses back to the event mesh for consumption by other applications.
In this post, we will walk through how the Event Mesh Entrypoint works, how to install and configure it, the key concepts behind event handlers and output handlers, and practical examples you can use as starting points.
How It Works
The Event Mesh Entrypoint maintains two separate Solace broker connections:
-
Control Plane (A2A): The standard Agent Mesh broker connection used for agent-to-agent communication via the A2A protocol. This is how the Entrypoint submits tasks to agents and receives responses.
-
Data Plane: A dedicated Solace client that connects to your existing broker infrastructure. This can be the same broker or a completely different one. This is where your business events flow.
The processing flow is:
- An external system publishes an event on a Solace topic on the data plane (e.g.,
orders/placed/ORD-20250612-001) - The Event Mesh Entrypoint picks up the message, transforms it into an agent prompt, and submits it as an A2A task on the control plane
- Agents process the task and return a response
- The Entrypoint’s output handler transforms the response and publishes it back to the data plane (e.g.,
orders/validated)
The Entrypoint itself makes no LLM calls. It is a translation and routing layer between your event mesh and the Agent Mesh.
Installation
Install the Event Mesh Entrypoint plugin:
sam plugin add my-event-mesh --plugin sam-event-mesh-gateway
See the Plugins documentation for all installation options and the sam-event-mesh-gateway documentation.
This creates a configuration file at configs/gateways/my-event-mesh.yaml. Edit the config for your environment (see Configuration section below), then start it:
sam run configs/gateways/my-event-mesh.yaml
Core Concepts
Event Handlers (Input Side)
An event handler defines what to listen for on the data plane and how to process it. Each handler has:
- Subscriptions: Solace topic filters to subscribe to (with wildcard support:
*for one level,>for one or more) - Input expression: How to transform the incoming message into an agent prompt
- Target agent: Which agent to send the task to (static or dynamic)
- Forward context: Data to extract from the message and carry through to the output handler
- On success / on error: Which output handlers to route results to
Output Handlers (Response Side)
An output handler defines how to format and publish agent responses back to the data plane. Each handler has:
- Topic expression: The Solace topic to publish the response to (can include forwarded context for correlation)
- Payload expression: How to extract and format the agent’s response
- Output schema: Optional JSON Schema validation before publishing
Expression Engine
Both input and output handlers use an expression engine for transformations. The most common form is template: syntax:
template:Validate this order: Customer: {{text://input.payload:customerName}}, Items: {{text://input.payload:items}}, Total: {{text://input.payload:totalAmount}}
Available input selectors:
| Selector | Description |
|---|---|
input.payload |
Full decoded message payload |
input.payload:field |
Specific field from the payload |
input.topic: |
The incoming topic string |
input.user_properties:key |
Solace user properties |
json://input.payload |
JSON-serialized full payload |
text://input.payload:field |
Text value of a field |
static:value |
Literal static value |
list_item:field |
Field from each item during artifact processing |
Available output selectors:
| Selector | Description |
|---|---|
task_response:text |
The agent’s text response |
task_response:files |
List of file objects from the agent |
task_response:data |
Data parts from the agent |
task_response:structured_output |
Parsed output from structured invocation |
task_response:a2a_task_response.error |
Error details |
user_data.forward_context:key |
Data forwarded from the event handler |
Configuration
Here is a complete working configuration based on an order processing use case. It listens for new orders, asks the OrchestratorAgent to validate them, and publishes the validation result back to the event mesh.
log:
stdout_log_level: INFO
log_file_level: DEBUG
log_file: my-event-mesh.log
shared_config:
- broker_connection: &broker_connection
broker_url: ${SOLACE_BROKER_URL, ws://localhost:8008}
broker_username: ${SOLACE_BROKER_USERNAME, default}
broker_password: ${SOLACE_BROKER_PASSWORD, default}
broker_vpn: ${SOLACE_BROKER_VPN, default}
- services:
artifact_service: &default_artifact_service
type: "filesystem"
base_path: "/tmp/samv2"
artifact_scope: namespace
apps:
- name: my-event-mesh-app
app_module: sam_event_mesh_gateway.app
broker:
<<: *broker_connection
app_config:
namespace: "${NAMESPACE}"
gateway_id: "event-mesh-gw-01"
artifact_service: *default_artifact_service
default_user_identity: "sam_dev_user"
# Data Plane Connection (can be the same or different broker)
event_mesh_broker_config:
broker_url: ${DATAPLANE_SOLACE_BROKER_URL, ws://localhost:8008}
broker_vpn: ${DATAPLANE_SOLACE_BROKER_VPN, default}
broker_username: ${DATAPLANE_SOLACE_BROKER_USERNAME, default}
broker_password: ${DATAPLANE_SOLACE_BROKER_PASSWORD, default}
event_handlers:
- name: "order_placed_handler"
subscriptions:
- topic: "orders/placed/>"
qos: 1
input_expression: >
template:Validate the following new order and check for any issues
(missing fields, suspicious amounts, invalid quantities):
Order ID: {{text://input.payload:orderId}},
Customer: {{text://input.payload:customerName}},
Items: {{json://input.payload:items}},
Total: {{text://input.payload:totalAmount}}.
Return a JSON object with fields 'orderId', 'status' (valid or flagged), and 'notes'.
payload_format: "json"
payload_encoding: "utf-8"
target_agent_name: "OrchestratorAgent"
on_success: "order_validated_handler"
on_error: "order_error_handler"
forward_context:
order_id: "input.payload:orderId"
output_handlers:
- name: "order_validated_handler"
topic_expression: "template:orders/validated/{{text://user_data.forward_context:order_id}}"
payload_expression: "task_response:text"
- name: "order_error_handler"
topic_expression: "template:orders/error/{{text://user_data.forward_context:order_id}}"
payload_expression: "task_response:a2a_task_response.error"
Context Forwarding
Context forwarding is how you carry data from the incoming event through to the output handler. This is essential for request-reply correlation.
In the event handler, define what to extract:
forward_context:
correlation_id: "input.user_properties:correlation_id"
original_topic: "input.topic:"
order_id: "input.payload:orderId"
In the output handler, reference it:
topic_expression: "template:responses/{{text://user_data.forward_context:correlation_id}}"
This lets you route the agent’s response back to a topic that includes the original correlation ID, so downstream systems can match it to their request.
Acknowledgment Policy
The acknowledgment policy controls when the Entrypoint tells the Solace broker that a message has been processed. This is critical for delivery guarantees.
on_receive (Default)
The message is acknowledged immediately when received. If the agent fails to process it, the message is lost. This is the simplest mode and suitable for non-critical events.
on_completion (Deferred ACK)
The message stays unacknowledged until the A2A task completes AND the response is published back to the data plane. This provides at-least-once delivery.
acknowledgment_policy:
mode: "on_completion"
on_failure:
action: "nack" # "nack" or "ack"
nack_outcome: "rejected" # "rejected" (redeliver) or "failed" (DLQ)
timeout_seconds: 300
On failure behavior:
nack+rejected: the broker redelivers the messagenack+failed: the broker sends the message to the Dead Letter Queue (DLQ)ack: the message is acknowledged and discarded even on failure
Timeout: If the agent does not respond within timeout_seconds, the message is settled as a failure.
Rate limiting: Combine deferred ACK with the Solace broker’s max-delivered-unacked-msgs-per-flow setting to control how many messages are processed concurrently. For example, setting it to 5 means the Entrypoint will have at most 5 in-flight tasks at any time.
You can set the policy at the gateway level (applies to all handlers) or override it per handler:
event_handlers:
- name: "low_priority_handler"
# Uses gateway default (on_receive)
subscriptions:
- topic: "events/low/>"
...
- name: "critical_order_handler"
acknowledgment_policy:
mode: "on_completion"
on_failure:
nack_outcome: "failed" # Send to DLQ on failure
timeout_seconds: 120
subscriptions:
- topic: "orders/placed/>"
...
User Identity
User identity is resolved in the following priority order:
user_identity_expressionon the handler: expression evaluated against the incoming message (e.g.,"input.user_properties:user_id"or"input.payload:userId")default_user_identityon the handler: fallback if the expression yields nothing
Tip: Set
default_user_identity: "sam_dev_user"at the gateway level to match the WebUI’s default user. This lets you visualize Event Mesh tasks in the WebUI’s Activities tab.
Dynamic Agent Selection
You can route events to different agents based on message content.
Static routing (same agent for all events on this handler):
target_agent_name: "OrchestratorAgent"
Dynamic routing (agent determined by message content):
target_agent_name_expression: "input.user_properties:target_agent"
The expression is evaluated against each incoming message. If it fails or returns empty, the Entrypoint falls back to target_agent_name.
You can also target workflows instead of individual agents:
target_workflow_name: "OrderProcessingWorkflow"
# or dynamically:
target_workflow_name_expression: "input.payload:workflow_name"
Artifact Processing
For messages that contain files (binary payloads or embedded documents in JSON), the Entrypoint can extract them as artifacts before sending to agents.
Binary Payload (e.g., IoT Camera Image)
- name: "iot_image_handler"
subscriptions:
- topic: "iot/camera/*/image"
payload_format: "binary"
artifact_processing:
extract_artifacts_expression: "input.payload"
artifact_definition:
filename: "template:image-{{text://input.user_properties:deviceId}}.jpg"
content: "list_item:"
mime_type: "static:image/jpeg"
content_encoding: "static:binary"
input_expression: "template:Analyze the attached security camera image for anomalies."
target_agent_name: "ImageAnalysisAgent"
Embedded Documents in JSON (e.g., Insurance Claims)
- name: "insurance_claim_handler"
subscriptions:
- topic: "claims/new"
artifact_processing:
extract_artifacts_expression: "input.payload:documents"
artifact_definition:
filename: "list_item:docName"
content: "list_item:docContent"
mime_type: "list_item:docType"
content_encoding: "list_item:encoding"
input_expression: "template:Process insurance case {{text://input.payload:caseId}}."
target_agent_name: "ClaimsProcessingAgent"
Testing with Try Me
You can test the Event Mesh Entrypoint without any external systems. The example configuration listens for JSON events on order topics, but no actual order management system is involved. You are simply publishing a Solace message that simulates what an order system would produce.
Step 1: Subscribe to responses
Open the Solace broker web console (e.g., http://localhost:8080), go to the Try Me tab, and in the Subscriber section, subscribe to:
orders/validated/>
This is where the Entrypoint will publish agent responses.
Step 2: Publish a test event
In the Publisher section of Try Me, set:
- Topic:
orders/placed/ORD-20250612-001 - Message:
{"orderId": "ORD-20250612-001", "customerName": "Acme Corp", "items": [{"sku": "WIDGET-100", "qty": 50, "price": 12.99}, {"sku": "GADGET-200", "qty": 10, "price": 49.99}], "totalAmount": 1149.40}
Click Publish.
What happens
- The Entrypoint picks up the message from the
orders/placed/>subscription - The event handler transforms it into a prompt: “Validate the following new order and check for any issues: Order ID: ORD-20250612-001, Customer: Acme Corp, Items: […]…”
- The OrchestratorAgent processes the prompt using the LLM and generates a validation result
- The Entrypoint publishes the result to
orders/validated/ORD-20250612-001via the output handler - Your Try Me subscriber receives the response
No external systems are involved. The entire flow is Solace messages in, agent processing, Solace messages out.
Tip: You may be able to watch Event Mesh tasks in the WebUI’s Activities tab by ensuring the Entrypoint’s
default_user_identitymatches the WebUI’s default (sam_dev_user). Alternatively, configure the WebUI admin user with thetasks:read:allscope to see tasks from all Entrypoints. Check with your admin for the exact setup.
Event Mesh vs. REST vs. Webhook
| Event Mesh | REST | Webhook | |
|---|---|---|---|
| Transport | Solace broker topics | HTTP API | HTTP endpoints |
| Trigger | Events on Solace topics | HTTP request from client | HTTP POST from external service |
| Response | Published back to Solace topics | Polling-based result retrieval | Transforms webhook payloads to A2A messages |
| Connection | Persistent Solace subscriber | HTTP server | HTTP server |
| Delivery guarantee | At-least-once via deferred ACK | HTTP-level | HTTP-level |
| Bidirectional | Yes (subscribe + publish on data plane) | Yes (submit + poll) | No (inbound only) |
| Input transform | Template expressions | Per gateway docs | Per gateway docs |
| Use case | Event-driven integration for Solace users | Programmatic API access | Third-party webhooks (GitHub, Stripe) |
The Event Mesh Entrypoint is purpose-built for organizations that already run a Solace event mesh. It adds AI agent capabilities to your existing event-driven architecture without introducing HTTP or new protocols. For a full overview of all available Entrypoint types, see the Gateways documentation.
Last Words of Wisdom
-
Start with a simple handler. One event handler, one output handler, one topic. Get a message flowing end-to-end before adding context forwarding, artifact processing, or deferred ACKs.
-
Use
on_receivefor development,on_completionfor production. Deferred ACK adds complexity. Get your transformations and routing right first, then switch toon_completionfor delivery guarantees. -
Forward context for correlation. If you need to route the response to a specific topic (e.g., including an order ID), use
forward_contextto carry that data through the agent processing. -
The data plane can be a different broker. The
event_mesh_broker_configdoes not have to point to the same broker as the A2A control plane. This is useful when your business events are on a separate infrastructure. -
Set
default_user_identity: "sam_dev_user"to match the WebUI default. This ensures consistent identity across Entrypoints. -
Rate limit with deferred ACK. Combine
mode: "on_completion"with the Solace broker’smax-delivered-unacked-msgs-per-flowto control concurrency. This prevents the Entrypoint from overwhelming your agents with too many simultaneous tasks. -
Test with Try Me. Use the Solace broker’s “Try Me” feature in the web console to publish test events to your subscribed topics without writing any code.
For more information about Solace Agent Mesh, visit the repository:
An event-driven framework designed to build and orchestrate multi-agent AI systems. It enables seamless integration of AI agents with real-world data sources and systems, facilitating complex, multi-step workflows.
