> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools

Each tool in this setup belongs either to a specific skill or directly to the agent. Skill-scoped tools are only available when that skill is active. Agent-level tools are available across all skills.

| Tool                   | Owner                   | Permission  |
| ---------------------- | ----------------------- | ----------- |
| `search_catalog`       | `product-lookup` skill  | `READ_ONLY` |
| `create_order`         | `order-placement` skill | `ADMIN`     |
| `update_order_status`  | `order-placement` skill | `ADMIN`     |
| `check_inventory`      | `inventory-check` skill | `READ_ONLY` |
| `get_customer_profile` | agent-level (no skill)  | `READ_ONLY` |

`get_customer_profile` is declared directly on the agent, not inside any skill. It is available across all skills without restriction.

To see these tools in action, see the [Sample query walkthrough](/agent_skills/multi/sample_query).

## Full implementation

```python PYTHON theme={null}
from ibm_watsonx_orchestrate.agent_builder.tools import tool, ToolPermission

_ORDER_SEQ = 2000
_PRODUCTS = {
    "SKU-001": {"name": "Widget Pro",    "price":  29.99, "stock": 250, "category": "electronics"},
    "SKU-002": {"name": "Gadget Max",    "price": 149.00, "stock":   5, "category": "electronics"},
    "SKU-003": {"name": "Comfort Chair", "price": 399.00, "stock":   0, "category": "home"},
    "SKU-004": {"name": "Running Shoes", "price":  89.50, "stock": 120, "category": "sports"},
}
_ORDERS: dict = {}
_CUSTOMERS = {
    "CUST-001": {"name": "Alice Johnson", "tier": "gold",     "credit_limit": 50000},
    "CUST-002": {"name": "Bob Smith",     "tier": "standard", "credit_limit":  5000},
}


@tool(name="search_catalog",
      description="Search the product catalog by keyword or category",
      permission=ToolPermission.READ_ONLY)
def search_catalog(query: str, category: str = None) -> dict:
    """
    Search the product catalog by keyword or category.
    :param query: search term (product name, SKU, or keyword)
    :param category: optional category filter (electronics, clothing, home, sports)
    """
    results = []
    q = query.lower()
    for sku, p in _PRODUCTS.items():
        if category and p["category"] != category:
            continue
        if q in p["name"].lower() or q in sku.lower() or q in p["category"]:
            results.append({
                "sku": sku,
                "name": p["name"],
                "price": p["price"],
                "category": p["category"],
                "in_stock": p["stock"] > 0,
                "stock_count": p["stock"],
            })
    return {"query": query, "count": len(results), "results": results}


@tool(name="create_order",
      description="Create a new customer order and return its record",
      permission=ToolPermission.ADMIN)
def create_order(product_id: str, quantity: int, unit_price: float) -> dict:
    """
    Create a new customer order and return its record.
    :param product_id: product identifier (e.g. SKU-001)
    :param quantity: number of units to order
    :param unit_price: price per unit in USD
    """
    global _ORDER_SEQ
    _ORDER_SEQ += 1
    order_id = f"ORD-{_ORDER_SEQ}"
    _ORDERS[order_id] = {
        "order_id":   order_id,
        "product_id": product_id,
        "quantity":   quantity,
        "unit_price": unit_price,
        "total":      round(quantity * unit_price, 2),
        "status":     "pending",
    }
    return _ORDERS[order_id]


@tool(name="update_order_status",
      description="Update the status of an existing order",
      permission=ToolPermission.ADMIN)
def update_order_status(order_id: str, status: str) -> dict:
    """
    Update the status of an existing order.
    :param order_id: the order identifier (e.g. ORD-2001)
    :param status: new status — one of: pending, confirmed, shipped, delivered, cancelled
    """
    allowed = {"pending", "confirmed", "shipped", "delivered", "cancelled"}
    if status not in allowed:
        return {"success": False, "error": f"Invalid status '{status}'. Allowed: {sorted(allowed)}"}
    if order_id not in _ORDERS:
        return {"success": False, "error": f"Order '{order_id}' not found"}
    _ORDERS[order_id]["status"] = status
    return {"success": True, "order_id": order_id, "status": status}


@tool(name="check_inventory",
      description="Return current inventory data for a product",
      permission=ToolPermission.READ_ONLY)
def check_inventory(product_id: str) -> dict:
    """
    Return current inventory data for a product.
    :param product_id: product identifier (e.g. SKU-001)
    """
    p = _PRODUCTS.get(product_id)
    if not p:
        return {"found": False, "product_id": product_id, "error": "Product not found"}
    return {
        "found":         True,
        "product_id":    product_id,
        "name":          p["name"],
        "current_stock": p["stock"],
        "daily_demand":  8.5,
    }


@tool(name="get_customer_profile",
      description="Retrieve a customer's profile including account tier and credit limit",
      permission=ToolPermission.READ_ONLY)
def get_customer_profile(customer_id: str) -> dict:
    """
    Retrieve a customer's profile including account tier and credit limit.
    This is an agent-level tool — it belongs to the agent, not to any skill.
    :param customer_id: customer identifier (e.g. CUST-001)
    """
    c = _CUSTOMERS.get(customer_id)
    if not c:
        return {"found": False, "customer_id": customer_id, "error": "Customer not found"}
    return {"found": True, "customer_id": customer_id, **c}
```

## Next steps

* See [Operations assistant](/agent_skills/multi/agent) to understand how these tools are assigned to the agent and its skills.
* See [Order placement skill](/agent_skills/multi/order_placement) for how `create_order` and `update_order_status` are used.
* See [Inventory check skill](/agent_skills/multi/inventory_check) for how `check_inventory` is used.
