Skip to content

About

VIP native passthrough for Anthropic & OpenAI through BlockRun — official Go SDKs, x402 USDC on Base, zero response reshaping.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

42 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

blockrun-llm-go-vip

Genuine native passthrough for Anthropic and OpenAI through the BlockRun gateway — use an API key, or pay per call in USDC (x402) on Solana or Base (vip.WithChain("solana")), with zero model substitution and zero response reshaping.

Unlike a re-implemented client, the constructors here return the official anthropic-sdk-go and openai-go client types. They only swap the transport (to add x402 payment) and the base URL. The gateway returns the upstream provider's response verbatim, so the official SDK parses the real signals:

  • Claude: claude-opus-5.5 · claude-sonnet-5.5 · claude-fable-5.1 · claude-fable-5 · claude-opus-5 · claude-sonnet-5 · claude-opus-4.8 · claude-opus-4.7 · claude-opus-4.5 · claude-sonnet-4.6 · claude-sonnet-4.5 · claude-haiku-4.5. Opus 4.7 and up use adaptive thinking — anthropic.ThinkingConfigParamOfEnabled(N) is honored.
  • GPT: native ID (chatcmpl-*), SystemFingerprint, honest token usage and JSON mode — routed to /v1/chat/completions.

A Claude / OpenAI relay detector sees a direct upstream call.

This is the Go counterpart of the Python blockrun-llm-vip package, reusing the x402 signing and wallet loading from blockrun-llm-go.

Account API

Register at user.blockrun.ai, create an API key, and add account credit.

export BLOCKRUN_API_KEY=brk_live_...
client, err := vip.NewOpenAI() // no wallet required
// Explicit form, accepted by all constructors:
client, err = vip.NewOpenAI(vip.WithAPIKey("brk_live_..."))

OpenAI/Anthropic native clients, Image/Speech/Music/Video, Voice/Phone, Search/Exa and RealFace/Portrait share account authentication. Media submission and polling use the same key; no x402 signing or wallet fallback occurs on account errors. The root defaults to https://api.blockrun.ai and accepts WithBaseURL, BLOCKRUN_API_KEY_URL (the main SDK's name for it) or BLOCKRUN_API_BASE_URL (trailing /v1 is normalized). Credentials are restricted to that origin and redirects are disabled. Account billing is reported in the portal; wallet-owned asset lists still require a wallet.

WithAPIKey plus WithWalletKey is rejected. An explicit wallet key overrides an environment API key. A value that is not an account key (vip.WithAPIKey("blockrun"), the pre-v0.8 form) is still just the placeholder key sent upstream and keeps the x402 wallet rail; a truncated brk_ secret is rejected where you set it. Any key the main SDK accepts is accepted here, brk_test_ included. Without account credentials, explicit/saved wallet choices and existing Base-only wallets are retained; otherwise Solana is preferred. Chain/facilitator options do not select a billing chain in account mode.

The account rail rides on the released blockrun-llm-go v0.21.1, whose constructors take a brk_ key wherever they take a wallet key — no replace directive, so applications get it from a plain go get.

One caveat on the "verbatim" promise above: it is exact on the x402 wallet rail. On the account rail the Anthropic responses carry gateway message ids (msg_br_… rather than a native msg_…), and adaptive-thinking models return real thinking signatures while some non-adaptive ones drop a thinking block that the wallet rail keeps. OpenAI responses stay native on both rails (chatcmpl-… ids, system_fingerprint, token-detail usage).

Video polling acceptance additionally requires the gateway's video signing-secret provisioning; local protocol tests cover that path, which is not a claim it is already live.

Install

go get github.com/BlockRunAI/blockrun-llm-go-vip

Use — it's a drop-in

import (
    "github.com/anthropics/anthropic-sdk-go"
    vip "github.com/BlockRunAI/blockrun-llm-go-vip"
)

// Claude — exactly the official anthropic-sdk-go API.
client, _ := vip.NewAnthropic()          // wallet auto-loaded from ~/.blockrun/.session
msg, _ := client.Messages.New(ctx, anthropic.MessageNewParams{
    Model:     anthropic.Model("claude-opus-5"), // current flagship (adaptive thinking)
    MaxTokens: 1024,
    Thinking:  anthropic.ThinkingConfigParamOfEnabled(1024),
    Messages:  []anthropic.MessageParam{
        anthropic.NewUserMessage(anthropic.NewTextBlock("What is 23*47?")),
    },
})
for _, b := range msg.Content {
    if b.Type == "thinking" {
        fmt.Println("signature:", b.Signature)   // real Anthropic signature
    }
}
import (
    vip "github.com/BlockRunAI/blockrun-llm-go-vip"
    "github.com/openai/openai-go"
)

