# Script Execution Flow & Entry Points Understanding how General Bots BASIC scripts are loaded, compiled, and executed is essential for building effective automation. This document covers the complete execution lifecycle. ## Execution Entry Points Scripts in General Bots can be triggered through several entry points: ![Script Execution Flow](../assets/script-execution-flow.svg) *BASIC scripts compile to Rhai AST and execute with registered keyword handlers. Scripts in .gbdialog/ are hot-reloaded on change.* ### 1. Bot Startup (`start.bas`) The primary entry point. Executed when a bot initializes or a conversation begins. ```basic ' start.bas - Primary entry point ' NO MAIN function needed - execution starts at line 1 ' 1. Register tools for LLM to use ADD TOOL "create-order" ADD TOOL "track-shipment" ADD TOOL "customer-lookup" ' 2. Load knowledge bases USE KB "products" USE KB "policies" ' 3. Set AI context/personality BEGIN SYSTEM PROMPT You are a helpful e-commerce assistant for AcmeStore. You can help customers with orders, tracking, and product questions. Always be friendly and professional. END SYSTEM PROMPT ' 4. Setup UI suggestions CLEAR SUGGESTIONS ADD SUGGESTION "New Order" ADD SUGGESTION "Track Package" ADD SUGGESTION "Contact Support" ' 5. Welcome message BEGIN TALK **Welcome to AcmeStore!** 🛒 I can help you: • Browse and order products • Track your shipments • Answer questions What would you like to do? END TALK ``` ### 2. Scheduled Execution (`SET SCHEDULE`) Scripts can run on a cron schedule without user interaction. ```basic ' sync-data.bas - Runs automatically on schedule SET SCHEDULE "0 0 */4 * * *" ' Every 4 hours ' Variables from config.csv are available ' param-host -> host, param-limit -> limit, param-pages -> pages SEND EMAIL admin1, "Data sync started..." page = 1 DO WHILE page > 0 AND page < pages res = GET host + "/products?page=" + page + "&limit=" + limit IF res.data THEN MERGE "products" WITH res.data BY "id" page = page + 1 ELSE page = 0 END IF WAIT 0.5 ' Rate limiting LOOP SEND EMAIL admin1, "Sync complete! " + REPORT RESET REPORT ``` **Cron Format:** `second minute hour day month weekday` | Pattern | Description | |---------|-------------| | `0 0 8 * * *` | Daily at 8:00 AM | | `0 30 22 * * *` | Daily at 10:30 PM | | `0 0 0 */2 * *` | Every 2 days at midnight | | `0 0 * * * *` | Every hour | | `0 */15 * * * *` | Every 15 minutes | ### 3. Webhook Entry (`WEBHOOK`) Scripts exposed as HTTP endpoints for external integrations. ```basic ' order-webhook.bas - HTTP endpoint WEBHOOK "order-received" ' Creates: POST /api/bot/{botname}/order-received ' Parameters become variables automatically ' Access webhook parameters orderId = GET TOOL PARAM "orderId" customerEmail = GET TOOL PARAM "email" amount = GET TOOL PARAM "amount" ' Validate (optional) IF orderId = "" THEN RETURN #{ status: 400, error: "Missing orderId" } END IF ' Process the webhook order = NEW OBJECT order.id = orderId order.email = customerEmail order.amount = amount order.status = "received" order.timestamp = NOW SAVE "orders", order ' Notify TALK TO customerEmail, "Order " + orderId + " received! Total: $" + amount RETURN #{ status: 200, orderId: orderId, message: "Order processed" } ``` ### 4. LLM Tool Invocation When registered with `ADD TOOL`, scripts become callable by the LLM during conversation. ```basic ' create-order.bas - Called by LLM when user wants to order PARAM productId AS STRING LIKE "PROD-001" REQUIRED PARAM quantity AS NUMBER LIKE 1 REQUIRED PARAM customerEmail AS STRING LIKE "john@example.com" REQUIRED DESCRIPTION "Creates a new order for a product" ' This script is invoked by the LLM, not directly by user ' The LLM collects all parameters through natural conversation product = FIND "products", "id=" + productId IF ISEMPTY(product) THEN RETURN "Product not found: " + productId END IF IF product.stock < quantity THEN RETURN "Only " + product.stock + " available" END IF ' Create the order order = NEW OBJECT order.id = "ORD-" + FORMAT(NOW, "yyyyMMddHHmmss") order.productId = productId order.quantity = quantity order.total = product.price * quantity order.customerEmail = customerEmail order.status = "pending" SAVE "orders", order ' Update inventory UPDATE "products", productId, "stock=" + (product.stock - quantity) RETURN "Order " + order.id + " created! Total: $" + order.total ``` ### 5. Event Handlers (`ON`) React to system events. ```basic ' events.bas - Event handlers ON "message" CALL HandleMessage ON "user_joined" CALL WelcomeUser ON "error" CALL LogError SUB HandleMessage(message) ' Process incoming message LOG_INFO "Received: " + message.text END SUB SUB WelcomeUser(user) TALK TO user.email, "Welcome to our service!" END SUB SUB LogError(error) LOG_ERROR "Error occurred: " + error.message SEND EMAIL admin1, "Bot Error: " + error.message END SUB ``` --- ## Variable Injection from config.csv Variables defined with `param-` prefix in config.csv are automatically injected into script scope. ### config.csv ```csv name,value bot-name,Bling Integration bot-description,ERP synchronization bot param-host,https://api.bling.com.br/Api/v3 param-limit,100 param-pages,50 param-admin1,admin@company.com param-admin2,backup@company.com param-blingClientID,your-client-id param-blingClientSecret,your-secret ``` ### Script Usage ```basic ' Variables are available without param- prefix ' All normalized to lowercase for case-insensitivity result = GET host + "/products?limit=" + limit DO WHILE page < pages ' Use injected variables directly data = GET host + "/items?page=" + page LOOP ' Admin emails for notifications SEND EMAIL admin1, "Sync complete!" SEND EMAIL admin2, "Backup notification" ``` ### Type Conversion Values are automatically converted: - Numbers: `param-limit,100` → `limit` as integer `100` - Floats: `param-rate,0.15` → `rate` as float `0.15` - Booleans: `param-enabled,true` → `enabled` as boolean `true` - Strings: Everything else remains as string --- ## Case Insensitivity **All variables in General Bots BASIC are case-insensitive.** ```basic ' These all refer to the same variable host = "https://api.example.com" result = GET Host + "/endpoint" TALK HOST ``` The preprocessor normalizes all variable names to lowercase while preserving: - Keywords (remain UPPERCASE for clarity) - String literals (exact content preserved) - Comments (skipped entirely) --- ## Script Compilation Flow ``` ┌─────────────────────────────────────────────────────────────────┐ │ COMPILATION PIPELINE │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. LOAD SOURCE │ │ └─→ Read .bas file from .gbdialog folder │ │ │ │ 2. LOAD CONFIG │ │ └─→ Read config.csv, extract param-* entries │ │ └─→ Inject into execution scope │ │ │ │ 3. PREPROCESS │ │ ├─→ Strip comments (REM, ', //) │ │ ├─→ Process SWITCH/CASE blocks │ │ ├─→ Normalize variables to lowercase │ │ ├─→ Transform multi-word keywords │ │ └─→ Handle FOR EACH blocks │ │ │ │ 4. COMPILE │ │ └─→ Parse to Rhai AST │ │ │ │ 5. EXECUTE │ │ └─→ Run AST with injected scope │ │ └─→ Keywords call registered handlers │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Functions vs Entry Points ### NO MAIN Function Unlike traditional programming, BASIC scripts do NOT use a `MAIN` function. Execution starts at line 1. ```basic ' ❌ WRONG - Don't do this SUB MAIN() TALK "Hello" END SUB ' ✅ CORRECT - Start directly TALK "Hello" ``` ### SUB and FUNCTION for Reuse Use `SUB` and `FUNCTION` for reusable code within tools, not as entry points. ```basic ' sync-products.bas - A complex tool with helper functions FUNCTION CalculateDiscount(price, percentage) RETURN price * (1 - percentage / 100) END FUNCTION SUB NotifyAdmin(message) SEND EMAIL admin1, message LOG_INFO message END SUB SUB ProcessProduct(product) IF product.discount > 0 THEN product.finalPrice = CalculateDiscount(product.price, product.discount) ELSE product.finalPrice = product.price END IF SAVE "products", product END SUB ' Main execution starts here (not in a MAIN sub) products = GET host + "/products" FOR EACH product IN products.data CALL ProcessProduct(product) NEXT product CALL NotifyAdmin("Processed " + COUNT(products.data) + " products") ``` --- ## Tool Chain Pattern Register tools in `start.bas`, implement in separate files: ### start.bas ```basic ' Register tools - LLM can call these ADD TOOL "create-customer" ADD TOOL "update-customer" ADD TOOL "delete-customer" ' Or clear and re-register CLEAR TOOLS ADD TOOL "order-management" ADD TOOL "inventory-check" ``` ### create-customer.bas ```basic PARAM name AS STRING LIKE "John Doe" REQUIRED PARAM email AS STRING LIKE "john@example.com" REQUIRED PARAM phone AS STRING LIKE "+1-555-0123" DESCRIPTION "Creates a new customer record in the CRM" ' Tool implementation customer = NEW OBJECT customer.id = "CUS-" + FORMAT(NOW, "yyyyMMddHHmmss") customer.name = name customer.email = email customer.phone = phone customer.createdAt = NOW SAVE "customers", customer RETURN #{ success: true, customerId: customer.id, message: "Customer created successfully" } ``` --- ## Best Practices ### 1. Organize by Purpose ``` mybot.gbai/ ├── mybot.gbdialog/ │ ├── start.bas ' Entry point, tool registration │ ├── tables.bas ' Database schema (TABLE definitions) │ │ │ ├── create-order.bas ' Tool: order creation │ ├── track-order.bas ' Tool: order tracking │ ├── cancel-order.bas ' Tool: order cancellation │ │ │ ├── sync-products.bas ' Scheduled: product sync │ ├── sync-inventory.bas ' Scheduled: inventory sync │ │ │ └── order-webhook.bas ' Webhook: external orders │ ├── mybot.gbot/ │ └── config.csv ' Configuration & param-* variables │ └── mybot.gbkb/ ' Knowledge base files ``` ### 2. Use param-* for Configuration Keep credentials and settings in config.csv, not hardcoded: ```basic ' ❌ WRONG host = "https://api.bling.com.br/Api/v3" apiKey = "hardcoded-key" ' ✅ CORRECT - From config.csv ' param-host and param-apiKey in config.csv result = GET host + "/endpoint" SET HEADER "Authorization", "Bearer " + apikey ``` ### 3. Error Handling in Tools ```basic PARAM orderId AS STRING REQUIRED DESCRIPTION "Cancels an order" order = FIND "orders", "id=" + orderId IF ISEMPTY(order) THEN RETURN #{ success: false, error: "Order not found" } END IF IF order.status = "shipped" THEN RETURN #{ success: false, error: "Cannot cancel shipped orders" } END IF UPDATE "orders", orderId, "status=cancelled" RETURN #{ success: true, message: "Order cancelled" } ``` ### 4. Logging for Scheduled Jobs ```basic SET SCHEDULE "0 0 6 * * *" LOG_INFO "Daily sync started" ' ... sync logic ... IF errorCount > 0 THEN LOG_WARN "Sync completed with " + errorCount + " errors" SEND EMAIL admin1, "Sync Warning", REPORT ELSE LOG_INFO "Sync completed successfully" END IF RESET REPORT ``` --- ## See Also - [Keyword Reference](./keywords.md) - Complete keyword documentation - [SET SCHEDULE](./keyword-set-schedule.md) - Scheduling details - [WEBHOOK](./keyword-webhook.md) - Webhook configuration - [Tools System](./keyword-use-tool.md) - Tool registration - [BEGIN SYSTEM PROMPT](./prompt-blocks.md) - AI context configuration