Agent Management
Agents represent entities in the Doover platform such as users, devices, or services. The Cloud API provides methods to retrieve and manage agents.
Agent Class
The Agent class represents an agent in the Doover system.
Attributes
| Attribute | Type | Description |
|---|---|---|
| key | str | The unique identifier (UUID) for the agent |
| id | str | Alias for key |
| type | str | The type of agent (e.g., "doover_users | user") |
| name | str | The display name of the agent |
| owner_org | str | The organization that owns the agent |
| deployment_config | dict | Deployment configuration settings |
| channels | list[Channel] | List of channels associated with the agent |
Properties
| Property | Type | Description |
|---|---|---|
| agent_id | str | Returns the unique identifier for the agent |
Methods
| Method | Returns | Description |
|---|---|---|
| update() | None | Fetches and updates the agent data from the server |
Retrieving Agents
Get All Agents
Use get_agent_list() to retrieve all agents you have access to:
from pydoover.cloud.api import Client
client = Client()
agents = client.get_agent_list()
for agent in agents:
print(f"Agent: {agent.name}")
print(f" Key: {agent.key}")
print(f" Type: {agent.type}")
print(f" Organization: {agent.owner_org}")
print(f" Channels: {len(agent.channels)}")
print()
Get a Specific Agent
Use get_agent() to retrieve a specific agent by its UUID:
from pydoover.cloud.api import Client, NotFound
client = Client()
try:
agent = client.get_agent("9fb5d629-ce7f-4b08-b17a-c267cbcd0427")
print(f"Found agent: {agent.name}")
except NotFound:
print("Agent not found or access denied")
Working with Agent Channels
Each agent has associated channels that can be accessed directly:
agent = client.get_agent("agent-uuid")
# List all channels for this agent
for channel in agent.channels:
print(f"Channel: {channel.name} ({channel.key})")
Channel Types
Channels are automatically typed based on their name prefix:
| Prefix | Type | Description |
|---|---|---|
| (none) | Channel | Regular data channel |
# | Processor | Processor channel for code execution |
! | Task | Task channel that triggers processors |
# Get channels by type
regular_channels = [c for c in agent.channels if not c.name.startswith(('#', '!'))]
processors = [c for c in agent.channels if c.name.startswith('#')]
tasks = [c for c in agent.channels if c.name.startswith('!')]
Updating Agent Data
The update() method refreshes the agent's data from the server:
agent = client.get_agent("agent-uuid")
print(f"Initial channel count: {len(agent.channels)}")
# Some time later, refresh the data
agent.update()
print(f"Updated channel count: {len(agent.channels)}")
Deployment Configuration
Agents may have deployment configuration that defines how applications are deployed:
agent = client.get_agent("agent-uuid")
if agent.deployment_config:
print("Deployment configuration:")
for key, value in agent.deployment_config.items():
print(f" {key}: {value}")
else:
print("No deployment configuration set")
Agent Data Structure
When fetched from the API, agent data includes:
{
"agent": "9fb5d629-ce7f-4b08-b17a-c267cbcd0427",
"type": "doover_users | user",
"name": "My Device",
"owner_org": "org-uuid",
"settings": {
"deployment_config": {
"key": "value"
}
},
"channels": [
{
"channel": "d1c7e8e3-f47b-4c68-86d7-65054d9e97d3",
"name": "status",
"type": "base",
"agent": "9fb5d629-ce7f-4b08-b17a-c267cbcd0427"
}
]
}
Complete Example
from pydoover.cloud.api import Client, NotFound
def list_agent_details(client: Client):
"""List all agents with their channels."""
agents = client.get_agent_list()
if not agents:
print("No agents found")
return
for agent in agents:
print(f"\n{'='*50}")
print(f"Agent: {agent.name or 'Unnamed'}")
print(f" ID: {agent.key}")
print(f" Type: {agent.type}")
print(f" Organization: {agent.owner_org}")
if agent.deployment_config:
print(" Deployment Config:")
for k, v in agent.deployment_config.items():
print(f" {k}: {v}")
print(f" Channels ({len(agent.channels)}):")
for channel in agent.channels:
prefix = ""
if channel.name.startswith('#'):
prefix = "[Processor] "
elif channel.name.startswith('!'):
prefix = "[Task] "
print(f" - {prefix}{channel.name}")
def find_agent_by_name(client: Client, name: str):
"""Find an agent by name."""
agents = client.get_agent_list()
for agent in agents:
if agent.name and name.lower() in agent.name.lower():
return agent
return None
def get_agent_channel(client: Client, agent_id: str, channel_name: str):
"""Get a specific channel from an agent."""
agent = client.get_agent(agent_id)
for channel in agent.channels:
if channel.name == channel_name:
return channel
return None
# Usage
client = Client()
# List all agents
list_agent_details(client)
# Find agent by name
agent = find_agent_by_name(client, "My Device")
if agent:
print(f"Found: {agent.key}")
# Get a specific channel from an agent
channel = get_agent_channel(client, "agent-uuid", "status")
if channel:
print(f"Channel aggregate: {channel.aggregate}")
Error Handling
from pydoover.cloud.api import Client, NotFound, Forbidden, HTTPException
client = Client()
try:
agent = client.get_agent("invalid-uuid")
except NotFound:
print("Agent not found - check the UUID or your permissions")
except Forbidden:
print("Access denied - you don't have permission to view this agent")
except HTTPException as e:
print(f"HTTP error: {e}")
Best Practices
Cache agent data: If you need to access agent data frequently, store the
Agentobject and callupdate()only when needed.Handle missing data: Not all agents have names or deployment configurations. Always check for
Nonevalues.Use channel lists efficiently: The
agent.channelslist is populated when the agent is fetched. For detailed channel data, useclient.get_channel().
# Efficient: Use pre-loaded channel list
for channel in agent.channels:
if channel.name == "status":
# Get full channel details only when needed
full_channel = client.get_channel(channel.key)
print(full_channel.aggregate)
break
# Less efficient: Fetching each channel separately
for channel_name in ["status", "config", "logs"]:
try:
channel = client.get_channel_named(channel_name, agent.key)
print(f"{channel_name}: {channel.aggregate}")
except NotFound:
pass