141 lines
4.5 KiB
TypeScript
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',
|
|
})
|
|
}
|