Краткая справка для LLM
Краткая справка для LLM
Заголовок раздела «Краткая справка для LLM»Эта страница предназначена для ИИ-агентов и LLM. Если вы разрабатываете на Wippy или генерируете код для проекта Wippy, прочтите это в первую очередь.
Что такое Wippy
Заголовок раздела «Что такое Wippy»Wippy — это среда выполнения приложений в виде одного бинарника, построенная на модели акторов. Она запускает код Lua в изолированных процессах с передачей сообщений — без разделяемой памяти, без блокировок. Существует три вычислительные модели: функции (без состояния, в рамках запроса), процессы (долгоживущие акторы с состоянием) и рабочие процессы (durable-акторы на базе Temporal, переживающие сбои). Система спроектирована так, чтобы агенты могли генерировать код, регистрировать его и улучшать приложения без повторного развёртывания.
Ментальная модель
Заголовок раздела «Ментальная модель»Всё в Wippy — это запись реестра (registry entry). Записи имеют ID (namespace:name), вид (определяющий поведение), метаданные и данные. YAML-файлы — один из способов объявления записей, но реестр является источником истины во время выполнения, и записи могут создаваться, обновляться или удаляться во время работы системы.
Виды определяют, что делает запись:
function.lua— вызываемая функция без состоянияprocess.lua— долгоживущий акторworkflow.lua— durable-воркфлоу (Temporal)http.service— HTTP-серверhttp.router— группа маршрутов с middlewarehttp.endpoint— HTTP-обработчикdb.sql.postgres/mysql/sqlite— подключение к БДstore.memory/store.sql— key-value хранилищеqueue.queue— очередь сообщенийprocess.host— хост выполнения процессовprocess.service— контролируемый процессcontract.definition/contract.binding— типизированные интерфейсы сервисовregistry.entry— данные конфигурации
Структура проекта
Заголовок раздела «Структура проекта»myapp/├── .wippy.yaml # Runtime configuration├── wippy.lock # Source directories└── src/ ├── _index.yaml # Entry definitions (namespace: app) ├── api/ │ ├── _index.yaml # namespace: app.api │ └── handler.lua └── workers/ ├── _index.yaml # namespace: app.workers └── task.luaОпределения записей находятся в файлах _index.yaml:
version: "1.0"namespace: app.api
entries: - name: get_user kind: function.lua source: file://handler.lua method: get_user modules: [sql, json]
- name: get_user.endpoint kind: http.endpoint meta: router: app:api_router method: GET path: /users/{id} func: app.api:get_userНаписание функций
Заголовок раздела «Написание функций»Функции не имеют состояния. Они получают аргументы, выполняют работу и возвращают результаты. Они наследуют контекст вызывающего и отменяются, если вызывающий отменён.
local sql = require("sql")local json = require("json")local http = require("http")
local function get_user(id) local db, err = sql.get("app:main_db") if err then return nil, err end
local rows, err = db:query("SELECT * FROM users WHERE id = $1", id) if err then return nil, err end if #rows == 0 then return nil, errors.new(errors.NOT_FOUND, "user not found") end
return rows[1]end
return get_userДля HTTP-обработчиков используйте модуль http:
local http = require("http")local json = require("json")
local function handler() local req = http.request() local res = http.response()
local id = req:param("id") local user, err = funcs.call("app.api:get_user", id) if err then res:set_status(404) res:write_json({error = err:message()}) return end
res:write_json(user)end
return handlerНаписание процессов
Заголовок раздела «Написание процессов»Процессы — это акторы. У них есть собственный PID, они получают сообщения через inbox и сохраняют состояние между сообщениями. Они уступают выполнение при блокирующем I/O, что позволяет тысячам из них работать одновременно.
local function worker(initial_config) local inbox = process.inbox() local events = process.events()
while true do local r = channel.select { inbox:case_receive(), events:case_receive() }
if r.channel == events then local ev = r.value if ev.type == process.event.CANCEL then break end elseif r.channel == inbox then local msg = r.value local topic = msg:topic() local data = msg:payload():data() handle_message(topic, data) end endend
return workerЗапускайте процессы из другого кода:
local pid = process.spawn("app.workers:task", "app:process_host", config)process.send(pid, "work", {item_id = 123})Написание воркфлоу
Заголовок раздела «Написание воркфлоу»Воркфлоу durable — они переживают сбои и перезапуски. Код выглядит как обычный Lua. Среда выполнения автоматически записывает результаты вызовов функций, сны и случайные значения, чтобы воспроизведение было детерминированным.
local function order_flow(order) local inventory = funcs.call("app:reserve_inventory", order.items) if not inventory then return nil, errors.new("out of stock") end
local payment = funcs.call("app:charge_payment", order.total) if not payment then funcs.call("app:release_inventory", inventory.id) return nil, errors.new("payment failed") end
-- Wait for approval signal (can block for days) local msg = process.inbox():receive() if not msg:payload():data().approved then funcs.call("app:refund_payment", payment.id) funcs.call("app:release_inventory", inventory.id) return nil, errors.new("rejected") end
return funcs.call("app:fulfill_order", order.id)end
return order_flowКлючевые API
Заголовок раздела «Ключевые API»Вызов функций
Заголовок раздела «Вызов функций»local funcs = require("funcs")
-- Synchronouslocal result, err = funcs.call("namespace:function_name", arg1, arg2)
-- Asynchronous (returns Future)local future = funcs.async("namespace:function_name", arg1)local result, err = future:result()
-- With contextlocal exec = funcs.new():with_context({user_id = "123"})exec:call("namespace:function_name")Взаимодействие процессов
Заголовок раздела «Взаимодействие процессов»-- Send message (fire-and-forget)process.send(pid, "topic", data)
-- Receive messageslocal inbox = process.inbox()local msg, ok = inbox:receive()local topic = msg:topic()local data = msg:payload():data()
-- Monitor another process (receive EXIT on death)process.monitor(pid)
-- Link processes (bidirectional failure notification)process.spawn_linked("namespace:name", "host")Каналы в стиле Go для взаимодействия корутин:
local ch = channel.new(10) -- bufferedch:send(value)local val, ok = ch:receive()
-- Select on multiple channelslocal r = channel.select { ch1:case_receive(), ch2:case_receive(), timeout:case_receive()}Обработка ошибок
Заголовок раздела «Обработка ошибок»Функции возвращают пары result, error. Ошибки — это типизированные объекты:
local result, err = some_operation()if err then if errors.is(err, errors.NOT_FOUND) then -- handle not found end return nil, errors.wrap(err, "context message")endВиды ошибок: UNKNOWN, INVALID, NOT_FOUND, ALREADY_EXISTS, PERMISSION_DENIED, TIMEOUT, CANCELED, UNAVAILABLE, INTERNAL, CONFLICT, RATE_LIMITED.
Доступ к данным
Заголовок раздела «Доступ к данным»-- SQLlocal sql = require("sql")local db = sql.get("app:main_db")local rows, err = db:query("SELECT * FROM users WHERE active = $1", true)db:execute("INSERT INTO users (name) VALUES ($1)", name)
-- Key-value storelocal store = require("store")local cache = store.get("app:cache")cache:set("key", value, 3600) -- TTL in secondslocal val = cache:get("key")
-- Queuelocal queue = require("queue")queue.publish("app:tasks", {task = "process", id = 123})
-- Filesystemlocal fs = require("fs")local vol = fs.get("app:storage")local data = vol:readfile("path/to/file.txt")vol:writefile("output.txt", content)HTTP-клиент
Заголовок раздела «HTTP-клиент»local http_client = require("http_client")
local resp, err = http_client.get("https://api.example.com/data", { headers = {Authorization = "Bearer token"}, timeout = "10s"})local body = resp.bodyБезопасность
Заголовок раздела «Безопасность»local security = require("security")
local actor = security.actor() -- who is callinglocal scope = security.scope() -- what permissions applylocal allowed = security.can("read", "resource:users")
-- Token managementlocal ts = security.token_store("app:tokens")local token = ts:create(actor, scope, {expiration = "24h"})local validated_actor, validated_scope = ts:validate(token)local time = require("time")
time.sleep("5s")local now = time.now()local timeout = time.after("30s") -- channel that fires oncelocal ticker = time.ticker("10s") -- repeating channellocal registry = require("registry")
local entry = registry.get("app.api:get_user")local tests = registry.find({["meta.type"] = "test"})
-- Create entries at runtimelocal snap = registry.snapshot()local changes = snap:changes()changes:create({id = "app:new_func", kind = "function.lua", data = {...}})changes:apply()События
Заголовок раздела «События»local events = require("events")
-- Publishevents.send("orders", "order.created", "/orders/123", {order_id = "123"})
-- Subscribe (wildcards supported)local sub = events.subscribe("orders.*")local ch = sub:channel()local evt = ch:receive()Контроль доступа к модулям
Заголовок раздела «Контроль доступа к модулям»Каждая запись объявляет, какие модули она может require(). Модули, не указанные в списке, просто недоступны — нет os.execute, io.open, debug.* или package.*, если вы явно их не разрешили. Среда выполнения не сканирует и не валидирует исходный код; она контролирует доступ на уровне модуля. Если модуль не в списке, для данной записи он не существует.
modules: [sql, json, http, time, funcs, store]Так же работает и детерминизм воркфлоу — воркфлоу-записи получают только детерминированные модули. Среда выполнения перехватывает time.now(), uuid.v4() и другие недетерминированные вызовы на уровне модуля, записывая результаты для воспроизведения.
Модули фреймворка
Заголовок раздела «Модули фреймворка»В Wippy есть модули фреймворка, устанавливаемые через зависимости:
- wippy/llm — интеграция LLM (OpenAI, Anthropic, Google).
llm.generate(), структурированный вывод, эмбеддинги, стриминг. - wippy/agent — агентный фреймворк с вызовом инструментов, делегированием, трейтами, памятью. Агенты определяются как записи реестра.
- wippy/test — BDD-тестирование. Блоки
describe/it, утверждения, моки. - wippy/dataflow — оркестрация воркфлоу на базе DAG. Узлы Function, Agent, Cycle, Parallel.
- wippy/relay — WebSocket-реле с центральным хабом, пользовательскими хабами, маршрутизацией плагинов.
- wippy/views — система страниц и компонентов с рендерингом шаблонов.
- wippy/facade — фронтенд iframe-фасад с мостом аутентификации.
Соглашения
Заголовок раздела «Соглашения»- ID записей используют формат
namespace:name - Имена используют точки для семантического разделения, подчёркивания для слов:
get_user.endpoint - Функции возвращают
result, error— всегда проверяйте ошибку - Процессы взаимодействуют через передачу сообщений, никогда через общее состояние
- Используйте
channel.selectдля мультиплексирования нескольких источников событий - Деревья супервизоров обрабатывают сбои — проектируйте по принципу “let it crash”
- Контекст (trace ID, информация о пользователе, безопасность) автоматически распространяется через вызовы функций
- Воркфлоу не должны напрямую использовать недетерминированные операции — среда выполнения обрабатывает это для
funcs.call,time.sleep,uuid.v4,time.now
Документация
Заголовок раздела «Документация»Полная документация доступна на wippy.ai/docs. Эндпоинты, удобные для LLM:
- Просмотр структуры:
https://wippy.ai/llm/toc - Поиск:
https://wippy.ai/llm/search?q=query - Получение страницы:
https://wippy.ai/llm/path/en/<path> - Пакетное получение:
https://wippy.ai/llm/context?paths=path1,path2