Создание приложений

Запуск правил Лиспекса

Создайте полный пакет правил, вызовите его из Топаза и обработайте исчерпание лимита ресурсов.

Вызовите правило Лиспекса из приложения на Топазе и обработайте результат при исчерпании лимита работы. Вы создадите шесть файлов и выполните одно правило с двумя разными лимитами.

Установите Топаз. Если вы ещё не работали с пакетами, пройдите Первое приложение. Вычислитель входит в Топаз, поэтому отдельно устанавливать Лиспекс не нужно. Эта интеграция использует Лиспекс 1.20.0.

Правило не может читать файлы, обращаться к системным часам или сети. Топаз подготавливает правило один раз. Каждое вычисление получает новую память, глобальные переменные, счётчики ресурсов и журнал выполнения.

Создайте правило и файлы лимитов

Создайте каталог lispex-first-call, а в нём каталоги rules и src. Сохраните в них следующие шесть файлов. Все команды ниже выполняйте из lispex-first-call.

Сохраните правило в rules/approve.lspx.

LISPEX
(if (< 10 15) "allow" "deny")

Правило сравнивает константы 10 и 15 и возвращает "allow". Входное значение оно не использует. Фиксированное решение позволяет сравнить завершённое вычисление с исчерпанием ресурсов.

Сохраните полный файл лимитов как rules/approve.limits.json.

JSON
{
  "schema": "topaz.lispex-embed-limits/v1",
  "prepare": {
    "raw_source_bytes": 4096,
    "prepare_work": 1000000,
    "logical_allocation": 1000000,
    "syntax_depth": 64
  },
  "evaluate": {
    "canonical_input_bytes": 4096,
    "eval_work": 10000,
    "logical_allocation": 1000000,
    "semantic_frames": 1000,
    "traversal_depth": 256,
    "output_bytes": 4096,
    "diagnostic_bytes": 4096,
    "transcript_bytes": 4096,
    "transcript_events": 100,
    "result_bytes": 4096
  }
}

Сохраните второй файл лимитов как rules/semantic-limit-probe.limits.json.

JSON
{
  "schema": "topaz.lispex-embed-limits/v1",
  "prepare": {
    "raw_source_bytes": 4096,
    "prepare_work": 1000000,
    "logical_allocation": 1000000,
    "syntax_depth": 64
  },
  "evaluate": {
    "canonical_input_bytes": 4096,
    "eval_work": 1,
    "logical_allocation": 1000000,
    "semantic_frames": 1000,
    "traversal_depth": 256,
    "output_bytes": 4096,
    "diagnostic_bytes": 4096,
    "transcript_bytes": 4096,
    "transcript_events": 100,
    "result_bytes": 4096
  }
}

Во втором файле eval_work равен 1. Этого недостаточно для завершения правила. Сохраните все поля обоих файлов. Значения можно уменьшать, но добавление или удаление полей делает документ недопустимым.

prepare_work учитывает работу при подготовке правила, а eval_work при его вычислении. Одинаковые правило, вход и настройки вычислителя расходуют одинаковое число единиц работы. Прошедшее время ограничивается отдельно.

Задайте квоты приложения

Сохраните этот файл как rules/application.quotas.json.

JSON
{
  "schema": "topaz.lispex-application-quotas/v1",
  "concurrent_evaluations": 2,
  "queued_evaluations": 2,
  "total_evaluations": 64,
  "aggregate_input_bytes": 262144,
  "aggregate_result_bytes": 262144,
  "aggregate_output_bytes": 262144,
  "aggregate_transcript_bytes": 262144,
  "aggregate_safety_fuel": 64000000000,
  "prepared_bytes": 3000000,
  "wall_millis": 5000
}

Квоты действуют на всё приложение. Этот файл разрешает два одновременных вычисления, два ожидающих вызова и 64 вычисления в сумме. wall_millis отводит на вычисление 5 000 миллисекунд. Поля в байтах ограничивают суммарный объём входов, результатов, вывода и журналов выполнения.

Объявите пакет

Сохраните этот файл как topaz.toml.

