97 lines
3.2 KiB
TypeScript
97 lines
3.2 KiB
TypeScript
/**
|
|
* Example 06: Tool Confirmation Pattern
|
|
*
|
|
* This example demonstrates how to implement user confirmation for destructive operations.
|
|
* It shows how to:
|
|
* - Use ThinkSignal to pause execution and request user confirmation
|
|
* - Implement stateful confirmation workflows
|
|
* - Handle confirmation state management across execution cycles
|
|
* - Use onExit callbacks to manage execution flow
|
|
* - Protect against accidental destructive operations
|
|
*
|
|
* Key concepts:
|
|
* - ThinkSignal for interrupting execution flow
|
|
* - Stateful confirmation management
|
|
* - Exit callback handling with onExit
|
|
* - Safety patterns for destructive operations
|
|
* - User consent workflows
|
|
*/
|
|
|
|
import { Client } from '@botpress/client'
|
|
import { z } from '@bpinternal/zui'
|
|
import chalk from 'chalk'
|
|
import { execute, ListenExit, ThinkSignal, Tool } from 'llmz'
|
|
|
|
import { CLIChat } from '../utils/cli-chat'
|
|
import { printTrace } from '../utils/debug'
|
|
|
|
// Initialize Botpress client
|
|
const client = new Client({
|
|
botId: process.env.BOTPRESS_BOT_ID!,
|
|
token: process.env.BOTPRESS_TOKEN!,
|
|
})
|
|
|
|
// State management for confirmation workflow
|
|
// These flags coordinate the confirmation process across execution cycles
|
|
let should_confirm = false // Set when tool needs confirmation
|
|
let confirming = false // Set when user is being asked to confirm
|
|
|
|
// Tool that requires user confirmation before executing
|
|
// Demonstrates the confirmation pattern for destructive operations
|
|
const overwriteData = new Tool({
|
|
name: 'overwrite',
|
|
output: z.object({
|
|
success: z.boolean().describe('Whether the operation was successful'),
|
|
}),
|
|
async handler() {
|
|
// First call: Request confirmation if not already confirming
|
|
if (!confirming) {
|
|
should_confirm = true
|
|
|
|
// ThinkSignal interrupts execution and sends a message to the agent
|
|
// This causes the agent to pause and ask the user for confirmation
|
|
throw new ThinkSignal('Please ask the user for confirmation before proceeding.')
|
|
} else {
|
|
// Second call: User has confirmed, proceed with operation
|
|
should_confirm = false
|
|
confirming = false
|
|
}
|
|
|
|
// Execute the actual destructive operation
|
|
console.log(chalk.bold('✅ Overwriting data'))
|
|
|
|
return { success: true }
|
|
},
|
|
})
|
|
|
|
const chat = new CLIChat()
|
|
|
|
// Main execution loop with confirmation handling
|
|
while (await chat.iterate()) {
|
|
await execute({
|
|
client,
|
|
chat,
|
|
instructions: `You are an assistant that can overwrite data.
|
|
Greet the user and tell them you can overwrite data (show a button "Overwrite Data").
|
|
Use buttons for quick responses when possible.`,
|
|
tools: [overwriteData],
|
|
onTrace: ({ trace }) => printTrace(trace, ['tool_call']),
|
|
|
|
// onExit callback manages confirmation state transitions
|
|
// This ensures proper coordination between tool calls and user responses
|
|
onExit: (exit) => {
|
|
// Handle state management when execution pauses for user input
|
|
if (ListenExit.match(exit)) {
|
|
if (should_confirm) {
|
|
// Tool has requested confirmation - set up confirmation state
|
|
confirming = true
|
|
should_confirm = false
|
|
} else {
|
|
// Normal execution flow - reset confirmation state
|
|
confirming = false
|
|
}
|
|
}
|
|
},
|
|
})
|
|
}
|