// GPT — exactly the official openai-go API.
gpt, _ := vip.NewOpenAI()
resp, _ := gpt.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
    Model:    openai.ChatModel("gpt-4o"),
    Messages: []openai.ChatCompletionMessageParamUnion{openai.UserMessage("hi")},
})
fmt.Println(resp.SystemFingerprint, resp.Model)   // genuine OpenAI direct

Runnable examples: examples/anthropic, examples/openai, and examples/seedance.

Models

You name the model; the gateway never substitutes it. Pass any current id verbatim:

  • Claude: claude-opus-5 · claude-sonnet-5 · claude-opus-4.8 · claude-opus-4.7 · claude-opus-4.5 · claude-sonnet-4.6 · claude-sonnet-4.5 · claude-haiku-4.5. Opus 4.7 and up use adaptive thinking — anthropic.ThinkingConfigParamOfEnabled(N) is honored.
  • GPT: gpt-6-astra · gpt-6.1-sol · gpt-6-sol · gpt-6-luna · gpt-5.6-sol · gpt-5.6-terra · gpt-5.6-luna (each 5.6 tier also as -pro) · gpt-5.5 · gpt-5.4 · gpt-5.2 · gpt-5.3-codex · gpt-4.1 · gpt-4o · gpt-4o-mini, reasoning o3 / o4-mini, and more. GPT‑5.x / o-series are reasoning models — leave MaxTokens/Temperature unset (the gateway normalizes them); gpt-4o / gpt-4o-mini are served OpenAI-direct.

The SDK also ships a 116-model catalog snapshot (chat, image, video, music, speech, and sound effects) so callers can build a picker without a network round trip:

for _, model := range vip.Models() {
    fmt.Println(model.ID, model.Categories, model.ContextWindow, model.Pricing)
}
opus, ok := vip.FindModel("anthropic/claude-opus-5")

Catalog ids are namespaced (anthropic/claude-opus-5), which is the form the media helpers take. The gateway resolves either form on the chat routes, so model.ID works with Messages.New / Chat.Completions.New too — but model.NativeID() gives the bare provider id ("claude-opus-5") that matches the upstream SDK docs. FindModel accepts either form. BillingMode ("paid", "free", or the media unit) identifies the free NVIDIA tier; an unpriced media model is not free.

One gotcha: use the dotted ids above. Dashed variants are accepted only as a fixed alias list, and a namespaced dashed id (anthropic/claude-sonnet-4-6) is rejected by /v1/messages outright.

The snapshot (2026-10-20) covers Claude, GPT-6 and GPT-5.x, Gemini, DeepSeek, Grok, GLM, Kimi, MiniMax, Qwen, MiMo, Mistral, the free tier, and media models. The gateway's per-model available flag is a live health signal and is not part of the snapshot. Use https://blockrun.ai/api/v1/models when your application needs the live catalog.

Seedance video — incl. real-person (RealFace) & AI character (Portrait)

Generate short videos through ByteDance Seedance. The gateway runs generation asynchronously, and the client mirrors that — Submit signs the x402 payment authorization and returns immediately, then you Poll or Wait. USDC settles on-chain only on the first poll that observes completed; failed or abandoned jobs are never charged:

video, _ := vip.NewVideo()

// Async: submit returns a job handle without blocking.
job, _ := video.Submit(ctx, "a neon-lit cyberpunk street, slow dolly forward",
    &vip.VideoGenerateOptions{Model: "bytedance/seedance-2.0-fast", DurationSeconds: 5})
fmt.Println(job.ID, job.Status) // e.g. "bytedance:video_…", "queued"

for !job.Done() {
    time.Sleep(12 * time.Second)
    video.Poll(ctx, job) // advances job.Status (see "How polling pays" below)
}
fmt.Println(job.Response.Data[0].URL) // permanent BlockRun-hosted MP4

How polling pays: on Solana (vip.WithChain("solana")) each poll proves the job is yours with a fresh ed25519 signature from your wallet over blockrun-poll:v1:video:<job id>:<unix seconds> (headers x-poll-wallet, x-poll-timestamp, x-poll-signature) — no payment is signed while the job is pending. When the video is ready the gateway answers that poll with a 402 ("status":"completed"); Poll signs exactly one payment from it and re-sends, which settles the job and returns the video. If the gateway refuses the proof for a job (e.g. one submitted before it bound payers, or a clock more than 300s off), Poll logs it and falls back to x-payment polling for that job. Your system clock must be within ±300s of real time. If the answer to that one paid poll is lost or the gateway reports the settlement as in progress, Poll keeps polling (the gateway settles a job at most once and hands back the video if it already did); after 4 such polls in a row it returns a *vip.VideoPaymentInDoubtError carrying the PollURL — resume by polling it with the same wallet, never by submitting again. On Base every poll re-signs x402 as before. On every rail, a job that failed upstream now ends as failed (never charged) instead of completed with no video.

