Files
2026-07-13 13:34:48 +08:00

141 lines
4.5 KiB
TypeScript

/**
* Example 04: Small Models with Tools
*
* This example demonstrates how LLMz works effectively with smaller, faster models.
* It shows how to:
* - Use smaller models for cost-effective operations
* - Implement a complete support ticket management system
* - Design tools with clear schemas and descriptions
* - Handle CRUD operations through tools
* - Enable trace logging for debugging tool calls
*
* Key concepts:
* - Model selection with options.model
* - Tool-based state management
* - Structured data manipulation with Zod schemas
* - Error handling in tool implementations
* - Lightweight trace logging
*/
import { Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import { execute, Tool } from 'llmz'
import { CLIChat } from '../utils/cli-chat'
import { lightToolTrace } from '../utils/debug'
// Initialize Botpress client
const client = new Client({
botId: process.env.BOTPRESS_BOT_ID!,
token: process.env.BOTPRESS_TOKEN!,
})
// Sample ticket data for demonstration
// In a real application, this would be stored in a database
let TICKETS = [
{ id: '123', status: 'Open', description: 'Salesforce keeps loading forever' },
{ id: '456', status: 'Closed', description: 'Unable to connect to the database' },
{ id: '789', status: 'Open', description: 'Error in the payment gateway integration' },
]
// Tool for retrieving individual ticket details
// Demonstrates read operations with error handling
const getTicket = new Tool({
name: 'getTicket',
description: 'Get a support ticket',
input: z.object({
ticketId: z.string().describe('The ID of the support ticket'),
}),
output: z.string().describe('Details of the support ticket'),
async handler({ ticketId }) {
// Search for the ticket in our data store
const ticket = TICKETS.find((t) => t.id === ticketId)
// Handle not found case with descriptive error
if (!ticket) {
throw new Error(`Ticket with ID ${ticketId} not found.`)
}
// Return formatted ticket information
return `Ticket ID: ${ticket.id}, Status: ${ticket.status}, Description: ${ticket.description}`
},
})
// Tool for closing/updating ticket status
// Demonstrates update operations with validation
const closeTicket = new Tool({
name: 'closeTicket',
description: 'Close a support ticket',
input: z.object({
ticketId: z.string().describe('The ID of the support ticket to close'),
}),
output: z.object({
message: z.string().describe('Confirmation message'),
}),
async handler({ ticketId }) {
// Validate ticket exists before attempting to update
if (!TICKETS.some((t) => t.id === ticketId)) {
throw new Error(`Ticket with ID ${ticketId} not found.`)
}
// Update the ticket status using immutable pattern
TICKETS = TICKETS.map((ticket) => (ticket.id === ticketId ? { ...ticket, status: 'Closed' } : ticket))
// Return structured confirmation response
return {
message: `Ticket ID: ${ticketId} has been closed successfully.`,
}
},
})
// Tool for listing all available tickets
// Demonstrates list operations with data transformation
const listTickets = new Tool({
name: 'listTickets',
description: 'List all support tickets',
input: z.object({}), // No input parameters required
output: z.object({
tickets: z
.array(
z.object({
id: z.string().describe('Ticket ID'),
description: z.string().describe('Ticket description'),
})
)
.describe('List of support tickets'),
}),
async handler() {
// Transform internal data structure for external consumption
// Only expose necessary fields for security/simplicity
return {
tickets: TICKETS.map((ticket) => ({
id: ticket.id,
description: ticket.description,
})),
}
},
})
const chat = new CLIChat()
// Main execution loop with smaller model configuration
while (await chat.iterate()) {
await execute({
instructions:
'You are a helpful assistant. You can manage support tickets by listing, retrieving, or closing them.',
// Provide all ticket management tools to the agent
tools: [getTicket, closeTicket, listTickets],
client,
chat,
// Enable lightweight trace logging to see tool calls
onTrace: ({ trace }) => lightToolTrace(trace),
// Use a smaller, faster model for cost-effective operations
// Smaller models work well with LLMz because TypeScript generation
// is easier than complex JSON tool calling
model: 'openai:gpt-4.1-mini-2025-04-14',
})
}