TOML
[package]
name = "complete_lispex_decision_application"
version = "0.1.0"
language = "5.20"
entry = "src/main.tpz"

[build]
target = "native"
deterministic = true

[dependencies]
std = "5.20"

[lispex]
profile = "lispex/r7rs-rule-current-profile-bounded/1"
application = "topaz/lispex-decision-application/2"
application_quotas = "rules/application.quotas.json"

[[lispex.rule]]
name = "approve"
source = "rules/approve.lspx"
limits = "rules/approve.limits.json"

[[lispex.rule]]
name = "semantic_limit_probe"
source = "rules/approve.lspx"
limits = "rules/semantic-limit-probe.limits.json"

Оба имени правила используют один исходный файл. approve получает обычные лимиты, а semantic_limit_probe получает лимит работы 1.

Для этого контракта приложения оставьте language и std равными 5.20. Сохраните идентификаторы profile и application точно как в примере. Профиль задаёт поддерживаемые возможности языка и правила выполнения. Слово bounded входит в идентификатор профиля и обозначает его лимиты ресурсов.

Каждая запись [[lispex.rule]] задаёт name и пути source и limits. Топаз предоставляет объявленные имена как функции в std.lispex.rules. Например, approve вызывается через rules.approve().

Вызовите правило

Сохраните эту программу целиком в src/main.tpz.

TOPAZ
import std.lispex { canonicalBytes, defaultLimits, evaluate, valueFromCanonical }
import std.lispex.rules as rules

export function main(аргументы: Array<string>, стандартныйВвод: string) -> Result<int, string> {
    let байты = Bytes.fromArray([0])?
    let вход = match valueFromCanonical(байты) {
        case Ok(значение) => значение
        case Err(_) => return Err("invalid input")
    }
    let сценарий = if аргументы.length == 0 { "approve" } else { аргументы[0] }
    let правило = if сценарий == "approve" {
        rules.approve()
    } else if сценарий == "semantic-limit" {
        rules.semantic_limit_probe()
    } else {
        return Err("use approve or semantic-limit")
    }
    match evaluate(правило, вход, defaultLimits(правило)) {
        case Ok(исход) => match исход {
            case Complete(значение) => print("complete:{canonicalBytes(значение).toHex()}")
            case LimitExhaustion(причина) => print("limit:{причина}")
            case SemanticFailure(причина) => return Err("rule failed: {причина}")
            case RequestRefusal(причина) => return Err("request refused: {причина}")
        }
        case Err(ошибка) => match ошибка {
            case DeadlineExceeded => return Err("application deadline exceeded")
            case TotalEvaluationsExceeded => return Err("application evaluation quota exceeded")
            case _ => return Err("operational fault")
        }
    }
    Ok(0)
}

Bytes.fromArray([0]) создаёт однобайтовое представление пустого значения Лиспекса, nil. valueFromCanonical проверяет соответствие байтов общему формату значений lispex.embed-value/v1. Программа передаёт это значение как вход.

defaultLimits читает объявленные лимиты вычисления для правила. evaluate возвращает результат LispexSettlement или операционную ошибку. Результат описывает завершение, ошибку правила, отказ в запросе или исчерпание ресурсов. Программа обрабатывает исчерпание работы как результат, а превышение квоты или времени как ошибку.

Создайте файл блокировки, проверьте и запустите пакет

Выполните команды из каталога с topaz.toml.

BASH
topaz lock --root .
topaz check --root . --locked
topaz run --root . --locked

lock записывает topaz.lock и подготавливает правила в .topaz/lispex. check завершается с кодом 0 без вывода. run печатает следующую строку и завершается с кодом 0.

Вывод
complete:090000000000000001080000000000000005616c6c6f77

Программа печатает канонические байты результата в шестнадцатеричном виде. Они кодируют список со строкой "allow". Complete означает, что вычислитель завершил правило.

Теперь выберите правило с меньшим лимитом работы.

BASH
topaz run --root . --locked -- semantic-limit
Вывод
limit:eval_work

