Embeddable widgets for Sage — the agent-economy concierge on ergoblockchain.org. Use the read-only activity feed, or embed the paid Sage chat flow with quote, manual Note verification, streaming answer, and receipt link.
Why this matters: Sage settles real paid AI queries on Ergo testnet. The feed makes the "agent-economy" thesis visibly provable wherever you embed it — not a marketing claim, a list of public on-chain receipts that update live.
npm install @ergoblockchain/sage-widget
# or
pnpm add @ergoblockchain/sage-widget
# or
yarn add @ergoblockchain/sage-widgetreact and react-dom are optional peer deps — only required if you import from /react.
import { SageActivityFeed } from "@ergoblockchain/sage-widget/react"
export function Footer() {
return <SageActivityFeed limit={5} refreshMs={60_000} />
}The component renders into your DOM (no iframe), styles itself with inline styles to avoid host-CSS conflicts, and polls /api/sage/activity on the host you point it at.
import { SagePaymentWidget } from "@ergoblockchain/sage-widget/react"
export function PaidSageBox() {
return (
<SagePaymentWidget
tenant={{ id: "my-site", label: "My Ergo app" }}
paymentInstructions={{
helperText: "Issue the quoted Accord Note from your testnet wallet, then paste the Note box id.",
walletUrl: "https://www.ergoblockchain.org/build/agent-payments",
}}
onQuote={(quote) => console.log("Sage quote", quote)}
onReceipt={(receipt) => console.log("Sage receipt", receipt.receiptUrl)}
onReceiptBundle={(bundle) => console.log("Receipt completeness", bundle.completeness)}
/>
)
}The paid widget calls /api/sage/quote, shows the Accord Note payment fields, accepts a noteBoxId, calls /api/sage/verify-payment, streams /api/sage/chat, then surfaces the receipt link from /api/sage/receipt/<id>.
import { mountSageFeed } from "@ergoblockchain/sage-widget/vanilla"
const handle = mountSageFeed(document.getElementById("sage-feed")!, {
limit: 5,
refreshMs: 60_000,
})
// later, if you want to tear down:
handle.destroy()Or use the canonical hosted CDN drop-in (no install needed):
<div id="sage-feed"></div>
<script src="https://www.ergoblockchain.org/agents.js"
data-target="#sage-feed"
data-height="320"
async></script>That last form is an iframe variant served straight from ergoblockchain.org — total style isolation, zero install. Use the npm package when you want the markup inline (themable, accessibility-friendly, tree-shakeable).
import { mountSagePaymentWidget } from "@ergoblockchain/sage-widget/vanilla"
const handle = mountSagePaymentWidget(document.getElementById("sage-chat")!, {
tenant: { id: "docs-footer", label: "Docs footer" },
})
// You can also start a question programmatically:
await handle.send("/research explain Ergo Notes")If you want to render your own UI over Sage's API and skip the bundled components:
import {
fetchSageActivity,
fetchSageQuote,
streamSageChat,
verifySagePayment,
type SageActivityEvent,
type SageActivityResponse,
} from "@ergoblockchain/sage-widget"
const data: SageActivityResponse = await fetchSageActivity({ limit: 10 })
const settlements = data.events.filter((e) => e.type === "settlement")<SageActivityFeed>
{({ response, loading }) => (
<MyOwnDesign events={response?.events ?? []} loading={loading} />
)}
</SageActivityFeed>| Prop | Type | Default | Notes |
|---|---|---|---|
apiBase |
string |
"https://www.ergoblockchain.org" |
Override if you run your own Sage deployment behind a custom domain. |
limit |
number |
5 |
Max 25. |
refreshMs |
number |
60000 |
Poll interval. Set to 0 to fetch once on mount and never refresh. |
onUpdate |
(r: SageActivityResponse) => void |
— | Fired after every successful poll. |
onError |
(err: unknown) => void |
console.warn |
Fired on fetch failure. |
className |
string |
— | Applied to the root container (React only). |
style |
CSSProperties |
— | Inline style merged onto the root container (React only). |
children |
render-prop | — | Pass a function for full UI control; the component will skip the default markup. |
SagePaymentWidget also accepts:
| Prop | Type | Notes |
|---|---|---|
tenant |
{ id?: string; label?: string; headers?: Record<string,string> } |
Stable embed metadata and optional request headers. |
initialMessages |
SageChatMessage[] |
Preloaded chat context. |
title |
string |
Widget heading. |
placeholder |
string |
Input placeholder. |
paymentInstructions |
{ helperText?: string; walletUrl?: string; noteBoxLabel?: string } |
Host-specific payment copy and guide link. |
onMessage |
(message, messages) => void |
Fired when the widget appends a chat message. |
onQuote |
(quote) => void |
Fired after Sage returns a premium quote. |
onReceipt |
(receipt) => void |
Fired after payment verifies and a receipt URL exists. |
onReceiptBundle |
(bundle) => void |
Fired after the widget fetches /api/sage/receipt/<id>. |
onTier |
("free" | "premium") => void |
Fired when the stream reports model tier. |
onPhase |
(phase) => void |
Fired on widget phase changes: idle, quoting, payment_required, verifying, streaming, error. |
onStatus |
(status) => void |
Fired with a compact snapshot of phase, tier, quote, receipt, receipt bundle, and error. |
Each event in response.events is a typed object:
{
txId: string // 64-char hex
blockHeight: number
timestamp: number // ms epoch
type: "settlement" | "issuance" | "transfer"
inflowNanoErg: number // sum of outputs to Sage wallet
paymentNanoErg?: number // value of redeemed Note (settlements only)
noteBoxId?: string // first Note-shape input
}For settlements, use paymentNanoErg (the value of the consumed Note) for "amount paid" display. inflowNanoErg includes change boxes when buyer and seller share an address in test setups.
- Live demo: ergoblockchain.org/agent-economy#sage-activity
- API directly:
/api/sage/activity— JSON, no auth, cached 30s - Receipt format:
/r/sage/<settlement_tx_id> - Accord Protocol: github.com/accord-protocol/accord-protocol
- Sage in the registry: accord-protocol/registry/providers/sage.json
- v0.1.x — read-only activity feed (React + vanilla + types).
- v0.2 (current source) —
<SagePaymentWidget />paid chat with quote, manual Note verify, streaming answer, receipt link, tenant config. - v0.3 — generic
<AccordActivityFeed providerId="..." />that works for any provider in the registry, not just Sage.
MIT