๐Ÿ”ท Core trusted

bx-ai-tools

Use this skill when creating AI tools (function calling) with aiTool(): parameter descriptions, tool registries, using tools with aiChat() and agents, the aiToolRegistry() BIF, global skills with aiglobalSkills(), and best practices for tool design.

$ npx skills add ortus-boxlang/skills/boxlang-modules/bx-ai/bx-ai-tools
$ coldbox ai skills install ortus-boxlang/skills/boxlang-modules/bx-ai/bx-ai-tools
๐Ÿ”— https://skills.boxlang.io/skills/raw/ortus-boxlang/skills/boxlang-modules~bx-ai~bx-ai-tools

bx-ai: AI Tools (Function Calling)

aiTool() BIF

// Signature
aiTool( name, description, handler, params={} )
  • name โ€” unique tool identifier (snake_case recommended)
  • description โ€” what the tool does (clear, imperative language)
  • handler โ€” lambda/closure called when AI invokes the tool
  • params โ€” additional parameter schema hints

Creating Tools

// Simple tool โ€” single parameter
weatherTool = aiTool(
    "get_weather",
    "Get the current weather for a given location",
    location -> getWeatherData( location )
)

// Multi-parameter tool โ€” use parameter descriptions
searchTool = aiTool(
    "search_database",
    "Search the products database by keyword and category",
    ( keyword, category ) -> {
        return queryExecute(
            "SELECT * FROM products WHERE name LIKE :kw AND category = :cat",
            { kw: "%#keyword#%", cat: category }
        )
    }
)

Describing Parameters

Use fluent describe*() methods to tell the AI what each parameter means:

// The method name is  describe + TitleCase(parameterName)
weatherTool = aiTool(
    "get_weather",
    "Get current weather for a location",
    location -> getWeatherAPI( location )
).describeLocation( "City and country, e.g. 'Boston, MA' or 'Paris, France'" )

searchTool = aiTool(
    "search_products",
    "Search the product catalog",
    ( keyword, category, maxResults ) -> {
        return productService.search( keyword, category, maxResults )
    }
)
.describeKeyword(    "Search keyword or product name" )
.describeCategory(   "Product category: electronics, clothing, food, or all" )
.describeMaxResults( "Maximum number of results (1-50)" )

Using Tools with aiChat()

tools = [
    aiTool( "get_time",   "Get current server time",           () -> now() ),
    aiTool( "get_uptime", "Get server uptime in hours",        () -> getServerUptime() ),
    aiTool( "calc",       "Evaluate a math expression",       expr -> evaluate( expr ) )
        .describeExpr( "Math expression as a string, e.g. '(15 * 3) + 7'" )
]

result = aiChat(
    "What time is it and what is 15% of 320?",
    {},
    { tools: tools }
)

Using Tools on an Agent

// Prefer passing tools to aiAgent() for reusable agents
agent = aiAgent(
    name        : "SystemAgent",
    instructions: "Use the provided tools to answer system questions accurately",
    tools       : [
        aiTool( "get_users",   "List all users",    () -> entityLoad( "User" ) ),
        aiTool( "get_stats",   "Get system stats",  () -> getSystemStats() ),
        aiTool( "send_email",  "Send an email",
            ( to, subject, body ) -> mailService.send( to, subject, body ) )
            .describeTo(      "Recipient email address" )
            .describeSubject( "Email subject line" )
            .describeBody(    "Email body in plain text or HTML" )
    ]
)

aiToolRegistry() โ€” Shared Tool Collections

// Build a reusable tool registry
registry = aiToolRegistry()
    .register( aiTool( "weather",  "Get weather", loc -> getWeather( loc ) ) )
    .register( aiTool( "stocks",   "Get stock price", sym -> getStock( sym ) ) )
    .register( aiTool( "currency", "Convert currency",
        ( amount, from, to ) -> convertCurrency( amount, from, to ) ) )

// Share across multiple agents
agentA = aiAgent( name: "A", tools: registry.getTools() )
agentB = aiAgent( name: "B", tools: registry.getTools() )

aiGlobalSkills() โ€” Application-Wide Skills

// Register skills available to ALL agents in the application
aiGlobalSkills([
    aiSkill( ".ai/skills/company-guidelines/SKILL.md" ),
    aiSkill( ".ai/skills/brand-tone/SKILL.md" )
])

Tool Design Best Practices

  • Name tools clearly โ€” use snake_case verbs: get_weather, search_products, send_email
  • Write actionable descriptions โ€” describe what the tool DOES, not what it IS
    • โœ… "Get the current weather for a city and country"
    • โŒ "Weather tool"
  • Describe every parameter โ€” vague parameters lead to incorrect AI usage
  • Return structured data โ€” structs and arrays are easier for AI to reason about than raw strings
  • Keep tools focused โ€” one tool, one responsibility
  • Handle errors gracefully โ€” return an error struct rather than throwing exceptions
// Good error handling in a tool
dbTool = aiTool(
    "query_user",
    "Look up a user by ID",
    userId -> {
        try {
            var user = entityLoadByPK( "User", userId )
            return isNull( user ) ? { found: false } : { found: true, data: user.getMemento() }
        } catch ( any e ) {
            return { error: true, message: e.message }
        }
    }
).describeUserId( "Numeric user ID" )

Common Pitfalls

  • โŒ Do NOT access arguments scope inside tool closures โ€” use bare parameter names
    • โŒ location -> getWeather( arguments.location )
    • โœ… location -> getWeather( location )
  • โŒ Avoid throwing exceptions inside tools โ€” return error structs instead
  • โœ… Always describe parameters for tools that take arguments
  • โœ… Test tools independently before connecting them to agents