В течение последних шести месяцев сайт, на котором вы находитесь отстаивал один тезис: автономным AI-агентам потребуется программируемые деньги — ограниченный кредит, машиночитаемые условия, проверка работы, квитанции расчетов. Манифест агент-экономики представил доказательства. Архитектурная страница описала четыре примитива. Блог объяснил, почему агенты не могут использовать Stripe.
Это была теория. На этой неделе сайт сам становится работающей демонстрацией.
Sage — это чат-виджет в нижнем правом углу каждой страницы. Спросите у него что-нибудь существенное об Ergo, агент-экономике или Accord. Бесплатный уровень — это Claude Haiku 4.5 над индексированным корпусом документации. Спросите /code или что-нибудь, что срабатывает при проверке премиума, и Sage вернет HTTP 402 с предложением: 0.001 testnet ERG, оплачиваемых как Accord Note, привязанное к хешу задачи. Оплатите. Адаптер rail-сервиса Sage проверяет Note в цепи, затем Claude Sonnet 4.6 потоково отправляет ответ. Каждый платный оборот становится открытой квитанцией на /r/sage/<box_id> с разметкой Schema.org Action, так что поисковые системы и AI-движки могут индексировать расчеты.
Этот пост — журнал разработки. Что это делает, что это заняло, три ошибки, которые потребовали часов работы, и что честно не готово.
Что такое Sage и что он делает
Sage — это одноклиентский конкьерж агент-экономики:
- Бесплатный уровень — Haiku 4.5 с BM25 поиском по индексированной документации и блогу Ergo. ~250-словные ответы. Отказывается выдумывать код, отказывается говорить о ценах, отказывается от посторонних тем. Стоит ~$0.001 за оборот на стороне Anthropic; ограничено по частоте на IP.
- Премиум-уровень — Sonnet 4.6 с более глубоким поиском (RAG_K=10 вместо 5), 2400 max_tokens вместо 800 и явное рассуждение. Ограничен вызовом 402: платная Note на Ergo testnet разблокирует один премиум-оборот.
- Квитанции — каждый платный оборот создает открытый URL с id бокса Note, tx выпуска, стоимостью, сроком действия и блоком Schema.org
Action, который могут читать AI-движки и краулеры.
Премиум-ворота срабатывают, когда вопрос пользователя совпадает с одним из: явный префикс команды /command, код-подобное намерение, глубокий исследовательский фразинг, длина свыше 400 символов или многооборотное следующее сообщение в длинной цепочке. Эвристики в src/lib/sage/payments/gate.ts. Мы смещаемся в сторону ложноотрицательных — лучше недозарядить, чем удивить первых 100 пользователей.
Четыре примитива, которые делают работу
Sage не построен на пользовательском SDK платежей. Он использует те же четыре примитива, которые определяет протокол Accord и которые отстаиваются в манифесте:
| Примитив | Что он делает в Sage |
|---|---|
| Reserve | Бокс 0.1-ERG на Ergo testnet, который поддерживает каждую Note. Одноразовая настройка. Id бокса 4af1816c… (проверяемо на обозревателе). |
| Note | Инструмент на предъявителя, выданный против Reserve. Несет 0.001 ERG, истекает через +120 блоков и имеет хеш задачи вопроса в регистре R6. |
| Acceptance Predicate | Условие траты ErgoScript, встроенное в Note: blake2b256(task_output) == R6. Заставляет погашение подтвердить правильность работы. |
| Tracker | Опционально в v0 — бесплатный уровень Sage не нуждается в этом, потому что каждая Note привязана к уникальному хешу задачи; двойное погашение обнаруживается по состоянию цепи. |
Вместе эти элементы превращают платеж в небольшой контракт на работу. Note — это не передача с прилагающейся квитанцией — это сама квитанция, со встроенным правилом погашения.
Полный жизненный цикл одного платного запроса
1. Пользователь вводит: "/code show me a Fleet SDK example"
2. Виджет POST /api/sage/chat → сервер вернул 402 с обоснованием
3. Виджет POST /api/sage/quote → сервер возвращает SageQuote:
receiver_address 3Wz1Lmu…AY28w (кошелек Sage на testnet)
reserve_box_id 4af1816c…628a4d (реальный Reserve на цепи)
task_hash 9674cd…ced33 (blake2b256 канонизированного вопроса)
price 0.001 testnet ERG
deadline +120 блоков
expires_at T+10мин (свежесть цитаты на сервере)
4. PaymentPanel отображает цитату с кнопками копирования + пошаговое руководство "как платить"
5. Кошелек покупателя (Nautilus / наш начальный CLI / совместимый кошелек)
выпускает Note с R4=reserve, R5=expiry, R6=task_hash
6. Note tx подтверждается на Ergo testnet (~2 мин)
7. Покупатель вставляет note_box_id в панель → Verify
8. Сервер POST /api/sage/verify-payment:
• rails-ergo verifyPayment получает Note из цепи
• проверяет привязку R4 reserve, R5 expiry, R6 task hash, value ≥ price
• проверено
9. Сервер возвращает токен платежа HMAC + id квитанции + (опционально) tx расчета
10. Виджет возобновляет чат с paymentToken
11. /api/sage/chat видит валидный токен → маршрут к Sonnet 4.6 + более глубокий RAG
12. Премиум-ответ потоком через SSE с значком "PREMIUM · paid"
13. Ссылка "view receipt →" указывает на /r/sage/<box_or_tx_id>
14. Страница квитанции отображает разметку Schema.org Action на сервере
Двенадцать дискретных шагов. Две транзакции на цепи (выпуск Note + опциональный расчет). Один вызов LLM. Одна открытая страница квитанции, индексируемая каждой поисковой системой и AI-движком в мире.
Поверхность кода — что мы действительно построили
Все это помещается в небольшой набор файлов. Большая часть сложности находится в двух местах: адаптер rail-обертка (потому что API обозревателя testnet имеет особенности) и абстракция кошелька (потому что мы не помещаем ключ подписи на Vercel).
src/lib/sage/
├── retrieve.ts BM25 поиск по индексу документов
├── rate-limit.ts Скользящее окно на IP
├── payments/
│ ├── agreement.ts buildSageQuote() + canonicalizeQuestion()
│ ├── gate.ts Эвристики decidePremium()
│ ├── note-ops.ts Обертка ErgoNoteOps, нормализирующая
│ │ формат объекта регистров обозревателя v1
│ ├── token.ts Токен платежа HMAC-SHA256, TTL 30 мин,
│ │ привязан к хешу вопроса, так что украденный
│ │ токен не может разблокировать другой вопрос
│ ├── verify.ts rails-ergo verifyPayment + settle
│ ├── wallet.ts getSageAgent(): одноэкземплярный ErgoAgentPay,
│ │ signer = удаленный URL или локальное seed (или
│ │ режим verify-only, если ничего не настроено)
│ └── types.ts SageQuote, PaymentProof, и др.
└── explorer/
└── fetch-tx.ts Fetcher обозревателя testnet с особенностями v1
src/app/api/sage/
├── chat/route.ts Endpoint потокового SSE, aware премиума
├── quote/route.ts POST { question } → SageQuote | { premium: false }
└── verify-payment/route.ts POST { quote, question, noteBoxId } → token
src/components/sage/
├── SageWidget.tsx Плавающий чат, оркестрирует поток платежа
├── PaymentPanel.tsx 402 → quote → input → verify
└── MessageBody.tsx Минимальный markdown-рендер
src/app/[locale]/r/sage/[id]/
└── page.tsx Открытая квитанция, Schema.org Action
scripts/sage-signer/
├── bootstrap.mjs --reserve, --issue-note, --balance, --env-out
└── signer.mjs Автономный HTTP подписант, Fleet SDK Prover
Всего кода Sage: ~2500 строк в чате, библиотеке платежей, виджете, странице квитанции и начальном CLI. Начальный CLI — это то, что создало Reserve на цепи и что мы используем для выпуска самопроверяющихся Note — это также полезный справочник для любого другого оплачиваемого MCP-сервиса, который хочет отправиться на Ergo без написания проводки подписи с нуля.
Три реальные проблемы, на которые мы наткнулись
1. Endpoint /boxes/{id} обозревателя testnet молча поломан для неиспользованных боксов
verifyPayment Sage вызывает ergo-agent-pay.checkNote(boxId). Это попадает на обозреватель v1 по адресу /boxes/{box_id}. Для потраченных выходов это работает. Для неиспользованных боксов — случай, который действительно важен, поскольку мы проверяем только что выданную Note, которая еще не погашена — это 404. Тот же бокс появляется в /boxes/unspent/byAddress/{addr} идеально.
Страница квитанции столкнулась с той же стеной.
Мы обходим это резервной копией в fetch-tx.ts: если автономный поиск не срабатывает, сканируем список неиспользованных кошелька и находим совпадение. Это некрасиво. Это правильный шаг до тех пор, пока мы не подадим вышестоящее исправление или полностью не уйдем от endpoint v1.
2. Обозреватель v1 возвращает регистры как объекты, а не как hex-строки
ergo-agent-pay@0.3.0 типизирует additionalRegisters как Record<string, string> и вызывает regs.R5.slice(2) для удаления префикса sigma-типа. Обозреватель testnet v1 фактически возвращает каждый регистр как { serializedValue, sigmaType, renderedValue }. Вызов .slice() падает с e.slice is not a function и окружающий verifyPayment rails-ergo отображает ошибку на NOTE_NOT_FOUND.
Мы оборачиваем агента Proxy в note-ops.ts, который перехватывает network.getBox и сглаживает любые объектно-подобные регистры в их hex-строку serializedValue. Замена drop-in ErgoNoteOps. ~30 строк включая импорты. Как только ergo-agent-pay@0.4 принимает обе формы вышестоящим, обертка уходит.
3. Мы отправляли неправильный task_output на rail
Это потребовало целый день. verifyPayment rails-ergo вычисляет blake2b256(task_output) и сравнивает с R6 Note. Note была выдана с R6 = blake2b256(canonicalize(question)). Итак, task_output должен равняться canonicalize(question) — сырым байтам, чей хеш совпадает с R6.
Мы отправляли hashQuestionForToken(question) — совершенно другой хеш HMAC, используемый в другом месте для привязки токена. Результат: TASK_HASH_MISMATCH на каждом платном обороте.
Исправление — одна строка в verify-payment/route.ts. Урок — это комментарий, который мы оставили рядом: когда два слоя оба содержат хеширование, назовите переменные для того, что они хешируют, а не для того, как они называются в протоколе.
Что означает "режим только-для-проверки" и почему мы его отправили
Sage в настоящее время работает в режиме только-для-проверки: шаг verifyPayment запускается на каждом платном обороте (только-чтение — подпись не нужна), но вторая транзакция на цепи (та, которая погашает Note и перемещает 0.001 ERG в кошелек Sage) отложена.
Это намеренно, не баг. Две причины:
- Ключ подписи находится вне Vercel. Помещение приватного ключа кошелька продавца в переменную окружения serverless — плохая операционная гигиена. Компрометация
ANTHROPIC_API_KEYне должна опустошать кошелек. Итак, подписание погашения происходит через локальный HTTP-подписант (scripts/sage-signer/signer.mjs), который оператор запускает на своей машине и открывает черезcloudflared tunnel. Sage отправляет unsigned tx ему; подписант проверяет в зависимости от лимита расходов на tx + whitelist получателей перед подписью. - Note автоматически возвращается при истечении. Если Sage не погасит Note до истечения срока
+120 блоков, условие траты Note вернет средства обратно в reserve покупателя. Итак, отложенное погашение не трапит деньги — в худшем случае это бесплатный премиум-ответ, что в порядке на фазе bring-up testnet.
Квитанции в режиме только-для-проверки показывают желтый значок verified · pending redemption. Когда подписант подключен и приходит следующий платный запрос, как этот оборот, так и любые непогашенные прошлые Note переключаются на зеленый вид settled автоматически — страница обновляется сама, когда состояние цепи меняется.
Твит с объявлением честно скажет "verified, settlement pending in this run". Проводка подписанта — это одноночная задача; мы не хотим переусложнять.
Что дальше
- Settler онлайн. Туннель подписанта, установить
SAGE_SIGNER_URLна Vercel, видеть, как следующая платная Note переключается из pending в settled с реальной tx погашения на цепи. - Conformance Accord. Запустить
@accord-protocol/conformance --target https://www.ergoblockchain.org/api/sage/quote, подписать результат ключом ed25519, опубликовать подписанный артефакт, обновить запись Sage в реестре с хешем conformance. Sage становится первым L4-сертифицированным провайдером в открытом реестре Accord. - Реестр агентов на сайте.
/ergo-watch/agentsбудет получать реестр Accord и отображать каждого провайдера с их возможностями, rails и последними квитанциями. Страница профиля Sage становится одной из многих. - Полоса активности живых агентов на главной. Последние платные квитанции по реестру, прокручивающиеся под статистикой сети. Сайт переходит от "мы описываем агент-экономику" к "вот что она делает прямо сейчас."
- Многоклиентский Sage. Извлечь виджет в отдельный npm-пакет
@accord/sage-widget. Любой сайт документации может вставить<script src="…/sage.js" data-rag="…" data-receiver="9f…">и иметь своего оплачиваемого конкьержа со своим кошельком Ergo. Множитель распределения — каждое вложение — это новый адрес получателя Ergo на новом домене.
Попробуйте
Откройте ergoblockchain.org. В нижнем правом углу кнопка Ask Sage. Бесплатные вопросы остаются бесплатными. Спросите /code или что-нибудь существенное — панель платежа проведет вас через выпуск Note testnet. Используйте кошелек testnet (Nautilus — стандарт или запустите node scripts/sage-signer/bootstrap.mjs --issue-note из клона репо) и 0.001 testnet ERG (кран дает ~1 ERG за запрос).
Исходник: репо ergoblockchain.org отправляет все описанное выше. Паттерн Accord, который использует Sage — это каноническая проводка покупателя/продавца на examples/16-paid-mcp-ergo-testnet.
Манифест и работающий агент теперь — это одно и то же. В этом вся суть.
Часто задаваемые вопросы
Почему testnet, а не mainnet?
Две причины. Во-первых, контракт погашения использует кошелек продавца Sage как условие траты без аудита. Mainnet-запись неаудированного ErgoScript никогда не должна происходить — шлюзы безопасности production в ergo-agent-pay активно их блокируют. Во-вторых, весь стек Accord находится на v0.4 и манифесты conformance все еще в draft-pre-audit. Mainnet на дорожной карте; сегодняшнее свидетельство — testnet.
Чем это отличается от x402 или Stripe Agentic Commerce?
x402 — это протокол платежа-требуемого — паттерн "402 challenge" одинаков. Отличие в rail. x402 обычно оборачивает платеж картой / Stripe и рассматривает цепь как слой отчетности. Accord размещает правило принятия работы в самом условии траты: Note не может быть погашена, если продавец не доставил работу, которая хешируется в хеш соглашения задачи. Stripe Agentic Commerce — зеркало покупателя — агенты, держащие карты. Полезно для покупок, санкционированных человеком. Другой слой от расчета агент-к-агенту.
Работает ли это без подписанта?
Да. Это режим только-для-проверки, описанный выше. Премиум-ответ течет на каждую успешную проверку; только вторая транзакция на цепи (погашение Sage) отложена. Квитанции показывают "settlement pending" до тех пор, пока подписант не онлайн.
Могу ли я запустить свой Sage?
Скоро, правильно — это многоклиентская работа в разделе "Что дальше". Сегодня вы можете клонировать репо, настроить свой кошелек через scripts/sage-signer/bootstrap.mjs и запустить экземпляр Sage из своего развертывания. Документация в docs/sage-provisioning.md.
Куда идут расходы Anthropic API?
API-ключ Anthropic находится в Vercel env. Мы платим за трафик бесплатного уровня. Премиум-обороты восстанавливают стоимость LLM через Note (0.001 ERG ≈ $0.0007 по testnet "ставкам", если вообразить их реальными). Экономика ценообразования mainnet открыта — отправка v0 — это точка доказательства, а не модель маржи.
