pocketflow/cookbook/pocketflow-cli-hitl/docs/design.md

4.9 KiB

Design Doc: Command-Line Joke Generator

Please DON'T remove notes for AI

Requirements

Notes for AI: Keep it simple and clear. If the requirements are abstract, write concrete user stories

The system will be a command-line application that:

  1. Asks the user for a topic for a joke.
  2. Generates a joke based on the provided topic.
  3. Asks the user if they approve of the joke.
  4. If the user approves, the application can end or offer to generate another joke (for simplicity, we'll end for now).
  5. If the user does not approve, the application should: a. Take note that the user disliked the previous joke. b. Generate a new joke about the same topic, attempting to make it different from the disliked one. c. Repeat step 3.

Flow Design

Notes for AI:

  1. Consider the design patterns of agent, map-reduce, rag, and workflow. Apply them if they fit.
  2. Present a concise, high-level description of the workflow.

Applicable Design Pattern:

Agent: The system acts as an agent that interacts with the user. It takes user input (topic, feedback), performs an action (generates a joke), and then decides the next step based on user feedback (either end or try generating another joke). This iterative process of generation and feedback fits the agent pattern.

Flow high-level Design:

  1. GetTopicNode: Prompts the user to enter the topic for the joke.
  2. GenerateJokeNode: Generates a joke based on the topic and any previous feedback.
  3. GetFeedbackNode: Presents the joke to the user and asks for approval. Based on the feedback, it either transitions to end the flow or back to GenerateJokeNode.
flowchart TD
    GetTopic[GetTopicNode] --> GenerateJoke[GenerateJokeNode]
    GenerateJoke --> GetFeedback[GetFeedbackNode]
    GetFeedback -- "Approve" --> Z((End))
    GetFeedback -- "Disapprove" --> GenerateJoke

Utility Functions

Notes for AI:

  1. Understand the utility function definition thoroughly by reviewing the doc.
  2. Include only the necessary utility functions, based on nodes in the flow.
  1. Call LLM (utils/call_llm.py)
    • Input: prompt (str), potentially including context like previously disliked jokes.
    • Output: response (str) - the generated joke.
    • Necessity: Used by GenerateJokeNode to generate jokes.

Node Design

Shared Store

Notes for AI: Try to minimize data redundancy

The shared store structure is organized as follows:

shared = {
    "topic": None,             # Stores the user-provided joke topic
    "current_joke": None,      # Stores the most recently generated joke
    "disliked_jokes": [],    # A list to store jokes the user didn't like, for context
    "user_feedback": None      # Stores the user's latest feedback (e.g., "approve", "disapprove")
}

Node Steps

Notes for AI: Carefully decide whether to use Batch/Async Node/Flow.

  1. GetTopicNode

    • Purpose: To get the desired joke topic from the user.
    • Type: Regular
    • Steps:
      • prep: (None needed for the first run, or could check if a topic already exists if we were to loop for a new topic)
      • exec: Prompt the user via input() for a joke topic.
      • post: Store the user's input topic into shared["topic"]. Return "default" action to proceed to GenerateJokeNode.
  2. GenerateJokeNode

    • Purpose: To generate a joke using an LLM, based on the topic and any previously disliked jokes.
    • Type: Regular
    • Steps:
      • prep: Read shared["topic"] and shared["disliked_jokes"]. Construct a prompt for the LLM, including the topic and a message like "The user did not like the following jokes: [list of disliked jokes]. Please generate a new, different joke about [topic]."
      • exec: Call the call_llm utility function with the prepared prompt.
      • post: Store the generated joke in shared["current_joke"]. Print the joke to the console. Return "default" action to proceed to GetFeedbackNode.
  3. GetFeedbackNode

    • Purpose: To get feedback from the user about the generated joke and decide the next step.
    • Type: Regular
    • Steps:
      • prep: Read shared["current_joke"].
      • exec: Prompt the user (e.g., "Did you like this joke? (yes/no) or (approve/disapprove): "). Get user's input.
      • post:
        • If user input indicates approval (e.g., "yes", "approve"):
          • Store "approve" in shared["user_feedback"].
          • Return "Approve" action (leading to flow termination or a thank you message).
        • If user input indicates disapproval (e.g., "no", "disapprove"):
          • Store "disapprove" in shared["user_feedback"].
          • Add shared["current_joke"] to the shared["disliked_jokes"] list.
          • Return "Disapprove" action (leading back to GenerateJokeNode).