From 5bf33b4535df727bf81bdf107b5449bc1b8c4881 Mon Sep 17 00:00:00 2001 From: liander-ai <258801505+liander-ai@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:42:27 +0800 Subject: [PATCH] feat: add Beaver Knight action provider Adds a read-only action provider for Beaver Knight, a trust bureau for autonomous trading agents that rates agents and vaults on realised on-chain performance and attests ratings on Base via EAS from a keyless (canister-controlled) address. Actions: - rate_wallet: counterparty check by address (EVM or Solana). An unrated address is found:false, which the tool description states is an absence of evidence, not a pass; an upstream failure is surfaced as "could not check", distinct from unrated. - get_vault_rankings: Hyperliquid / ERC-4626 vaults ranked by score, return, Sharpe, Sortino, Calmar, drawdown, TVL or decision count, with a significance-test flag per vault. - get_integrity_report: full report for one record incl. findings/limits (kept separate), factor breakdown, basis, and on-chain attestation. Public API, no keys, network-agnostic. Unit tests mock fetch and cover the miss/error distinctions. README and changeset included. --- .../beaver-knight-action-provider.md | 5 + .../action-providers/beaverknight/README.md | 93 +++++++++ .../beaverknightActionProvider.test.ts | 190 ++++++++++++++++++ .../beaverknightActionProvider.ts | 180 +++++++++++++++++ .../beaverknight/constants.ts | 18 ++ .../action-providers/beaverknight/index.ts | 1 + .../action-providers/beaverknight/schemas.ts | 62 ++++++ .../agentkit/src/action-providers/index.ts | 1 + 8 files changed, 550 insertions(+) create mode 100644 typescript/.changeset/beaver-knight-action-provider.md create mode 100644 typescript/agentkit/src/action-providers/beaverknight/README.md create mode 100644 typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.test.ts create mode 100644 typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.ts create mode 100644 typescript/agentkit/src/action-providers/beaverknight/constants.ts create mode 100644 typescript/agentkit/src/action-providers/beaverknight/index.ts create mode 100644 typescript/agentkit/src/action-providers/beaverknight/schemas.ts diff --git a/typescript/.changeset/beaver-knight-action-provider.md b/typescript/.changeset/beaver-knight-action-provider.md new file mode 100644 index 000000000..30998b39b --- /dev/null +++ b/typescript/.changeset/beaver-knight-action-provider.md @@ -0,0 +1,5 @@ +--- +"@coinbase/agentkit": patch +--- + +Added Beaver Knight action provider: a read-only counterparty check (rate_wallet), ranked trading vaults with significance-tested figures (get_vault_rankings), and full Integrity Reports with on-chain EAS attestations (get_integrity_report) from the Beaver Knight trust bureau. diff --git a/typescript/agentkit/src/action-providers/beaverknight/README.md b/typescript/agentkit/src/action-providers/beaverknight/README.md new file mode 100644 index 000000000..95d436b30 --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/README.md @@ -0,0 +1,93 @@ +# Beaver Knight Action Provider + +This directory contains the **Beaver Knight** action provider. [Beaver Knight](https://www.beaverknight.com) is a trust bureau for autonomous trading agents: it rates agents and vaults on what they actually did with real money on chain (realised P&L read from the venue itself, with a statistical-significance gate), publishes the rating whether or not the subject asked, and attests ratings on Base via [EAS](https://attest.org) from a canister-controlled address that has no private key. + +The actions are public, unauthenticated, read-only, and network-agnostic. They give an agent a counterparty check before it pays, delegates to, or copies another agent or vault. + +## Directory Structure + +``` +beaverknight/ +├── beaverknightActionProvider.ts # Main provider +├── beaverknightActionProvider.test.ts # Tests +├── constants.ts # Base URL, sort keys +├── index.ts # Main exports +├── README.md # Documentation +└── schemas.ts # Action schemas +``` + +## Actions + +- `rate_wallet`: Check an address (execution wallet, owner wallet or token; EVM or Solana) against the bureau. + + - Returns score (0-99), level (`strong | solid | fair | unproven | flag`), verdict, and two **separate** lists: `findings` (about the subject) and `limits` (about the bureau's own reach). + - An unrated address returns `found: false`. That is an absence of evidence, **not** a clean bill of health. + +- `get_vault_rankings`: The vaults on the board (Hyperliquid trading vaults, ERC-4626 yield vaults), ranked. + + - Sort by `score` (default), `return`, `sharpe`, `sortino`, `calmar`, `drawdown`, `tvl` or `decisions`; filter by level, venue, minimum TVL. + - Each vault carries the figures an allocator compares on, including the t-statistic of the edge and whether it clears the significance gate. A `null` figure means unmeasured, never zero. + +- `get_integrity_report`: The full Integrity Report for one record (board id, Virtuals ACP id, or address). + - Every metric, the factor breakdown behind the score, findings and limits, disclosures, recent windows, a "basis" line describing how to re-derive every number from the venue's public API, and provenance, including the on-chain EAS attestation (UID, tx, keyless attester) when one exists. + +## Adding to an agent + +```typescript +import { AgentKit, beaverknightActionProvider } from "@coinbase/agentkit"; + +const agentKit = await AgentKit.from({ + walletProvider, + actionProviders: [beaverknightActionProvider()], +}); +``` + +An optional base URL can be passed (`beaverknightActionProvider("https://...")`) for a self-hosted or staging bureau. + +## Examples + +### Checking a counterparty + +```bash +Prompt: before I pay this agent, is 0xa1b6d8efbcb2fb750a84dbc05649fa4968034f04 rated? + +------------------- +{ + "version": 1, + "query": "0xa1b6d8efbcb2fb750a84dbc05649fa4968034f04", + "found": true, + "rating": { + "id": "hlv-pf1-a1b6d8", + "name": "PF1", + "score": 99, + "status": "Strong", + "level": "strong", + "verdict": "verified edge", + "venue": "Hyperliquid", + ... + }, + "meaning": "Verified track record, and the edge is statistically distinguishable from luck. This is the strongest verdict we issue.", + "findings": [], + "limits": [{ "label": "below size floor", "detail": null }], + ... +} +``` + +### A miss + +```bash +Prompt: is 0x0000000000000000000000000000000000000001 rated? + +------------------- +{ + "found": false, + "rating": null, + "meaning": "No Beaver Knight rating exists for this address. That is an ABSENCE OF EVIDENCE, NOT A CLEAN BILL OF HEALTH. ... Do not treat a miss as a pass." +} +``` + +## Notes + +- A tool error ("could not check", e.g. HTTP 503 from the bureau) is **not** the same as `found: false`; the provider keeps the two distinguishable. +- Ratings are a third-party census; no subject pays to be rated, and none can opt out. The bureau publishes what it could not establish alongside what it found. +- API documentation for machines: https://www.beaverknight.com/llms.txt diff --git a/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.test.ts b/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.test.ts new file mode 100644 index 000000000..fe51e2dfd --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.test.ts @@ -0,0 +1,190 @@ +import { beaverknightActionProvider } from "./beaverknightActionProvider"; + +describe("BeaverKnightActionProvider", () => { + const fetchMock = jest.fn(); + global.fetch = fetchMock; + + const provider = beaverknightActionProvider(); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + const okResponse = (body: unknown) => ({ + ok: true, + status: 200, + text: jest.fn().mockResolvedValue(JSON.stringify(body)), + }); + + describe("rateWallet", () => { + it("returns the rating payload and hits /api/rate with the wallet", async () => { + const payload = { + version: 1, + found: true, + rating: { id: "hlv-pf1-a1b6d8", score: 99, level: "strong" }, + findings: [], + limits: [{ label: "below size floor", detail: null }], + }; + fetchMock.mockResolvedValue(okResponse(payload)); + + const result = await provider.rateWallet({ + wallet: "0xa1b6d8efbcb2fb750a84dbc05649fa4968034f04", + }); + + expect(JSON.parse(result)).toEqual(payload); + expect(fetchMock).toHaveBeenCalledWith( + "https://www.beaverknight.com/api/rate?wallet=0xa1b6d8efbcb2fb750a84dbc05649fa4968034f04", + ); + }); + + it("passes a found:false miss through unchanged (a miss is not a pass)", async () => { + const payload = { + version: 1, + found: false, + rating: null, + meaning: + "No Beaver Knight rating exists for this address. That is an ABSENCE OF EVIDENCE, NOT A CLEAN BILL OF HEALTH.", + }; + fetchMock.mockResolvedValue(okResponse(payload)); + + const result = await provider.rateWallet({ + wallet: "0x0000000000000000000000000000000000000001", + }); + + expect(JSON.parse(result).found).toBe(false); + expect(result).toContain("NOT A CLEAN BILL OF HEALTH"); + }); + + it("reports an upstream failure as 'could not check', never as unrated", async () => { + fetchMock.mockResolvedValue({ + ok: false, + status: 503, + text: jest.fn().mockResolvedValue('{"error":"upstream_unavailable"}'), + }); + + const result = await provider.rateWallet({ wallet: "0xabc" }); + + expect(result).toContain("Error checking wallet"); + expect(result).toContain("503"); + expect(result).toContain('NOT "unrated"'); + }); + + it("handles network errors", async () => { + fetchMock.mockRejectedValue(new Error("Network error")); + const result = await provider.rateWallet({ wallet: "0xabc" }); + expect(result).toContain("Error checking wallet"); + expect(result).toContain("Network error"); + }); + }); + + describe("getVaultRankings", () => { + it("builds the query from the provided filters and defaults the limit", async () => { + const payload = { version: 1, vaults: [{ rank: 1, id: "hlv-pf1-a1b6d8" }], withdrawn: [] }; + fetchMock.mockResolvedValue(okResponse(payload)); + + const result = await provider.getVaultRankings({ + sort: "calmar", + level: "strong,solid", + minTvl: 250000, + venue: "Hyperliquid", + limit: null, + }); + + expect(JSON.parse(result)).toEqual(payload); + const calledUrl = fetchMock.mock.calls[0][0] as string; + expect(calledUrl.startsWith("https://www.beaverknight.com/api/vaults?")).toBe(true); + const params = new URL(calledUrl).searchParams; + expect(params.get("sort")).toBe("calmar"); + expect(params.get("level")).toBe("strong,solid"); + expect(params.get("min_tvl")).toBe("250000"); + expect(params.get("venue")).toBe("Hyperliquid"); + expect(params.get("limit")).toBe("25"); + }); + + it("omits null filters", async () => { + fetchMock.mockResolvedValue(okResponse({ vaults: [] })); + await provider.getVaultRankings({ + sort: null, + level: null, + minTvl: null, + venue: null, + limit: 10, + }); + const params = new URL(fetchMock.mock.calls[0][0] as string).searchParams; + expect(params.has("sort")).toBe(false); + expect(params.has("level")).toBe(false); + expect(params.has("min_tvl")).toBe(false); + expect(params.has("venue")).toBe(false); + expect(params.get("limit")).toBe("10"); + }); + + it("handles API errors gracefully", async () => { + fetchMock.mockResolvedValue({ + ok: false, + status: 500, + text: jest.fn().mockResolvedValue("boom"), + }); + const result = await provider.getVaultRankings({ + sort: null, + level: null, + minTvl: null, + venue: null, + limit: null, + }); + expect(result).toContain("Error fetching vault rankings"); + expect(result).toContain("500"); + }); + }); + + describe("getIntegrityReport", () => { + it("fetches the report by id and returns it unchanged", async () => { + const payload = { + found: true, + subject: { id: "hlv-pf1-a1b6d8", name: "PF1" }, + provenance: { attestation: { uid: "0xec0e" } }, + }; + fetchMock.mockResolvedValue(okResponse(payload)); + + const result = await provider.getIntegrityReport({ id: "hlv-pf1-a1b6d8" }); + + expect(JSON.parse(result)).toEqual(payload); + expect(fetchMock).toHaveBeenCalledWith( + "https://www.beaverknight.com/api/report/hlv-pf1-a1b6d8", + ); + }); + + it("URL-encodes the id", async () => { + fetchMock.mockResolvedValue(okResponse({ found: false })); + await provider.getIntegrityReport({ id: "weird id/with slash" }); + expect(fetchMock).toHaveBeenCalledWith( + "https://www.beaverknight.com/api/report/weird%20id%2Fwith%20slash", + ); + }); + + it("reports an upstream failure as 'could not check'", async () => { + fetchMock.mockResolvedValue({ + ok: false, + status: 503, + text: jest.fn().mockResolvedValue("{}"), + }); + const result = await provider.getIntegrityReport({ id: "x" }); + expect(result).toContain("Error fetching integrity report"); + expect(result).toContain('NOT "unrated"'); + }); + }); + + describe("supportsNetwork", () => { + it("is network-agnostic", () => { + expect(provider.supportsNetwork()).toBe(true); + }); + }); + + describe("custom base URL", () => { + it("uses the override and strips a trailing slash", async () => { + const custom = beaverknightActionProvider("https://example.test/"); + fetchMock.mockResolvedValue(okResponse({ found: false })); + await custom.rateWallet({ wallet: "0xabc" }); + expect(fetchMock).toHaveBeenCalledWith("https://example.test/api/rate?wallet=0xabc"); + }); + }); +}); diff --git a/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.ts b/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.ts new file mode 100644 index 000000000..4523af02f --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/beaverknightActionProvider.ts @@ -0,0 +1,180 @@ +import { z } from "zod"; +import { ActionProvider } from "../actionProvider"; +import { CreateAction } from "../actionDecorator"; +import { RateWalletSchema, GetVaultRankingsSchema, GetIntegrityReportSchema } from "./schemas"; +import { BEAVER_KNIGHT_BASE_URL } from "./constants"; + +/** + * BeaverKnightActionProvider gives an agent read access to Beaver Knight, a trust bureau for + * autonomous trading agents. The bureau rates agents and vaults on what they actually did with real + * money on chain (realised P&L read from the venue itself, with a statistical-significance gate), + * publishes the rating whether or not the subject asked, and attests ratings on Base via EAS from a + * canister-controlled address that has no private key. + * + * All actions are public, unauthenticated, read-only, and network-agnostic. + * + * Two conventions every consumer must respect: + * - An unrated address comes back as `found: false`. That is an ABSENCE OF EVIDENCE, not a clean bill + * of health. Never treat a miss as a pass. + * - `findings` (things the bureau holds against the subject) and `limits` (gaps in the bureau's own + * reach) are separate lists. Merging them turns a coverage gap into an accusation. + */ +export class BeaverKnightActionProvider extends ActionProvider { + private readonly baseUrl: string; + + /** + * Constructor for the BeaverKnightActionProvider class. + * + * @param baseUrl - Optional override of the bureau base URL (defaults to the public bureau). + */ + constructor(baseUrl: string = BEAVER_KNIGHT_BASE_URL) { + super("beaverknight", []); + this.baseUrl = baseUrl.replace(/\/+$/, ""); + } + + /** + * Looks up the Beaver Knight rating for a wallet or token address. + * + * @param args - The lookup parameters + * @returns A JSON string with the rating, or a `found:false` warning, or an error message + */ + @CreateAction({ + name: "rate_wallet", + description: `This tool checks a counterparty against the Beaver Knight trust bureau by address. +It takes the following input: +- wallet: the address to look up (EVM 0x... or Solana base58). It matches an agent's execution wallet, owner wallet or token. + +It returns JSON with: +- found: whether the bureau has a rating for this address +- rating: score (0-99), level (strong | solid | fair | unproven | flag), status, verdict, venue, size, ratedAt, stale +- meaning: what the level means, in words +- findings: statements ABOUT THE SUBJECT (e.g. lost value, high leverage, dormant) +- limits: statements ABOUT THE BUREAU'S REACH (e.g. insufficient track record) - keep these separate from findings +- links: the human report and badge + +Important notes: +- found:false is an ABSENCE OF EVIDENCE, NOT A CLEAN BILL OF HEALTH. Do not treat a miss as a pass. +- If the bureau record cannot be read the tool returns an error ("could not check"); that is NOT "unrated". +- Ratings are derived from realised on-chain performance, not from feedback or self-reports.`, + schema: RateWalletSchema, + }) + async rateWallet(args: z.infer): Promise { + try { + const url = `${this.baseUrl}/api/rate?wallet=${encodeURIComponent(args.wallet)}`; + const response = await fetch(url); + const text = await response.text(); + if (!response.ok) { + return `Error checking wallet: the bureau answered HTTP ${response.status} (this means "could not check", NOT "unrated"). ${text}`; + } + return text; + } catch (error: unknown) { + return `Error checking wallet: ${error instanceof Error ? error.message : String(error)}`; + } + } + + /** + * Returns the vaults on the Beaver Knight board, ranked. + * + * @param args - Sort and filter parameters + * @returns A JSON string with the ranked vaults, or an error message + */ + @CreateAction({ + name: "get_vault_rankings", + description: `This tool lists trading vaults (Hyperliquid vaults and ERC-4626 yield vaults) rated by the Beaver Knight bureau, ranked. +It takes the following optional inputs: +- sort: score (default) | return | sharpe | sortino | calmar | drawdown | tvl | decisions +- level: comma-separated levels to include, e.g. "strong,solid" +- minTvl: minimum TVL in USD +- venue: e.g. "Hyperliquid" +- limit: how many to return (default 25, max 100) + +Each ranked vault carries: id (use it with get_integrity_report), name, venue, address, score, level, verdict, +figures {tvlUsd, returnPct, realizedPnlUsd, winRatePct, sharpe, sortino, calmar, maxDrawdownPct, decisions, tStat, edgeIsReal, realizedSharePct, grossLeverage}, +findings, limits, and links. + +Important notes: +- A null figure means the bureau could not measure it. It never means zero. +- edgeIsReal reports whether the edge passes a statistical significance test. A high return over few decisions with edgeIsReal false is a good run, not a good vault. +- Withdrawn ratings are listed under "withdrawn" and hold no rank. +- This is the bureau's own census; nothing here is paid placement and no vault can opt out.`, + schema: GetVaultRankingsSchema, + }) + async getVaultRankings(args: z.infer): Promise { + try { + const params = new URLSearchParams(); + if (args.sort) params.set("sort", args.sort); + if (args.level) params.set("level", args.level); + if (args.minTvl !== null && args.minTvl !== undefined) + params.set("min_tvl", String(args.minTvl)); + if (args.venue) params.set("venue", args.venue); + params.set("limit", String(args.limit ?? 25)); + const url = `${this.baseUrl}/api/vaults?${params.toString()}`; + const response = await fetch(url); + const text = await response.text(); + if (!response.ok) { + return `Error fetching vault rankings: HTTP ${response.status}. ${text}`; + } + return text; + } catch (error: unknown) { + return `Error fetching vault rankings: ${error instanceof Error ? error.message : String(error)}`; + } + } + + /** + * Returns the full Integrity Report for one rated record. + * + * @param args - The record identifier + * @returns A JSON string with the report, a `found:false` warning, or an error message + */ + @CreateAction({ + name: "get_integrity_report", + description: `This tool fetches the Beaver Knight Integrity Report for one rated agent or vault. +It takes the following input: +- id: a board id (from get_vault_rankings), a Virtuals ACP agent id, or a wallet/token address + +It returns JSON with: subject, rating (score, level, verdict, headline, ratedAt, stale, dormant), meaning, +figures (for vaults), every metric with its value, the factor breakdown that produced the score, findings and +limits (kept separate), disclosures, recent performance windows, the track-record span, a "basis" line that +says how to re-derive every number from the venue's public API, and provenance. + +provenance.attestation, when present, is the on-chain EAS attestation of this rating on Base: uid, txHash, +schemaUid, and the attester address (a canister-controlled address with no private key). When it is null the +record has not been attested yet - that means "not attested", not "unrated". + +Important notes: +- found:false is an ABSENCE OF EVIDENCE, NOT A CLEAN BILL OF HEALTH. +- A retracted rating is marked retracted and should not be relied on.`, + schema: GetIntegrityReportSchema, + }) + async getIntegrityReport(args: z.infer): Promise { + try { + const url = `${this.baseUrl}/api/report/${encodeURIComponent(args.id)}`; + const response = await fetch(url); + const text = await response.text(); + if (!response.ok) { + return `Error fetching integrity report: the bureau answered HTTP ${response.status} (this means "could not check", NOT "unrated"). ${text}`; + } + return text; + } catch (error: unknown) { + return `Error fetching integrity report: ${error instanceof Error ? error.message : String(error)}`; + } + } + + /** + * Beaver Knight is a read-only HTTP API, so it is available on every network. + * + * @returns True always. + */ + supportsNetwork(): boolean { + return true; + } +} + +/** + * Creates a new instance of the Beaver Knight action provider. + * + * @param baseUrl - Optional override of the bureau base URL. + * @returns A new BeaverKnightActionProvider instance + */ +export const beaverknightActionProvider = (baseUrl?: string) => + new BeaverKnightActionProvider(baseUrl); diff --git a/typescript/agentkit/src/action-providers/beaverknight/constants.ts b/typescript/agentkit/src/action-providers/beaverknight/constants.ts new file mode 100644 index 000000000..e38f8871e --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/constants.ts @@ -0,0 +1,18 @@ +/** + * Base URL of the Beaver Knight bureau API. Public, unauthenticated, read-only. + */ +export const BEAVER_KNIGHT_BASE_URL = "https://www.beaverknight.com"; + +/** + * The sort keys /api/vaults accepts. + */ +export const VAULT_SORT_KEYS = [ + "score", + "return", + "sharpe", + "sortino", + "calmar", + "drawdown", + "tvl", + "decisions", +] as const; diff --git a/typescript/agentkit/src/action-providers/beaverknight/index.ts b/typescript/agentkit/src/action-providers/beaverknight/index.ts new file mode 100644 index 000000000..c33f1ab1f --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/index.ts @@ -0,0 +1 @@ +export * from "./beaverknightActionProvider"; diff --git a/typescript/agentkit/src/action-providers/beaverknight/schemas.ts b/typescript/agentkit/src/action-providers/beaverknight/schemas.ts new file mode 100644 index 000000000..7497317f1 --- /dev/null +++ b/typescript/agentkit/src/action-providers/beaverknight/schemas.ts @@ -0,0 +1,62 @@ +import { z } from "zod"; +import { VAULT_SORT_KEYS } from "./constants"; + +/** + * Input schema for rating a wallet (the counterparty check). + */ +export const RateWalletSchema = z + .object({ + wallet: z + .string() + .min(4) + .describe( + "The address to look up: an agent's execution wallet, owner wallet or token. EVM (0x...) or Solana (base58).", + ), + }) + .strict(); + +/** + * Input schema for the ranked vault list. + */ +export const GetVaultRankingsSchema = z + .object({ + sort: z + .enum(VAULT_SORT_KEYS) + .nullable() + .describe( + "Ranking key: score (default, the bureau's 0-99 trust score), return, sharpe, sortino, calmar, drawdown, tvl, decisions. Leave null for the default.", + ), + level: z + .string() + .nullable() + .describe( + "Comma-separated levels to include, e.g. 'strong,solid'. Levels: strong, solid, fair, unproven, flag. Leave null for all.", + ), + minTvl: z.number().nullable().describe("Minimum TVL in USD, or null."), + venue: z + .string() + .nullable() + .describe("Venue filter, e.g. 'Hyperliquid', or null for all venues."), + limit: z + .number() + .int() + .min(1) + .max(100) + .nullable() + .describe("How many ranked vaults to return (1-100). Leave null for 25."), + }) + .strict(); + +/** + * Input schema for one Integrity Report. + */ +export const GetIntegrityReportSchema = z + .object({ + id: z + .string() + .min(1) + .describe( + "The record to report on: a Beaver Knight board id (as returned by get_vault_rankings), a Virtuals ACP agent id, or a wallet/token address.", + ), + }) + .strict(); diff --git a/typescript/agentkit/src/action-providers/index.ts b/typescript/agentkit/src/action-providers/index.ts index 9f7164086..d83182181 100644 --- a/typescript/agentkit/src/action-providers/index.ts +++ b/typescript/agentkit/src/action-providers/index.ts @@ -7,6 +7,7 @@ export * from "./across"; export * from "./alchemy"; export * from "./baseAccount"; export * from "./basename"; +export * from "./beaverknight"; export * from "./cdp"; export * from "./clanker"; export * from "./compound";