Roles & Tools

Agent roles define what an AI agent can do — its personality (system prompt), which tools it can call, how creative it should be (temperature), and optionally which LLM provider to use.

Default Roles

Three roles ship out of the box:

Support

For customer-facing inquiries — order status, tracking, returns, general questions.

{
  "name": "Customer Support",
  "system_prompt": "You are a customer support agent for {{tenant_name}}...",
  "allowed_tools": ["orders.get", "orders.getStats", "customers.*"],
  "temperature": 0.3,
  "max_tokens": 1024
}

Low temperature (0.3) for consistent, factual responses.

Operations

For internal operations — order management, fulfillment, shipping.

{
  "name": "Operations Assistant",
  "allowed_tools": ["orders.*"],
  "temperature": 0.1,
  "max_tokens": 2048
}

Very low temperature (0.1) for precise, action-oriented responses.

Analytics

For business questions — revenue trends, order volumes, product performance.

{
  "name": "Analytics Assistant",
  "allowed_tools": ["orders.getStats"],
  "temperature": 0.2,
  "max_tokens": 2048
}

API Endpoints

List Roles

GET /api/v1/ai/agent/roles
{
  "data": [
    {"id": "support", "name": "Customer Support", "allowed_tools": ["orders.get", "customers.*"], ...},
    {"id": "operations", "name": "Operations Assistant", ...},
    {"id": "analytics", "name": "Analytics Assistant", ...}
  ],
  "default_role": "support"
}

Create or Update a Role

PUT /api/v1/ai/agent/roles/custom-role

{
  "name": "Shipping Specialist",
  "description": "Handles shipping, tracking, and delivery questions",
  "system_prompt": "You are a shipping specialist for {{tenant_name}}. You help with tracking, delivery estimates, and shipping issues. Always include tracking URLs when available.",
  "allowed_tools": ["orders.get", "orders.getStats"],
  "temperature": 0.2,
  "max_tokens": 1024,
  "provider_id": null
}

Set Default Role

PUT /api/v1/ai/agent/roles/default
{
  "role_id": "support"
}

Delete a Custom Role

DELETE /api/v1/ai/agent/roles/custom-role

Default roles (support, operations, analytics) cannot be deleted — only customized.

API Permission Scoping

All agent endpoints require the ai.view or ai.configure tenant permission:

Endpoint Permission Required
POST /ai/agent/chat ai.view
POST /ai/agent/chat/stream ai.view
GET /ai/agent/roles ai.view
GET /ai/agent/tools ai.view
PUT /ai/agent/roles/{id} ai.configure
DELETE /ai/agent/roles/{id} ai.configure
POST /ai/agent/graph/run ai.configure

Users without ai.view cannot access the AI widget, voice assistant, or any agent endpoints. The widget and voice assistant are conditionally rendered based on these permissions.

Tool Permissions

How Tools Are Discovered

Tools come from module bus endpoints declared in each module's module.json:

// modules/Orders/module.json → api.provides
{
  "orders.get": { "description": "Get a single order by ID" },
  "orders.create": { "description": "Create a new order via ingest pipeline" },
  "orders.updateStatus": { "description": "Update order status" }
}

When building the TenantContext, Laravel reads all bus endpoints from installed modules via ModuleApiRegistry::getAllProvided() and filters them by the role's allowed_tools patterns.

Modules with Tools

Module Tools Examples
Orders 10 orders.get, orders.create, orders.updateStatus, orders.getStats
ResellerAdmin 8 admin.approveReseller, admin.getNetworkTree, admin.generateReferralCode
ChannelLiveChatWidget 6 chat.acceptChat, chat.getConversationHistory, chat.transferToHuman
Communications 5 comms.send, comms.sendBulk, comms.getDeliveryStatus
ResellerCatalog 4 catalog.calculatePrice, catalog.setPricing, catalog.getAvailableCatalog
ResellerOrders 4 orders.createChainOrder, orders.forwardOrder, orders.markShipped
ResellerNetwork 3 network.getDashboard, network.getDownlineTree
ResellerFinance 2 finance.processDeliveredOrder, finance.getSettlementSummary

To add tools to other modules, see Adding Tools to Modules.

List Available Tools

GET /api/v1/ai/agent/tools
{
  "data": [
    {"name": "orders.get", "module": "Orders", "description": "Get a single order by ID"},
    {"name": "orders.create", "module": "Orders", "description": "Create a new order via ingest pipeline"},
    {"name": "orders.updateStatus", "module": "Orders", "description": "Update order status"},
    {"name": "orders.getStats", "module": "Orders", "description": "Get order statistics"}
  ]
}

Wildcard Patterns

Tool permissions support wildcards:

Pattern Matches
orders.get Only orders.get
orders.* orders.get, orders.create, orders.updateStatus, etc.
* All tools from all modules

Pattern matching uses prefix comparison — orders.* matches any tool starting with orders..

Two-Level Permission Enforcement

Tools are filtered at two independent levels before the AI agent can use them:

Level 1 — Role filtering (Laravel):

The role's allowed_tools patterns filter which tools are sent to the Python agent. AgentGatewayService::buildToolList() iterates all registered tools and matches against the patterns. Tools not matching any pattern are excluded from the TenantContext.

Level 2 — User RBAC (Python agent):

The Python agent infers what tenant permission each tool requires from its name:

Tool Name Pattern Inferred Permission
*.get*, *.search*, *.Stats* {module}.view
*.create* {module}.create
*.update*, *.process*, *.reserve* {module}.manage
*.delete*, *.cancel* {module}.delete
Other {module}.view (default)

Examples:

  • orders.get → requires orders.view
  • orders.create → requires orders.create
  • orders.updateStatus → requires orders.manage
  • orders.processRefund → requires orders.manage
  • catalog.getAvailableCatalog → requires catalog.view

The agent checks each inferred permission against the user's actual tenant permissions (from Spatie). If the user lacks the permission, the tool is silently skipped.

Result: An agent can never do more than the intersection of what the role allows AND what the user's RBAC permits. A support agent with only orders.view can never trigger orders.create even if the role's allowed_tools includes orders.*.

System Prompt Variables

System prompts support the {{tenant_name}} variable, replaced at runtime:

"You are a support agent for {{tenant_name}}."
→ "You are a support agent for Acme Corp."

Provider Overrides

Each role can optionally use a different LLM provider:

{
  "name": "Budget Support",
  "provider_id": "groq",
  "temperature": 0.3,
  "allowed_tools": ["orders.get"]
}

If provider_id is null, the tenant's default provider is used.