Skip to main content

Почему контроль бюджета важен

ИИ-агент, вызывающий платные API в цикле, может быстро накопить значительные расходы. Контроль бюджета позволяет:
  • Ограничить общие расходы за сессию
  • Установить лимиты по доменам (например, не более 100 sats/сессию на api.weather.com)
  • Получать обратный вызов перед каждым платежом
  • Получить полный отчёт о расходах в любое время

Глобальный бюджет

import { L402Client, BlinkWallet } from "l402-kit";

const client = new L402Client({
  wallet: new BlinkWallet(process.env.BLINK_API_KEY!, process.env.BLINK_WALLET_ID!),
  budgetSats: 500, // max 500 sats total this session
});
Когда ответ 402 содержит поле priceSats и его значение превышает оставшийся бюджет, клиент выбрасывает BudgetExceededError до совершения платежа — никакие satoshi не тратятся.

Бюджет по доменам

const client = new L402Client({
  wallet,
  budgetSats: 2000,
  budgetPerDomain: {
    "api.weather.com": 100,
    "api.finance.com": 500,
  },
});
Лимиты по доменам проверяются независимо от глобального лимита — оба условия должны выполняться, чтобы платёж был совершён.

Обратные вызовы

const client = new L402Client({
  wallet,
  budgetSats: 1000,
  onSpend: (sats, url) => {
    console.log(`✓ Paid ${sats} sats → ${url}`);
    // log to your telemetry, update a dashboard, etc.
  },
  onBudgetExceeded: (url, sats) => {
    console.warn(`✗ Blocked: ${sats} sats requested by ${url} — budget exhausted`);
    // alert, notify Slack, etc.
  },
});
onBudgetExceeded / on_budget_exceeded вызывается непосредственно перед выбросом BudgetExceededError — удобно для логирования или оповещений.

Отчёт о расходах

const report = client.spendingReport();

if (report) {
  console.log(`Total spent: ${report.total} sats`);
  console.log(`Remaining:   ${report.remaining} sats`);
  console.log("By domain:", report.byDomain);
  // { "api.weather.com": 42, "api.finance.com": 105 }

  for (const tx of report.transactions) {
    console.log(`  ${tx.ts}  ${tx.sats} sats  ${tx.url}`);
  }
}
spendingReport() возвращает null / None, если бюджет не настроен.

Обработка BudgetExceededError

import { BudgetExceededError } from "l402-kit";

try {
  const res = await client.fetch("https://api.example.com/premium");
} catch (err) {
  if (err instanceof BudgetExceededError) {
    console.log(`Need ${err.required} sats, only ${err.remaining} remaining`);
    // gracefully degrade — return cached data, skip this step, etc.
  }
}

Замечания о параллельном выполнении

Не используйте один экземпляр L402Client в параллельных вызовах Promise.all, если важны лимиты бюджета.BudgetTracker.check() и record() разделены операцией await (платёж через Lightning Network). Два параллельных вызова client.fetch() к разным эндпоинтам могут оба пройти проверку бюджета до того, как хоть один из них зафиксирует расход — это означает, что суммарные затраты могут временно превысить лимит бюджета на один платёж.Безопасный паттерн — последовательные вызовы:
for (const url of urls) {
  const res = await client.fetch(url); // awaited one at a time
}
Рискованный паттерн — параллельные вызовы:
// Both may pass budget.check() before either calls budget.record()
const results = await Promise.all(urls.map(url => client.fetch(url)));
Решение для параллельных задач: устанавливайте budgetSats с запасом (например, 80% от реального лимита), чтобы компенсировать перерасход от одного параллельного платежа. Для строгого соблюдения лимитов обрабатывайте вызовы последовательно.

Полный справочник параметров

ПараметрTypeScriptPythonПо умолчаниюОписание
Глобальный бюджетbudgetSatsbudget_satsбез ограниченийМаксимум sats за сессию
По доменамbudgetPerDomainbudget_per_domain{}Карта домен → максимум sats
Хук расходаonSpendon_spendВызывается после каждого платежа
Хук превышенияonBudgetExceededon_budget_exceededВызывается перед выбросом исключения