video.Wait(ctx, job) blocks until done, and video.Generate(ctx, prompt, opts) is shorthand for Submit+Wait (one blocking call). Video is implemented natively in this package; RealFace and Portrait reuse blockrun-llm-go's gateway clients. All x402-paid on Base.

A specific, real person can appear consistently across clips: enroll once via RealFace (one-time $0.01, ~1-min on-phone liveness for consent, no KYC), get a ta_xxxx, and pass it as RealFaceAssetID on Seedance 2.0 / 2.0-fast. For an AI character / mascot use Portrait instead (single enroll, no liveness).

portrait, _ := vip.NewPortrait()
asset, _ := portrait.Enroll(ctx, "Mascot", "https://example.com/character.jpg") // $0.01
job, _ := video.Generate(ctx, "the mascot waves in soft studio light",
    &vip.VideoGenerateOptions{Model: "bytedance/seedance-2.0", RealFaceAssetID: asset.AssetID})

RealFaceAssetID is mutually exclusive with ImageURL and only works on Seedance 2.0 / 2.0-fast. Constructors: vip.NewVideo, vip.NewRealFace, vip.NewPortrait.

Full real-person flow (RealFace state machine, on-phone liveness, error states): docs/real-person-flow.md.

Image — generate & edit

img, _ := vip.NewImage()
out, _ := img.Generate(ctx, "a red fox in fresh snow, soft studio light",
    &vip.ImageGenerateOptions{Model: "openai/gpt-image-1"})
fmt.Println(out.Data[0].URL)

// edit / multi-image fusion:
edited, _ := img.Edit(ctx, "make it night", []string{dataURI}, nil)

Models: openai/gpt-image-1 · gpt-image-2 · gpt-image-2.5-flare · gpt-image-2.5-sunburst · google/nano-banana · nano-banana-2 · nano-banana-pro · xai/grok-imagine-image · grok-imagine-image-2.0 · grok-imagine-image-pro · bytedance/seedream-5-pro · zai/cogview-4. img.ListImageModels(ctx) lists them (free).

Audio — speech, music, sound effects

sp, _ := vip.NewSpeech()
speech, _ := sp.Generate(ctx, "Hello there.", &vip.SpeechGenerateOptions{Voice: "sarah"})
sfx, _ := sp.SoundEffect(ctx, "distant thunder over rain", nil)

mu, _ := vip.NewMusic()
instrumental := true
track, _ := mu.Generate(ctx, "dreamy lo-fi beat", &vip.MusicGenerateOptions{Instrumental: &instrumental})
fmt.Println(speech.Data[0].URL, sfx.Data[0].URL, track.Data[0].URL)

sp.ListVoices(ctx) lists TTS voices (free). Music runs ~1-3 min and blocks until ready.

Search — Grok Live Search & Exa

s, _ := vip.NewSearch()
r, _ := s.Search(ctx, "latest on x402 micropayments",
    &vip.SearchOptions{Sources: []string{"x", "news"}, MaxResults: 15})

exa, _ := vip.NewExa()
hits, _ := exa.Search(ctx, "x402 protocol", map[string]any{"numResults": 5})
text, _ := exa.Contents(ctx, []string{"https://example.com"}, nil)
ans, _ := exa.Answer(ctx, "what is the x402 payment header?", nil)

Voice & Phone — AI phone calls

Lease a wallet-bound number, then place an AI-driven outbound call. Call returns a call id; poll it with GetCallStatus for the transcript + recording.

phone, _ := vip.NewPhone()
num, _ := phone.BuyNumber(ctx, vip.BuyNumberOptions{Country: "US", AreaCode: "415"}) // $5, 30-day lease

voice, _ := vip.NewVoice()
call, _ := voice.Call(ctx, vip.CallOptions{
    To:          "+14155551234",
    Task:        "Ask if they're open Sunday, confirm hours, then thank them and end the call.",
    MaxDuration: 3,
})
status, _ := voice.GetCallStatus(ctx, call.CallID)
fmt.Println(status)

Phone also does Lookup / LookupFraud, ListNumbers, RenewNumber, ReleaseNumber.

Options

