Skip to content

SDK reference (@eazo/anima)

The official SDK is Node.js / TypeScript (@eazo/anima). Other languages call the HTTP API directly.

Why domains and endpoints still say eak

SDK symbols are unified under the Anima prefix (Qoni, AnimaScopes, Anima*Error). Domains and endpoints such as api.eak.eazo.ai and /api/v3/eak/... keep the legacy identifier eak — they all refer to the same Qoni infrastructure.

This page is verified line by line against the type definitions of the published @eazo/anima v0.2.1. After upgrading the SDK, the type definitions of that version are authoritative.

Install and initialize

bash
npm install @eazo/anima
typescript
import { Qoni } from "@eazo/anima";

const anima = new Qoni({
  host: "https://api.eak.eazo.ai",
  accessKey: process.env.ANIMA_ACCESS_KEY!,
  secretKey: process.env.ANIMA_SECRET_KEY!,
});

Common AnimaOptions:

OptionTypeNotes
hoststringGateway address. The SDK discovers per-service addresses through runtime-config
accessKey / secretKeystringWorkspace access key. Server-side only — never ship it to a browser or client (see Security considerations)
timeoutMsnumberRequest timeout
sseMaxRetriesnumberAutomatic reconnect attempts for SSE streams (default 5, resumes from last-event-id; 0 disables)
fetchtypeof fetchCustom fetch implementation

Deprecated initialization options

accessKeyId / accessKeySecret are @deprecated — use accessKey / secretKey. The direct-address options eakBaseUrl / genauthBaseUrl and friends are @deprecated — use host and let runtime discovery do the work.

delegateToken — start a delegation

Two modes, two return shapes. Overloads:

typescript
delegateToken(input: DelegateTokenInteractiveInput): Promise<AnimaResponse<InteractiveDelegationResponse>>;
delegateToken(input: DelegateTokenSilentInput): Promise<AnimaResponse<DelegateTokenSilentResponse>>;
typescript
import { AnimaScopes } from "@eazo/anima";

const { data } = await anima.delegateToken({
  mode: "interactive",
  agent: "report-agent",
  scopes: [AnimaScopes.WEB_SEARCH_RUN, AnimaScopes.WEB_SEARCH_READ],
  redirectUri: "https://yourapp.example.com/eak/callback",
  state: "opaque-business-state",
  user: { id: "usr_demo_0001" },
});
// data: InteractiveDelegationResponse
// { mode: "interactive", authorizationUrl, grantId, grantState, state, requestedScopes? }

Send the user to authorizationUrl to give consent, then exchange the callback for a token with completeDelegateToken.

typescript
const { data } = await anima.delegateToken({
  agent: "report-agent",
  scopes: [AnimaScopes.WEB_SEARCH_RUN],
  user: { id: "usr_demo_0001" },
  expiresIn: 7200, // seconds, 60-86400
});
// data: DelegateTokenSilentResponse (contains the token immediately)

Where silent mode ends

Silent mode gives consent on behalf of the organization instead of asking the user. It only belongs in a hardened, trusted server-side integration. Read the hard-constraint checklist in Security considerations and the positioning in Consent and approval before you use it.

Input fields (DelegateTokenInput)

FieldTypeRequiredNotes
agentstringAgent identifier
scopesstring[]Requested scopes (use the AnimaScopes constants)
user{ id: string, ... }✓ for silent / optional for interactiveThe delegating user
mode"silent" | "interactive"defaults to silentConsent mode
redirectUri / statestring✓ for interactiveCallback address and your business state
expiresInnumber | stringoptionalToken lifetime (seconds, 60-86400)
idempotencyKeystringoptionalIdempotency key

Deprecated: the top-level userId (use user: { id }) and the delegateAgent() alias (use delegateToken()). Migration mapping: Glossary and migration. The server-side compatibility risk is covered in Security considerations.

typescript
const { data } = await anima.completeDelegateToken({ grantId, code, state });
// data: DelegateTokenResponse

DelegateTokenResponse fields:

FieldTypeNotes
tokenstringThe delegate token. This is the SDK's renamed field — over HTTP it is called delegationToken (see the comparison below). The SDK also keeps the @deprecated aliases delegateAgentToken and delegationToken
tokenType"Bearer"Token type
expiresInnumberLifetime in seconds
grantId / auditIdstringGrant record ID / audit chain ID
grantedScopesstring[]?Scopes actually granted
mode"silent" | "interactive"How it was issued

SDK field names ≠ HTTP field names

The SDK renames and enriches the backend response. Mixing the two returns undefined:

HTTP response (API reference)SDK response (this page)
Delegate tokendelegationToken (+ delegateAgentToken, same value)token
Granted scopesnot presentgrantedScopes?
Error codeseak.* dotted codes (e.g. eak.delegation.agent_not_allowed)merged codes + typed error classes (below)

Use this page when you use the SDK; use the API reference when you call HTTP directly.

Namespaces

  • anima.genauth: introspectDelegationToken({ token }) (online delegate-token validation), userInfo({ accessToken }), jwks(), discovery(), users.list / get / getBatch / create / createBatch / update / deleteBatch (management plane, requires an admin token).
  • anima.eak: workspaces.list / get / create / update, credentials.list / create / rotate / update (workspace and access-key management, matching the workspace endpoints in the API reference).
  • Product namespaces: anima.gumem, anima.webSearch, anima.doAnything, anima.track, anima.deepResearch — product capability calls that accept a token (delegate token or runtime token); see the respective product docs.

Other useful methods

MethodPurpose
anima.currentUser({ accessToken })Resolve the signed-in user from their access token — this is how application code decides "on whose behalf"
anima.resolveAnyBoundUser()Return any user ID from the bound user pool. Demos and smoke tests only — production code should use currentUser
anima.request({ method, path, body?, query?, headers?, token? })Raw request channel for endpoints that have no named wrapper yet (such as token exchange at POST /api/v3/eak/token-exchange); signing is handled for you
anima.unstableRequest(...)Same, for unstable or experimental endpoints

Scope constants

AnimaScopes (formatted service.capability:action) and AnimaScopeBundles (common combinations):

typescript
AnimaScopes.WEB_SEARCH_RUN        // "webagent.web_search:run"
AnimaScopes.DO_ANYTHING_RUN       // "webagent.do_anything:run"
AnimaScopes.GUMEM_MEMORY_READ     // "gumem.memory:read"

AnimaScopeBundles.WEB_SEARCH               // run + read
AnimaScopeBundles.AGENT_DO_ANYTHING_BASIC  // run + read + stop + control
AnimaScopeBundles.GUMEM_READONLY           // memory:read + profile:read

Pick for least privilege: prefer a single scope over a bundle, and read over run.

Error handling

Every error extends AnimaError (carrying code, status and meta.requestId):

Error classTypical codeWhen it happens
AnimaAuthErrorauth.failedBad signature or key
AnimaDelegationRequiredErrordelegation.requiredDelegate token missing
AnimaPermissionDeniedErrorpermission_deniedInsufficient scope, or whitelist rejection
AnimaTokenExpiredErrortoken.expiredToken expired
AnimaValidationErrorvalidation.failedRequest validation failed
AnimaRateLimitErrorrate_limit.exceededRate limited
AnimaUpstreamErrorupstream.failed, eak.token_exchange.upstream_failedUpstream service failure
AnimaTimeoutErrortimeoutTimed out
typescript
import { AnimaTokenExpiredError } from "@eazo/anima";

try {
  await anima.genauth.introspectDelegationToken({ token });
} catch (err) {
  if (err instanceof AnimaTokenExpiredError) {
    // start a new delegation
  }
  throw err;
}

Next steps