Skip to documentation
Anywe

SDK helpers

The repository provides small helpers for the signed agent boundary, in TypeScript and Python. They are deliberately not a complete HTTP API client: your service remains responsible for sending most requests, receiving raw bodies, and storage.

What the helpers cover, one delivery at a time
  1. Delivery arrives

    raw body

  2. Verify

    verify()

  3. Build the reply

    text, card...

  4. Sign

    sign()

  5. Send

    ReplyClient

  6. Platform accepts

    202

Everything before "Send" is covered in both languages. Sending is covered only in TypeScript, by ReplyClient; a Python agent signs and posts its own request. Neither helper opens a webhook server, reads /v1/*, or stores anything on your behalf.

What is included

PackageImplemented surface
TypeScriptHMAC sign, verify, and authorization; typed reply-block constructors; ReplyClient for posting a reply (one-shot, streaming partials, or pass); schema-derived wire types
PythonHMAC sign, verify, and authorization; reply-block constructors; schema-derived wire types

The TypeScript package declares an entry point as @anywe/sdk-ts, with separate CommonJS and ESM builds and a ./generated/* subpath for the schema-derived types, which are deliberately not re-exported from the root. Neither package is on a public registry yet, and neither package sends /v1/* requests for you: build from an authorized checkout and treat the documented behavior as a reference until a distribution channel is announced.

Sign and verify

A platform delivery is authenticated over its exact raw bytes. Verify before parsing JSON; sign the exact bytes you will transmit, never a re-serialization. The authorization scheme is HMAC, not Bearer.

TypeScript
import { authorization, sign, verify } from "@anywe/sdk-ts";
 
const index = verify([currentSecret, previousSecret], inboundSignature, rawBody, Date.now());
const signature = sign(currentSecret, Math.floor(Date.now() / 1000), replyBody);
const authorizationHeader = authorization(agentId, credentialId);
PYTHON
from anywe import authorization, sign, verify
 
index = verify([current_secret, previous_secret], inbound_signature, raw_body)
signature = sign(current_secret, int(time.time()), reply_body)
authorization_header = authorization(agent_id, credential_id)

Keep every active secret in the verification list during a credential overlap. The helpers check both future and past replay-window violations, and they do not make a secret's position observable through an early return. Do not base64-decode the printed secret or reserialize the request body.

Reply-block builders

Both packages construct the same twelve reply shapes: text, card, action, image, file, buttons, progress, table, audio, form, taskUpdate (task_update in Python), and the blocks collector. Four builders throw rather than emit an invalid block: a card takes at most 3 actions, buttons takes 1 to 5, a table takes 1 to 8 columns and at most 50 rows, and a form takes 1 to 20 fields.

A helper existing does not establish end-to-end platform support, and a helper missing does not withhold it. Check the interaction reference rather than the builder list: list, location, event, notification, and video are supported end to end with no builder in either package, so construct those as plain objects, while date_picker has no builder and is refused on the agent path regardless.

TypeScript
import { action, blocks, buttons, card, text } from "@anywe/sdk-ts";
 
const replyBlocks = blocks([
  text("Here is the result."),
  card({ title: "Result", body: "Details", actions: [action("Open", "open://result")] }),
  buttons([action("Continue", "continue")]),
]);
PYTHON
from anywe import blocks as b
 
reply_blocks = b.blocks([
    b.text("Here is the result."),
    b.card("Result", body="Details", actions=[b.action("Open", "open://result")]),
    b.buttons([b.action("Continue", "continue")]),
])

Sending a reply (TypeScript only)

ReplyClient posts blocks to /hooks/v1/reply, signing every frame and retrying a 429 up to three times using the wait the platform names in the response. There is no Python equivalent: sign the body with sign above and post it yourself.

TypeScript
import { ReplyClient, text } from "@anywe/sdk-ts";
 
const client = new ReplyClient({
  platformUrl: "https://anywe.dev",
  agentId: "agt_01ARZ3NDEKTSV4RRFFQ69G5FAV",
  credentialId: "cred_01ARZ3NDEKTSV4RRFFQ69G5FAV",
  secret: process.env.ANYWE_AGENT_SECRETS!,
});
 
// One-shot: the whole answer, no streaming.
await client.sendFinal("dlv_01ARZ3NDEKTSV4RRFFQ69G5FAV", [text("Done.")]);
 
// Streaming: update() coalesces snapshots to the platform's published rate; final() flushes and ends.
const stream = client.stream("dlv_01ARZ3NDEKTSV4RRFFQ69G5FAV", 1);
stream.update([text("Working on it...")]);
await stream.final([text("Done.")]);
 
// Explicitly declining to answer this delivery:
await client.pass("dlv_01ARZ3NDEKTSV4RRFFQ69G5FAV", "no action needed");

ANYWE_AGENT_SECRETS is the name anywe agent secret exports; CLI v0.2.0 exports the same value as AICONNECT_AGENT_SECRETS, so read that name if your credential came from it.

update takes the complete cumulative snapshot, never a delta, and coalesces to the platform's published rate: calling it faster than that is safe, and only the newest snapshot is ever sent. sendFinal and pass each derive their own idempotency key, so retrying the same call after a network failure replays safely. See replies and streaming for the wire contract this client implements.

Builders and the client enforce local bounds and retries, but they do not replace platform validation. Use the interaction reference for rendered block behavior.