vip.NewAnthropic(
    vip.WithChain("solana"),                     // explicit wallet chain
    vip.WithWalletKey("..."),                    // explicit key (Base hex, or bs58 on Solana)
    vip.WithBaseURL("https://blockrun.ai/api"),  // override the gateway
    vip.WithSolanaRPCURL("https://..."),         // override the Solana RPC (Solana only)
    vip.WithFacilitator("payai"),                // facilitator preference (Solana only; default "figment")
)

All options apply to every constructor (NewOpenAI, NewImage, NewVideo, …).

Solana

Pass vip.WithChain("solana") to any constructor to pay USDC on Solana via sol.blockrun.ai instead of Base — the drop-in stays identical:

claude, _ := vip.NewAnthropic(vip.WithChain("solana"))  // bs58 key from ~/.blockrun/.solana-session
gpt, _    := vip.NewOpenAI(vip.WithChain("solana"))
img, _    := vip.NewImage(vip.WithChain("solana"))

Payment is the x402 SVM "exact" scheme: the bs58 key signs a Solana TransferChecked USDC transaction locally (ed25519), and BlockRun's facilitator co-signs the fee and settles it gaslessly. Responses are still the upstream provider's verbatim JSON. Runnable example: examples/solana.

Facilitator routing (v0.7.0+)

Solana VIP clients send a facilitator preference (x-blockrun-facilitator: figment) plus the wallet's public address (x-payer-wallet) with each request, so VIP traffic settles through the Figment facilitator while other BlockRun clients keep using PayAI. Payment semantics are identical on both rails (same x402 exact-scheme USDC transfer, gasless for the payer). Opt out with vip.WithFacilitator("payai") or BLOCKRUN_FACILITATOR=payai — the wire is then byte-identical to v0.6.x. Base chain is unaffected.

Wallet

The private key is used only for local signing (EIP-712 on Base, SVM/ed25519 on Solana) and never leaves your machine.

Base resolution order:

  1. WithWalletKey(...) option
  2. BLOCKRUN_WALLET_KEY env
  3. BASE_CHAIN_WALLET_KEY env
  4. ~/.blockrun/.session

Solana (WithChain("solana")) resolution order:

  1. WithWalletKey(...) option (bs58)
  2. SOLANA_WALLET_KEY env
  3. ~/.*/solana-wallet.json (most recent)
  4. ~/.blockrun/.solana-session

The gateway base URL can be overridden via BLOCKRUN_API_URL (Base) / BLOCKRUN_SOLANA_API_URL (Solana); the Solana signing RPC via SOLANA_RPC_URL.

How it works

NewAnthropic / NewOpenAI build the official SDK client with two request options:

  • option.WithBaseURL(...) — point at the BlockRun gateway.
  • option.WithMiddleware(...) — a transport middleware that performs the x402 handshake: the first request goes out unpaid; on a 402 the payment-required requirement is parsed, a USDC authorization is signed locally (EIP-712 on Base, the SVM "exact" scheme on Solana), and the original request is replayed verbatim with a PAYMENT-SIGNATURE header. On 200 the upstream body is handed back untouched.

Because the middleware never reshapes the success response, the official SDK does all parsing — that is what makes the passthrough native.

Two failures recover automatically, both bounded, and both only on an explicit machine-readable signal from the gateway:

  • Stale blockhash (402) — the signed Solana transaction aged out. It is discarded, never replayed; the whole negotiation re-runs from a fresh quote and a fresh signature.
  • Verifier unavailable (503 PAYMENT_VERIFICATION_UNAVAILABLE) — the gateway could not run its payer-risk screen and failed closed, so the payment was never judged. The request is retried honouring the server's Retry-After (capped at 30s).

Every other response, including any other 503, is handed to the caller untouched. That is deliberate: paid routes settle optimistically, in parallel with the upstream work, so an unmarked 503 may arrive after the charge — retrying it would buy the same thing twice. Recovery is limited to answers the gateway gives before anything is broadcast.

Scope

Covers, on Base or Solana (vip.WithChain("solana")):

  • Anthropic + OpenAI native passthrough (NewAnthropic, NewOpenAI).
  • Seedance video incl. RealFace real-person + Virtual Portrait (NewVideo, NewRealFace, NewPortrait).
  • Image generate + edit (NewImage).
  • Audio: ElevenLabs speech + sound effects (NewSpeech), MiniMax music (NewMusic).
  • Search: Grok Live Search (NewSearch) + Exa web search (NewExa).
  • Voice & Phone: AI phone calls (NewVoice) + number provisioning (NewPhone).

Access

Give BlockRun your wallet address to enable VIP, then pay per call from that wallet.

Contact: vicky@blockrun.ai

About

VIP native passthrough for Anthropic & OpenAI through BlockRun — official Go SDKs, x402 USDC on Base, zero response reshaping.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages