Created
September 12, 2024 22:07
-
-
Save kleneway/923a04ebcceba35f897f813e3b1009b3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This is a version of a tool-calling behavior that implements a "phased scenario" style prompt | |
* for restaurant selection and reservation. The conversational agent guides the user through | |
* selecting a restaurant and making a reservation based on their preferences in phases. | |
*/ | |
import { defineTool } from "@pioneersquarelabs/language-barrier"; | |
import { defineBehaviorModule } from "@pioneersquarelabs/vdot"; | |
import { z } from "zod"; | |
/** | |
* This object keeps track of the preferences we learn about the user for restaurant selection. | |
*/ | |
export type RestaurantPreferences = { | |
cuisine?: string; | |
location?: string; | |
priceRange?: string; | |
partySize?: number; | |
dateTime?: string; | |
}; | |
/** | |
* This prompt sets the overall tone for the agent interaction. | |
*/ | |
function basePrompt(): string { | |
return "You are a helpful assistant designed to help users select a restaurant and make a reservation. Your goal is to understand the user's preferences and assist them through the process. Pay close attention to the instructions section."; | |
} | |
/** | |
* This prompt refines the objective of the agent depending on what we know so far. | |
*/ | |
function phaseSpecificInstructions(prefs: Readonly<RestaurantPreferences>): string { | |
if (!prefs.cuisine && !prefs.location && !prefs.priceRange && !prefs.partySize && !prefs.dateTime) { | |
return "# Instructions\nYour current goal is to learn the user's preferred cuisine, location, price range, party size, and desired date/time for the reservation. Determine these preferences through natural conversation without being too direct."; | |
} | |
if (!prefs.cuisine) { | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nFocus on learning the user's preferred cuisine. Ask questions that help uncover this preference naturally.`; | |
} | |
if (!prefs.location) { | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nFocus on learning the user's preferred location for dining. Ask questions that help uncover this preference naturally.`; | |
} | |
if (!prefs.priceRange) { | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nFocus on understanding the user's preferred price range for dining out. Ask questions that help uncover this preference naturally.`; | |
} | |
if (!prefs.partySize) { | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nFocus on determining the number of people in the user's party. Ask questions that help uncover this information naturally.`; | |
} | |
if (!prefs.dateTime) { | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nFocus on determining the user's preferred date and time for the reservation. Ask questions that help uncover this preference naturally.`; | |
} | |
return `# Current knowledge\n${formatKnowledge(prefs)}\n# Instructions\nYou have gathered all necessary preferences. Provide restaurant recommendations based on the user's preferences and offer to make a reservation.`; | |
} | |
function formatKnowledge(prefs: Readonly<RestaurantPreferences>): string { | |
return Object.entries(prefs) | |
.filter(([_, value]) => value !== undefined) | |
.map(([key, value]) => `${key}: ${value}`) | |
.join('\n'); | |
} | |
/** | |
* This tool allows the agent to assert user preferences for restaurant selection. | |
*/ | |
export const assertRestaurantPreferences = defineTool({ | |
name: "assertRestaurantPreferences", | |
description: "Assert preferences that you have learned about the user for restaurant selection", | |
parameters: { | |
cuisine: z.string().describe("Preferred cuisine of the user").optional(), | |
location: z.string().describe("Preferred dining location of the user").optional(), | |
priceRange: z.string().describe("The preferred price range for dining").optional(), | |
partySize: z.number().describe("Number of people in the dining party").optional(), | |
dateTime: z.string().describe("Preferred date and time for the reservation").optional(), | |
}, | |
}); | |
/** | |
* This tool allows the agent to make a restaurant reservation. | |
*/ | |
export const makeReservation = defineTool({ | |
name: "makeReservation", | |
description: "Make a reservation at the selected restaurant", | |
parameters: { | |
restaurantName: z.string().describe("Name of the selected restaurant"), | |
dateTime: z.string().describe("Date and time of the reservation"), | |
partySize: z.number().describe("Number of people in the party"), | |
specialRequests: z.string().describe("Any special requests for the reservation").optional(), | |
}, | |
}); | |
/** | |
* This behavior module manages the conversational flow for restaurant selection and reservation. | |
*/ | |
export const restaurantReservationBehavior = defineBehaviorModule({ | |
toolbox: [assertRestaurantPreferences, makeReservation], | |
initialize: () => { | |
const initialPreferences: RestaurantPreferences = {}; | |
return { | |
systemPrompt: [ | |
basePrompt(), | |
phaseSpecificInstructions(initialPreferences), | |
].join("\n"), | |
toolChoice: "auto", | |
userData: initialPreferences, | |
options: { | |
model: "claude-3-5-sonnet-20240620", | |
tokenConstraints: { maxOutput: 1024 }, | |
temperature: 0.3, | |
}, | |
}; | |
}, | |
onToolResult: async (state, toolCall) => { | |
if (toolCall.name === assertRestaurantPreferences.name) { | |
let updated = false; | |
for (const [key, value] of Object.entries(toolCall.args)) { | |
if (value !== undefined) { | |
(state.userData as any)[key] = value; | |
updated = true; | |
} | |
} | |
if (updated) { | |
state.systemPrompt = [ | |
basePrompt(), | |
phaseSpecificInstructions(state.userData), | |
].join("\n"); | |
} | |
} else if (toolCall.name === makeReservation.name) { | |
// Here you would typically integrate with an actual reservation system | |
// For this example, we'll just update the system prompt to confirm the reservation | |
state.systemPrompt = `${basePrompt()}\n# Instructions\nA reservation has been made at ${toolCall.args.restaurantName} for ${toolCall.args.partySize} people on ${toolCall.args.dateTime}. Confirm the reservation details with the user and ask if they need anything else.`; | |
} | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's the previous version: