t27.aiРусский

A bot is a message loop

You will learn

How a bot waits for a message, picks a reply from a table and goes back to waiting, and why the same message always gets the same reply.

A bot is not magic. It is a loop with four beats: wait for a message, read it, pick a reply, send it, and wait again. In message_loop.t27 a message is a small number: 1 is start, 2 is help, 3 is stop, and anything else is not understood. A table maps each message to a reply, so one turn of the loop is one lookup. The inbox holds 5 messages and the loop stops at the stop message, so it answers 4. Send the widget a few messages and notice that the same message always gets the same reply.

Try it

Send start, then help, then an unknown word, then stop, and count the replies. In the spec frame, find the inbox and the index of its stop message, and the test that turns red when two commands share a reply.

Open the interactive lesson →

A bot is a loop: send messages, watch it answer ↗

Send start, help or an unknown word to a toy bot and watch the four beats of its message loop: wait, read, reply, wait again. A stop message ends it. Nothing is sent.

specs/vibecoding/message_loop.t27

// SPDX-License-Identifier: Apache-2.0
; specs/vibecoding/message_loop.t27 -- lesson "A bot is a message loop" of the course Vibecoding from zero
; The one idea: a bot is a loop. It takes the next message, decides a reply from the message alone,
; sends the reply, and goes back for the next message, until a stop message arrives.
; Messages are small numbers here so the loop is easy to read: 1 is start, 2 is help, 3 is stop,
; anything else is a message the bot does not know. Replies are numbers too: 10 hello, 20 help,
; 90 not understood. The reply table is indexed by the message, so one turn of the loop is one
; lookup. ASCII only (L3), English only (LANG-EN).
; phi^2 + 1/phi^2 = 3 | TRINITY

module vc_message_loop;

pub const MSG_START : u8 = 1;
pub const MSG_HELP : u8 = 2;
pub const MSG_STOP : u8 = 3;

pub const REPLY_HELLO : u8 = 10;
pub const REPLY_HELP : u8 = 20;
pub const REPLY_UNKNOWN : u8 = 90;

; The reply for message 0, 1, 2 and 3; message 3 is the stop message and gets no reply (0).
pub const REPLY_TABLE : [4]u8 = [90, 10, 20, 0];

; The inbox: five messages waiting. The third one (9) is not a known command.
pub const INBOX : [5]u8 = [1, 2, 9, 2, 3];

; One turn of the loop: the reply depends on the message and on nothing else.
pub fn reply_for(msg: u8) -> u8 {
    if (msg == 1) {
        return 10;
    }
    if (msg == 2) {
        return 20;
    }
    return 90;
}

; The loop: go through the inbox from the first message, stop at a stop message, and count the
; replies sent. A stop message is not answered.
pub fn replies_sent() -> u8 {
    var sent : u8 = 0;
    var i : u8 = 0;
    while (i < 5) {
        if (INBOX[i] == 3) {
            return sent;
        }
        sent = sent + 1;
        i = i + 1;
    }
    return sent;
}

; The loop stops at the first stop message: index 4, so four replies were sent.
pub const STOP_AT : u8 = 4;

test start_gets_hello {
    assert REPLY_TABLE[MSG_START] == REPLY_HELLO;
}

test help_gets_help {
    assert REPLY_TABLE[MSG_HELP] == REPLY_HELP;
}

test an_unknown_message_is_not_understood {
    assert REPLY_TABLE[0] == REPLY_UNKNOWN;
}

test the_loop_answers_four_messages_then_stops {
    assert INBOX[STOP_AT] == MSG_STOP;
    assert INBOX[0] != MSG_STOP;
    assert INBOX[1] != MSG_STOP;
    assert INBOX[2] != MSG_STOP;
    assert INBOX[3] != MSG_STOP;
}

; Negative control: two different commands must not get the same reply. Plant the bug
; (REPLY_TABLE = [90, 20, 20, 0], two commands mixed up) and this test turns red.
test two_commands_never_share_a_reply {
    assert REPLY_TABLE[MSG_START] != REPLY_TABLE[MSG_HELP];
    assert REPLY_TABLE[MSG_START] != REPLY_TABLE[0];
}

Open the lesson's spec in the player ↗

All lessons