CRM Agent Environment SDK by Construct Labs - Train RL agents to interact with CRM systems
Project description
Construct Labs CRM Agent Environment
Python SDK for the Construct Labs CRM Agent Environment - a reinforcement learning environment for training AI agents to interact with CRM systems.
License
This software requires a commercial license from Construct Labs GmbH. Contact hello@construct-labs.com for licensing inquiries.
Installation
pip install construct-labs-crm-env
Quick Start
from construct_labs_crm_env import CrmAgentEnv, CrmAgentAction, CRMActionType
# Connect to the CRM environment
with CrmAgentEnv(
base_url="https://api.construct-labs.com",
api_key="your-api-key" # Issued by Construct Labs
) as env:
# Reset the environment
result = env.reset()
# List companies
result = env.step(CrmAgentAction(
action_type=CRMActionType.LIST_COMPANIES,
limit=10
))
print(result.observation.data)
Environment Variables
You can set your API key via environment variable:
export CRM_AGENT_API_KEY=your-api-key
# API key is read from environment
env = CrmAgentEnv(base_url="https://api.construct-labs.com")
LLM Integration Example
The SDK is designed to work with LLM-based agents. Here's how to parse LLM tool calls:
from construct_labs_crm_env import CrmAgentEnv
with CrmAgentEnv(
base_url="https://api.construct-labs.com",
api_key="your-api-key"
) as env:
result = env.reset()
# Simulate an LLM generating a tool call
llm_tool_call = {
"name": "list_companies",
"arguments": {"limit": 5}
}
# Parse the tool call into a CrmAgentAction
parsed = env.parse_tool_call(llm_tool_call)
if parsed.is_valid:
result = env.step(parsed.action)
print(result.observation.model_dump_json(indent=2))
else:
print(f"Invalid tool call: {parsed.error_message}")
Customization
Subclass CrmAgentEnv to customize agent behavior:
Custom System Prompt
class SalesAgent(CrmAgentEnv):
@property
def system_prompt(self) -> str:
return """You are a sales assistant AI.
Your goal is to help close deals by:
1. Finding relevant companies and contacts
2. Creating opportunities with accurate values
3. Adding follow-up tasks
Be concise. Focus on high-value opportunities."""
Restricted Tool Set
class ReadOnlyAgent(CrmAgentEnv):
"""Agent that can only read data, not modify."""
@property
def tools(self) -> list[dict]:
read_only = {'list_companies', 'get_company', 'list_people',
'get_person', 'list_opportunities', 'submit_answer'}
return [t for t in self._default_tools()
if t['function']['name'] in read_only]
Custom Observation Formatting
class VerboseAgent(CrmAgentEnv):
def format_observation(self, observation):
base = super().format_observation(observation)
return f"=== CRM Response ===\n{base}\n=== End ==="
Available Actions
Company Operations
LIST_COMPANIES- List all companiesGET_COMPANY- Get a specific company by IDCREATE_COMPANY- Create a new companyUPDATE_COMPANY- Update an existing companyDELETE_COMPANY- Delete a company
Contact Operations
LIST_PEOPLE- List all contactsGET_PERSON- Get a specific contact by IDCREATE_PERSON- Create a new contactUPDATE_PERSON- Update an existing contactDELETE_PERSON- Delete a contact
Opportunity Operations
LIST_OPPORTUNITIES- List all opportunitiesGET_OPPORTUNITY- Get a specific opportunity by IDCREATE_OPPORTUNITY- Create a new opportunityUPDATE_OPPORTUNITY- Update an existing opportunityDELETE_OPPORTUNITY- Delete an opportunity
Note Operations
LIST_NOTES- List all notesCREATE_NOTE- Create a note attached to a record
Task Operations
LIST_TASKS- List all tasksCREATE_TASK- Create a new taskUPDATE_TASK- Update an existing taskCOMPLETE_TASK- Mark a task as complete
Submit Answer
SUBMIT_ANSWER- Submit the final answer and end the session
Integration with Training Frameworks
Collecting Rollouts for RL Training
The SDK is designed for reinforcement learning. Here's how to collect rollouts with rewards:
from dataclasses import dataclass, field
from construct_labs_crm_env import CrmAgentEnv, CrmAgentObservation
@dataclass
class Rollout:
"""A single episode rollout for training."""
observations: list[CrmAgentObservation] = field(default_factory=list)
actions: list[dict] = field(default_factory=list) # Raw tool calls
rewards: list[float] = field(default_factory=list)
done: bool = False
total_reward: float = 0.0
def collect_rollout(env: CrmAgentEnv, agent, seed: int | None = None) -> Rollout:
"""Collect a single rollout from the environment."""
rollout = Rollout()
# Reset environment
result = env.reset(seed=seed)
rollout.observations.append(result.observation)
while not result.done:
# Get action from agent (returns tool call dict)
tool_call = agent.get_action(
system_prompt=env.system_prompt,
tools=env.tools,
observation=result.observation,
)
# Parse and execute
parsed = env.parse_tool_call(tool_call)
if parsed.is_valid:
result = env.step(parsed.action)
reward = result.reward if result.reward is not None else 0.0
else:
# Invalid action penalty
reward = -1.0
result.done = True
# Store transition
rollout.actions.append(tool_call)
rollout.rewards.append(reward)
rollout.observations.append(result.observation)
rollout.done = True
rollout.total_reward = sum(rollout.rewards)
return rollout
# Collect multiple rollouts for training
def collect_rollouts(
env: CrmAgentEnv,
agent,
num_rollouts: int,
seed_offset: int = 0,
) -> list[Rollout]:
"""Collect multiple rollouts for batch training."""
rollouts = []
for i in range(num_rollouts):
rollout = collect_rollout(env, agent, seed=seed_offset + i)
rollouts.append(rollout)
return rollouts
# Example usage
with CrmAgentEnv(
base_url="https://api.construct-labs.com",
api_key="your-api-key"
) as env:
# Collect 10 rollouts
rollouts = collect_rollouts(env, your_agent, num_rollouts=10)
# Compute statistics
avg_reward = sum(r.total_reward for r in rollouts) / len(rollouts)
avg_length = sum(len(r.actions) for r in rollouts) / len(rollouts)
print(f"Average reward: {avg_reward:.2f}")
print(f"Average episode length: {avg_length:.1f}")
GRPO Training Integration
For Group Relative Policy Optimization (GRPO) training:
from construct_labs_crm_env import CrmAgentEnv
def collect_grpo_group(
env: CrmAgentEnv,
agent,
group_size: int = 8,
seed: int = 0,
) -> list[Rollout]:
"""Collect a group of rollouts with the same seed for GRPO."""
group = []
for _ in range(group_size):
# Same seed = same initial state, different agent samples
rollout = collect_rollout(env, agent, seed=seed)
group.append(rollout)
return group
def compute_grpo_advantages(group: list[Rollout]) -> list[float]:
"""Compute relative advantages within a group."""
rewards = [r.total_reward for r in group]
mean_reward = sum(rewards) / len(rewards)
std_reward = (sum((r - mean_reward) ** 2 for r in rewards) / len(rewards)) ** 0.5
if std_reward < 1e-8:
return [0.0] * len(rewards)
return [(r - mean_reward) / std_reward for r in rewards]
# Training loop
with CrmAgentEnv(
base_url="https://api.construct-labs.com",
api_key="your-api-key"
) as env:
for step in range(num_training_steps):
# Collect group of rollouts
group = collect_grpo_group(env, agent, group_size=8, seed=step)
# Compute advantages
advantages = compute_grpo_advantages(group)
# Update policy using advantages
agent.update(group, advantages)
Basic Training Loop
from construct_labs_crm_env import CrmAgentEnv
env = CrmAgentEnv(
base_url="https://api.construct-labs.com",
api_key="your-api-key"
)
with env:
result = env.reset(seed=42)
while not result.done:
# Get action from your agent/LLM
tool_call = your_agent.get_action(
env.system_prompt,
env.tools,
result.observation
)
# Parse and execute
parsed = env.parse_tool_call(tool_call)
if parsed.is_valid:
result = env.step(parsed.action)
else:
# Handle invalid action
print(f"Invalid action: {parsed.error_message}")
break
API Reference
CrmAgentEnv
Main client class for interacting with the CRM environment.
Constructor:
base_url(str): Base URL of the CRM environment serverapi_key(str, optional): API key for authenticationconnect_timeout_s(float): Connection timeout in seconds (default: 10)message_timeout_s(float): Message timeout in seconds (default: 60)
Methods:
reset(seed=None)- Reset the environmentstep(action)- Execute an actionstate()- Get current environment stateclose()- Close the connectionparse_tool_call(tool_call)- Parse LLM tool call to actionformat_observation(observation)- Format observation for LLM
Properties (overridable):
system_prompt- System prompt for the agenttools- Available tool definitions
CrmAgentAction
Pydantic model for CRM actions.
action = CrmAgentAction(
action_type=CRMActionType.CREATE_COMPANY,
company_name="Acme Corp",
company_domain="acme.com",
company_employees=100
)
CrmAgentObservation
Pydantic model for CRM observations.
success(bool): Whether the action succeedederror(str | None): Error message if faileddata(dict): Raw response datadone(bool): Whether episode has endedreward(float | None): Reward signal
Use observation.model_dump_json() to get JSON representation.
Support
For licensing, technical support, or questions:
Email: hello@construct-labs.com
License
Copyright (c) 2024 Construct Labs GmbH. All rights reserved.
This software is proprietary and requires a commercial license. See LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file construct_labs_crm_env-0.1.7.tar.gz.
File metadata
- Download URL: construct_labs_crm_env-0.1.7.tar.gz
- Upload date:
- Size: 17.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59f28507db158b4e13e40ab9c74175cff7b45064c1ff442798683230db84c296
|
|
| MD5 |
522862cf80e3dcb4c82e91b35c383f2e
|
|
| BLAKE2b-256 |
d1bc1310e9a85b9500c7aca6cf604fcad9210affd1fb3efd2cb282463a53c459
|
Provenance
The following attestation bundles were made for construct_labs_crm_env-0.1.7.tar.gz:
Publisher:
publish-crm-env.yml on constructlabs/mono
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
construct_labs_crm_env-0.1.7.tar.gz -
Subject digest:
59f28507db158b4e13e40ab9c74175cff7b45064c1ff442798683230db84c296 - Sigstore transparency entry: 894908114
- Sigstore integration time:
-
Permalink:
constructlabs/mono@9e1029de985956d4b5e1ff48dd99829e4c4f67c2 -
Branch / Tag:
refs/tags/crm-env-v0.1.7 - Owner: https://github.com/constructlabs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-crm-env.yml@9e1029de985956d4b5e1ff48dd99829e4c4f67c2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file construct_labs_crm_env-0.1.7-py3-none-any.whl.
File metadata
- Download URL: construct_labs_crm_env-0.1.7-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
475b6fc8eb0984c2e1fde21e66791c66f358584a6b26e5853403814c4678d8ad
|
|
| MD5 |
b57b1b93af26cf9c84c9b3d5a7bca488
|
|
| BLAKE2b-256 |
ad7e3d79bce3319d21a1d610725ed4209dc3e3868addd53ac0db54d7ebbd6f11
|
Provenance
The following attestation bundles were made for construct_labs_crm_env-0.1.7-py3-none-any.whl:
Publisher:
publish-crm-env.yml on constructlabs/mono
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
construct_labs_crm_env-0.1.7-py3-none-any.whl -
Subject digest:
475b6fc8eb0984c2e1fde21e66791c66f358584a6b26e5853403814c4678d8ad - Sigstore transparency entry: 894908120
- Sigstore integration time:
-
Permalink:
constructlabs/mono@9e1029de985956d4b5e1ff48dd99829e4c4f67c2 -
Branch / Tag:
refs/tags/crm-env-v0.1.7 - Owner: https://github.com/constructlabs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-crm-env.yml@9e1029de985956d4b5e1ff48dd99829e4c4f67c2 -
Trigger Event:
push
-
Statement type: