Skip to main content

Creating Service Providers

This guide details the process for developers to create service provider plugins for integrating backend systems (for example, HR platforms, CRMs) with the Solace Agent Mesh (SAM).

Understanding Service Providers

Service Providers function as the abstraction layer between SAM and enterprise data sources. They are implemented as Python classes that adhere to a specific abstract base class, enabling standardized interaction between SAM components (Gateways and Agents) and the underlying data.

There are two primary service provider interfaces:

  • BaseIdentityService: Responsible for identity enrichment. This service is utilized by Gateways to augment the profile of an authenticated user with additional details (for example, full name, job title) based on their initial authentication claims.
  • BaseEmployeeService: Responsible for general directory querying. This service is utilized by agents (for example, the EmployeeAgent) to execute lookups across the entire employee directory.

The "Dual-Role Provider" Pattern

In many enterprise systems, particularly HR platforms, the data source for identity enrichment and general employee queries is identical. To optimize development, SAM promotes a "Dual-Role Provider" pattern.

This pattern involves creating a single class that inherits from both BaseIdentityService and BaseEmployeeService. This consolidated class can then be configured to fulfill either or both roles, thereby reducing code duplication.

Step-by-Step Implementation Guide

This section provides a walkthrough for creating a new provider for a fictional "CorpHR" system.

Step 1: Establish the Plugin Structure

The recommended structure for a custom service provider plugin should include a pyproject.toml for packaging and a src directory for the source code.

sam plugin create my_corp_hr_provider --type custom

Step 2: Define the Provider Class

Create a provider.py module and define the provider class, ensuring it inherits from both base service classes.

# my_corp_hr_provider/provider.py

# Import base classes from the SAM framework
try:
from solace_agent_mesh.common.services.identity_service import BaseIdentityService
from solace_agent_mesh.common.services.employee_service import BaseEmployeeService
except ImportError:
# Fallback for local development environments
from src.solace_agent_mesh.common.services.identity_service import BaseIdentityService
from src.solace_agent_mesh.common.services.employee_service import BaseEmployeeService

# Import any other necessary libraries, such as 'requests' or a proprietary SDK
# from .corp_hr_sdk import CorpHR_SDK

class CorpHRProvider(BaseIdentityService, BaseEmployeeService):
"""
A dual-role provider for the CorpHR system, implementing methods
for both identity enrichment and employee directory services.
"""
def __init__(self, config):
super().__init__(config)
# Initialize the backend service/SDK client here.
# It is best practice to implement this as a singleton to share
# connection pools and cache.
# self.corp_hr_sdk = CorpHR_SDK(api_key=config.get("api_key"))

# --- BaseIdentityService Method Implementations ---

async def get_user_profile(self, auth_claims):
"""Enrich the current user's profile based on their auth claims."""
# TODO: Implement logic to fetch user data from CorpHR
pass

async def search_users(self, query, limit=10):
"""Search for users, for features like @-mentions."""
# TODO: Implement user search logic against CorpHR
pass

# --- BaseEmployeeService Method Implementations ---

async def get_employee_dataframe(self):
"""Return all employees as a pandas DataFrame for directory-wide queries."""
# TODO: Fetch all employee data and return as a DataFrame
pass

async def get_employee_profile(self, employee_id):
"""Get a single employee's full profile by their ID."""
# Note: This is a general directory lookup, distinct from get_user_profile.
# TODO: Implement single employee lookup
pass

async def get_time_off_data(self, employee_id):
"""Get an employee's raw time off data."""
# Example return format:
# return [{'start': '2025-07-04', 'end': '2025-07-04', 'type': 'Holiday'}]
# TODO: Implement time off data retrieval
pass

async def get_employee_profile_picture(self, employee_id):
"""Fetch a profile picture as a data URI string."""
# Example return format: "data:image/jpeg;base64,..."
# TODO: Implement profile picture fetching
pass

Step 3: Map to the Canonical Employee Schema

When implementing the service methods, it is mandatory to map the data from the source system to SAM's canonical employee schema. This ensures data consistency and interoperability with all tools and components across the mesh.

Field NameData TypeDescription
idstringA unique, stable, and lowercase identifier (e.g., email, GUID).
displayNamestringThe employee's full name for display purposes.
workEmailstringThe employee's primary work email address.
jobTitlestringThe employee's official job title.
departmentstringThe department to which the employee belongs.
locationstringThe physical or regional location of the employee.
supervisorIdstringThe unique id of the employee's direct manager.
hireDatestringThe date the employee was hired (ISO 8601: YYYY-MM-DD).
mobilePhonestringThe employee's mobile phone number (optional).
info

If a field is not available in the source system, return None or omit the key from the returned dictionary.

Step 4: Register the Plugin

To make the provider discoverable by SAM, it must be registered as a plugin via entry points.

1. Add an entry point in pyproject.toml: The key assigned here (corphr) is used as the type identifier in YAML configurations.

[project.entry-points."solace_agent_mesh.plugins"]
corphr = "my_corp_hr_provider:info"

2. Define the info object in the plugin's __init__.py: This object points to the provider's class path and provides a brief description.

# my_corp_hr_provider/__init__.py
info = {
"class_path": "my_corp_hr_provider.provider.CorpHRProvider",
"description": "Identity and People Service provider for CorpHR.",
}

Configuring the Provider

Once the plugin is created and installed (for example, via pip install .), it can be configured in any Gateway or Agent app_config.yml.

For a Gateway (Identity Service Role):

app_config:
identity_service:
type: "corphr" # Matches the key in pyproject.toml
api_key: "${CORPHR_API_KEY}"
lookup_key: "email" # The field from auth_claims to use for lookup

For an Agent (Employee Service Role): This example demonstrates configuring the provider for the employee_tools group.

app_config:
tools:
- tool_type: builtin-group
group_name: "employee_tools"
config:
type: "corphr" # Same provider, different role
api_key: "${CORPHR_API_KEY}"