Программа завершается с кодом 0, поскольку обработала LimitExhaustion. Правило остановилось на лимите eval_work. Чтобы оно завершилось, измените это поле в rules/semantic-limit-probe.limits.json с 1 на 10000. Повторите команды блокировки, проверки и запуска. Вы получите строку complete, показанную выше.

Для следующих примеров верните eval_work значение 1 в этом файле и снова выполните topaz lock --root .. Файл блокировки обновится, а semantic-limit снова выведет limit:eval_work.

Проверьте topaz.lock перед коммитом. Он фиксирует вычислитель, профиль, кодирование, лимиты, квоты, исходники правил, подготовленные правила и их дайджесты. Дайджест определяет точные байты. Эти значения должна записывать команда topaz lock.

После изменения манифеста, правил, лимитов, квот, вычислителя или профиля обновите файл блокировки. Команды с --locked отклоняют несовпадения. Подробнее о блокировке читайте в разделе Пакеты и распространение, об установке в разделе Состояние инструментария.

Сохраните и проверьте запись вычисления

Для сохранения записи вычисления используйте evaluateWithEvidence. Для подходящих детерминированных исходов функция возвращает артефакт потребителя, запись, созданную вызывающим приложением.

ФункцияНазначение
consumerArtifactBytesПреобразовать запись в байты для хранения
consumerArtifactFromBytesПрочитать сохранённые байты и проверить формат
inspectConsumerArtifactПрочитать метаданные и идентификаторы без запуска правила
verifyConsumerArtifactПроверить структуру, дайджесты и связь с параметрами вычисления
portableCoreBytesИзвлечь вложенную запись в формате Лиспекса, если она есть
freshReplayВыполнить записанные правило и вход с записанными лимитами в новом экземпляре и сравнить полученный артефакт

Запись и её ядро в формате Лиспекса создаются вызывающей стороной без подписи и аутентификации. Они не указывают издателя и не дают одобрения поставщика, полномочий подписи, допуска компонента или разрешения на внешние действия. Проверяйте содержимое записи и разрешения на внешние действия отдельно.

Локальный отказ в запросе, отмена, переполненная очередь, защитная остановка и сбой движка не создают переносимого ядра. freshReplay завершается успешно, когда новый артефакт совпадает с сохранённым.

Поддерживаемый пример docs/samples/guides/lispex-application/first-call содержит шесть файлов выше. Пример в родительском каталоге также проверяет повторные вычисления, хранение и проверку записей, повторное выполнение, изоляцию состояния и общую квоту. Его сценарий all завершается после отказа в 65-м вызове. Программа первого вызова на этой странице принимает approve и semantic-limit.

Соберите нативный продукт

Установив инструменты сборки Rust, создайте релизную сборку вне каталога пакета.

BASH
topaz build --root . --locked --release --out-dir ../complete-product

В Linux или macOS запустите полученную программу.

BASH
../complete-product/target/release/program
../complete-product/target/release/program semantic-limit

В Windows используйте следующие команды.

POWERSHELL
..\complete-product\target\release\program.exe
..\complete-product\target\release\program.exe semantic-limit

Первая команда печатает строку complete, вторая печатает limit:eval_work. Обе завершаются с кодом 0. Используйте исполняемый файл в той ОС и на той архитектуре, для которых он собран.

Выберите среду выполнения

МаршрутПоведение
interpreterЗапускает приложение с файлом блокировки через topaz run
nativeВыполняется на поддерживаемых нативных релизных платформах
raw-web и worker-webОтклоняются до записи выходных файлов
no-capabilityОтклоняется до выполнения или записи выходных файлов
mcp-empty-component-setОтклоняется до выполнения

Нативные релизные платформы включают Windows x64, Linux x64 и arm64, macOS x64 и arm64. Неподдерживаемый маршрут завершается ошибкой без перехода к другой среде выполнения.

Существующие пакеты Топаза 5.18 используют профиль совместимости embedded-core со своими идентификаторами вычислителя, профиля, контракта и подготовленных правил. Приложение выше использует lispex/r7rs-rule-current-profile-bounded/1. Выбор одного профиля не подменяет его другим.

Связанные разделы