t27.aiEnglish

Бот — это цикл сообщений

Вы узнаете

Как бот ждёт сообщение, берёт ответ из таблицы и снова ждёт, и почему одно и то же сообщение всегда получает один и тот же ответ.

Бот — не магия. Это цикл из четырёх тактов: ждать сообщение, прочитать его, выбрать ответ, отправить его и снова ждать. В message_loop.t27 сообщение — маленькое число: 1 — старт, 2 — помощь, 3 — стоп, всё остальное не понято. Таблица связывает каждое сообщение с ответом, поэтому один оборот цикла — это один поиск. В очереди 5 сообщений, и цикл останавливается на сообщении «стоп», так что отвечает на 4. Отправьте виджету несколько сообщений и заметьте: одно и то же сообщение всегда получает один и тот же ответ.

Попробуйте

Отправьте старт, потом помощь, потом незнакомое слово, потом стоп и посчитайте ответы. В кадре со спецификацией найдите очередь и индекс её сообщения «стоп», а также тест, который краснеет, когда у двух команд общий ответ.

Открыть интерактивный урок →

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];
}

Открыть спеку урока в плеере ↗

Все уроки