Skip to main content

Full Example: Book Recommendation Agent

Here’s a complete example that demonstrates the various language constructs working together, including multiple until statements:
state = {}
meta_prompt = "You're a book recommendation assistant helping users find their next great read."
res = say("Hello! I'm BookBot, your personal book recommendation assistant.", exact=True)

# Introduce the service and set expectations
say("I can help you find books based on your preferences, including genre, format, and reading level.")

# Collect initial user preferences with multiple until paths
loop:
    initial_response = talk(
        f"{meta_prompt} Ask the user what they're looking for today, offering to recommend books, find new releases, or check book availability.",
        True
    )
until "User wants book recommendations":
    recommendation_request = initial_response.ask(
        question="Is the user asking for book recommendations?",
        example={"wants_recommendations": true}
    )

    if recommendation_request["wants_recommendations"]:
        # Handle recommendation path
        state["intent"] = "recommendations"

        # Collect genre preferences
        loop:
            genre_response = talk(
                "What genre of books do you enjoy reading?",
                True,
                {"genre": "fantasy", "format": "e-book"}
            )
        until "User provides valid genre and format preferences":
            preferences = genre_response.ask(
                question="Extract the user's preferred book genre and format.",
                example={"genre": "fantasy", "format": "e-book"}
            )

            if preferences["genre"] and preferences["format"]:
                state["preferences"] = preferences
                break

        # Generate recommendations
        response = requests.get(
            url='https://bookstore-api.example.com/recommendations',
            params=state["preferences"]
        )
        recommendations = response.json().ask(
            question="Extract the top 3 book recommendations with title, author, and description.",
            example={"books": [{"title": "Book Title", "author": "Author Name", "description": "Brief description"}]}
        )

        # Present recommendations
        say(f"Based on your interest in {state['preferences']['genre']} books, here are 3 titles I think you'll love:", exact=True)
        for i, book in enumerate(recommendations["books"]):
            say(f"{i+1}. '{book['title']}' by {book['author']}: {book['description']}", exact=True)
        break
until "User wants to check new releases":
    new_release_request = initial_response.ask(
        question="Is the user asking about new or upcoming book releases?",
        example={"wants_new_releases": true, "genre": "thriller"}
    )

    if new_release_request["wants_new_releases"]:
        # Handle new releases path
        state["intent"] = "new_releases"
        genre = new_release_request.get("genre", "")

        # Get new releases, optionally filtered by genre
        response = requests.get(
            url='https://bookstore-api.example.com/new-releases',
            params={"genre": genre} if genre else {}
        )
        new_releases = response.json().ask(
            question="Extract the latest 5 book releases with title, author, and release date.",
            example={"books": [{"title": "New Book", "author": "Author Name", "release_date": "2023-10-15"}]}
        )

        # Present new releases
        header = f"Here are the latest releases in {genre}:" if genre else "Here are the latest book releases:"
        say(header, exact=True)
        for i, book in enumerate(new_releases["books"]):
            say(f"{i+1}. '{book['title']}' by {book['author']} - Released: {book['release_date']}", exact=True)
        break
until "User wants to check book availability":
    availability_request = initial_response.ask(
        question="Is the user asking about checking if a specific book is available?",
        example={"checking_availability": true, "book_title": "The Great Novel", "author": "Famous Writer"}
    )

    if availability_request["checking_availability"]:
        # Handle availability check path
        state["intent"] = "check_availability"

        book_info = {}
        if "book_title" in availability_request:
            book_info["title"] = availability_request["book_title"]
        if "author" in availability_request:
            book_info["author"] = availability_request["author"]

        # If we have complete information, check availability
        if "title" in book_info and "author" in book_info:
            availability = check_book_availability(book_info["title"], book_info["author"])
            if availability["available"]:
                say(f"Good news! '{book_info['title']}' by {book_info['author']} is available in these formats: {', '.join(availability['formats'])}", exact=True)
            else:
                say(f"I'm sorry, '{book_info['title']}' by {book_info['author']} is currently unavailable. Would you like me to notify you when it becomes available?", exact=True)
        else:
            # Need more information
            loop:
                book_details_response = talk(
                    "I'd be happy to check book availability. Could you please provide the book title and author?",
                    True
                )
            until "User provides complete book details":
                details = book_details_response.ask(
                    question="Extract the book title and author from the user's response.",
                    example={"title": "The Great Novel", "author": "Famous Writer"}
                )

                if "title" in details and "author" in details:
                    availability = check_book_availability(details["title"], details["author"])
                    if availability["available"]:
                        say(f"Good news! '{details['title']}' by {details['author']} is available in these formats: {', '.join(availability['formats'])}", exact=True)
                    else:
                        say(f"I'm sorry, '{details['title']}' by {details['author']} is currently unavailable. Would you like me to notify you when it becomes available?", exact=True)
                    break
        break

# Conversation wrap-up
say("Is there anything else I can help you with today?", exact=True)

Key Takeaways

This example demonstrates several important Based patterns:
  1. State Management: Using the state dictionary to persist user intent and preferences across conversation turns
  2. Multiple Until Conditions: Handling different user intents (recommendations, new releases, availability) with separate until blocks
  3. Nested Loops: Using inner loop-until patterns for collecting additional information when needed
  4. API Integration: Making HTTP requests to external services and using .ask() to extract structured data from responses
  5. Dynamic Responses: Building personalized responses based on extracted user data

Conclusion

The Based language provides a powerful yet intuitive framework for building conversational agents. By mastering the core constructs—particularly the essential loop-talk-until pattern—you can create sophisticated conversation flows that handle complex interactions while maintaining readability and maintainability. Remember that Based is designed to be declarative, allowing you to focus on the “what” rather than the “how” of conversational AI. This approach dramatically reduces the amount of code needed to create powerful agents while increasing reliability and ease of maintenance. The combination of the core language constructs with platform-specific functions allows you to build agents that take full advantage of each deployment platform’s unique capabilities while maintaining a consistent codebase and user experience.