Hello World Bot
Let’s build a simple “Greeter” bot from scratch. By the end, you’ll have a working bot that greets users and remembers their names.
Prerequisites
- Flexus running (either self-hosted or SaaS)
- Python 3.10+ installed
flexus-client-kitpackage installed:Terminal window pip install flexus-client-kit- API key from your Flexus instance
Project Setup
-
Create the directory structure:
Terminal window mkdir -p greetercd greetertouch __init__.py greeter_bot.py greeter_prompts.py greeter_install.py -
Set environment variables:
Terminal window export FLEXUS_API_BASEURL=http://localhost:8000/ # or https://flexus.team/export FLEXUS_API_KEY=your-api-keyexport FLEXUS_WORKSPACE=your-workspace-id
Step 1: Define the Prompts
Create greeter_prompts.py:
"""System prompts for the Greeter bot.Kept separate from runtime code for easy editing and versioning."""
SYSTEM_PROMPT_DEFAULT = """You are Greeter, a friendly bot that welcomes users.
## Your Personality- Warm and welcoming- Remembers user names- Uses appropriate greeting based on time of day
## Your Tools
### greetUse this to generate a personalized greeting. Always use this tool when the user introduces themselves or asks for a greeting.
### remember_nameUse this to store the user's name for future conversations.
## How to Respond
1. When someone says hello, use the `greet` tool2. If they tell you their name, use `remember_name` to save it3. Be friendly but not overly enthusiastic"""Step 2: Create the Bot
Create greeter_bot.py:
"""Greeter Bot - A simple hello world bot for learning Flexus."""import asynciofrom datetime import datetimefrom typing import Dict, Any
from flexus_client_kit import ckit_clientfrom flexus_client_kit import ckit_cloudtoolfrom flexus_client_kit import ckit_bot_execfrom flexus_client_kit import ckit_shutdownfrom greeter import greeter_install
BOT_NAME = "greeter"BOT_VERSION = "1.0.0"
# --- Tool Definitions ---# Tools must be defined with strict=True for OpenAI compatibility.# All parameters go in "required", use ["type", "null"] for optional ones.
GREET_TOOL = ckit_cloudtool.CloudTool( strict=True, name="greet", description="Generate a personalized greeting for a user.", parameters={ "type": "object", "properties": { "name": { "type": ["string", "null"], "description": "The user's name. Null if unknown.", }, "style": { "type": "string", "enum": ["formal", "casual", "enthusiastic"], "description": "The greeting style to use.", }, }, "required": ["name", "style"], "additionalProperties": False, },)
REMEMBER_NAME_TOOL = ckit_cloudtool.CloudTool( strict=True, name="remember_name", description="Store the user's name for future conversations.", parameters={ "type": "object", "properties": { "name": { "type": "string", "description": "The name to remember.", }, }, "required": ["name"], "additionalProperties": False, },)
# All tools this bot providesTOOLS = [GREET_TOOL, REMEMBER_NAME_TOOL]
# --- Helper Functions ---
def get_time_of_day() -> str: """Returns 'morning', 'afternoon', or 'evening' based on current hour.""" hour = datetime.now().hour if hour < 12: return "morning" elif hour < 17: return "afternoon" else: return "evening"
def generate_greeting(name: str | None, style: str) -> str: """Generate a greeting based on name, style, and time of day.""" tod = get_time_of_day() name_part = name if name else "friend"
greetings = { "formal": { "morning": f"Good morning, {name_part}. I hope you have a productive day.", "afternoon": f"Good afternoon, {name_part}. How may I assist you?", "evening": f"Good evening, {name_part}. How can I help you this evening?", }, "casual": { "morning": f"Hey {name_part}! Morning!", "afternoon": f"Hi {name_part}! What's up?", "evening": f"Hey {name_part}! How's it going?", }, "enthusiastic": { "morning": f"GOOD MORNING {name_part.upper()}! What an AMAZING day!", "afternoon": f"HEY {name_part.upper()}! So great to see you!", "evening": f"EVENING {name_part.upper()}! Let's make this evening AWESOME!", }, }
return greetings.get(style, greetings["casual"]).get(tod, "Hello!")
# --- Main Bot Loop ---
async def greeter_main_loop(fclient: ckit_client.FlexusClient, rcx: ckit_bot_exec.RobotContext) -> None: """ Main loop for the Greeter bot.
rcx (RobotContext) provides: - rcx.persona: The bot's persona configuration - rcx.latest_threads: Active threads - rcx.latest_tasks: Kanban tasks - Decorators for event handlers """ # Merge default setup with user overrides setup = ckit_bot_exec.official_setup_mixing_procedure( greeter_install.greeter_setup_schema, rcx.persona.persona_setup )
# In-memory storage for names (in production, use MongoDB) remembered_names: Dict[str, str] = {}
# --- Tool Handlers --- # Each tool in TOOLS must have a handler decorated with @rcx.on_tool_call
@rcx.on_tool_call(GREET_TOOL.name) async def handle_greet(toolcall: ckit_cloudtool.FCloudtoolCall, args: Dict[str, Any]) -> str: """ Handle the greet tool call.
Args: toolcall: Contains fcall_id, fcall_ft_id (thread), etc. args: The arguments the LLM provided
Returns: String result that the LLM will see """ name = args.get("name") style = args.get("style", "casual")
# Check if we have a remembered name for this thread if not name: name = remembered_names.get(toolcall.fcall_ft_id)
greeting = generate_greeting(name, style) return greeting
@rcx.on_tool_call(REMEMBER_NAME_TOOL.name) async def handle_remember_name(toolcall: ckit_cloudtool.FCloudtoolCall, args: Dict[str, Any]) -> str: """Store a user's name.""" name = args["name"] remembered_names[toolcall.fcall_ft_id] = name return f"Got it! I'll remember that your name is {name}."
# --- Event Handlers (optional) ---
@rcx.on_updated_message async def on_message(msg): """Called when a new message arrives or is updated.""" pass # We don't need to do anything special here
@rcx.on_updated_thread async def on_thread(thread): """Called when a thread is updated.""" pass
# --- Main Loop --- # This loop runs until shutdown, processing events as they arrive
try: while not ckit_shutdown.shutdown_event.is_set(): # This processes all queued events (messages, tool calls, etc.) # and sleeps for up to 10 seconds if there's nothing to do await rcx.unpark_collected_events(sleep_if_no_work=10.0)
finally: # Cleanup code runs on shutdown print(f"Greeter bot {rcx.persona.persona_id} shutting down")
# --- Entry Point ---
def main(): """Entry point for running the bot.""" # Parse command line args (--scenario, --group, etc.) scenario_fn = ckit_bot_exec.parse_bot_args()
# Create Flexus client fclient = ckit_client.FlexusClient( ckit_client.bot_service_name(BOT_NAME, BOT_VERSION), endpoint="/v1/jailed-bot" )
# Run the bot asyncio.run(ckit_bot_exec.run_bots_in_this_group( fclient, marketable_name=BOT_NAME, marketable_version_str=BOT_VERSION, bot_main_loop=greeter_main_loop, inprocess_tools=TOOLS, scenario_fn=scenario_fn, install_func=greeter_install.install, ))
if __name__ == "__main__": main()Step 3: Create the Install Script
Create greeter_install.py:
"""Installation script for Greeter bot.Run with: python greeter_install.py --ws=your_workspace_id"""import jsonfrom flexus_client_kit import ckit_bot_installfrom flexus_client_kit.ckit_bot_install import FMarketplaceExpertInputfrom flexus_simple_bots import prompts_commonfrom greeter import greeter_bot, greeter_prompts
# Setup schema - defines user-configurable options# These appear in the bot's setup dialog in the UIgreeter_setup_schema = { "default_style": { "bs_type": "string_short", "bs_default": "casual", "bs_group": "behavior", "bs_description": "Default greeting style (formal, casual, enthusiastic)", },}
# Convert tools to JSON for expert definitiontools_json = json.dumps([t.openai_style_tool() for t in greeter_bot.TOOLS])
def install(ws_id: str): """Install the bot to the marketplace.""" return ckit_bot_install.marketplace_upsert_dev_bot( ws_id=ws_id, marketable_name="greeter", marketable_version="1.0.0", marketable_title1="Greeter", marketable_title2="A friendly bot that welcomes users", marketable_occupation="Welcomer", marketable_author="Flexus Team", marketable_description="""Greeter is a simple bot that demonstrates Flexus bot development.
## Features- Personalized greetings based on time of day- Remembers user names- Multiple greeting styles (formal, casual, enthusiastic)
## Example UsageJust say hello and introduce yourself!""", marketable_typical_group="Assistants / Demo", marketable_tags=["demo", "greeting", "hello-world"], marketable_setup_schema=json.dumps(greeter_setup_schema), # For demo, we'll skip images - in real bot, load them: # marketable_picture_big_b64=ckit_bot_install.load_image_b64(__file__, "greeter-1024x1536.webp"), # marketable_picture_small_b64=ckit_bot_install.load_image_b64(__file__, "greeter-256x256.webp"), marketable_picture_big_b64="", marketable_picture_small_b64="", marketable_experts=[ ("default", FMarketplaceExpertInput( fexp_system_prompt=greeter_prompts.SYSTEM_PROMPT_DEFAULT, fexp_app_capture_tools=tools_json, )), ], marketable_schedule=[ # This bot doesn't need schedules - it only responds to direct chat ], )
if __name__ == "__main__": ckit_bot_install.main_install_dev_bot(install)Step 4: Install and Run
-
Install to marketplace:
Terminal window python greeter_install.py --ws=your_workspace_idYou should see output like:
Installed greeter version 1.0.0 -
Hire the bot in UI:
Go to Marketplace in the Flexus UI, find “Greeter”, and click “Hire”.
-
Run the bot:
Terminal window python greeter_bot.pyThe bot will connect and start listening for events.
-
Test it:
Open a chat with Greeter in the UI and say:
Hello! My name is Alex.The bot should greet you and remember your name.
Understanding What Happened
- You sent a message — Stored in PostgreSQL, published to Redis
- Advancer picked it up — Called the LLM with your system prompt and tools
- LLM decided to use tools — Called
remember_namethengreet - Tool calls routed to your bot — Via GraphQL subscription
- Your handlers executed — Returned results to backend
- LLM received results — Generated final response
- Response sent to you — Streamed back to the UI
Adding Persistence
The example stores names in memory. For real bots, use MongoDB:
from pymongo import AsyncMongoClientfrom flexus_client_kit import ckit_mongo
async def greeter_main_loop(fclient, rcx): # Get MongoDB credentials mongo_conn_str = await ckit_mongo.mongo_fetch_creds(fclient, rcx.persona.persona_id) mongo = AsyncMongoClient(mongo_conn_str) db = mongo[rcx.persona.persona_id + "_db"] names_collection = db["remembered_names"]
@rcx.on_tool_call(REMEMBER_NAME_TOOL.name) async def handle_remember_name(toolcall, args): name = args["name"] await names_collection.update_one( {"thread_id": toolcall.fcall_ft_id}, {"$set": {"name": name}}, upsert=True ) return f"Got it! I'll remember that your name is {name}."
# ... rest of the codeNext Steps
Congratulations! You’ve built your first Flexus bot. Next:
- Tools Deep Dive — Learn tool definition patterns
- Kanban Board — Add task management
- Basic Bot Pattern — See a complete production bot