Skip to documentation

JavaScript & React SDK

eli.ai's package family separates wire contracts, a headless HTTP client, and React UI. You can use only JSON types, drive every public API operation from a server, or embed complete capabilities in a React application without importing Next.js.

Implemented in the repository

@eli-ai/contracts, @eli-ai/client, and @eli-ai/react are implemented as version 0.1.0 workspace packages. A public package-registry release is a separate distribution step, so confirm your registry before using the install commands below. The OpenAPI reference remains the wire source of truth.

Three layers, one wire contract

SDK package dependency graph

React builds on the headless client; the client builds on JSON-safe contracts; all server authority remains in /api/v1.

Rendering diagram

Downloads

Concepts

  • Package graph
  • SDK

Keywords

  • JSON / SSE
  • Your application
  • JSON-safe types by capability
  • transport + capability clients
  • provider · hooks · components · CSS
  • eli.ai
  • @eli-ai/contracts
  • @eli-ai/client
  • @eli-ai/react
  • /api/v1
Source and generation provenance

Status: current

Generated at: 2026-08-12T23:42:02.967Z

Source hash: 8bbd725c00ac74564f2011484ebd2ce99acd8234cdc6a9370111f7cf1d155ef4

Metadata payload hash: b9b35205a36b230ba5ef37ae1b38408b3933bfee88d244dd18ea0de933e19c92

Canonical appearance

src/app/(docs)/docs/api/sdk/page.tsx:24 route /docs/api/sdk

All appearances

  • canonicalsrc/app/(docs)/docs/api/sdk/page.tsx:24 route /docs/api/sdk

No mirrored appearances.

Generation versions

App: eli-ai 0.1.0

Mermaid: 11.16.0 · Mermaid CLI: 11.16.0

Node: v26.3.1 · Yarn: 4.17.1

Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101

Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033

Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1

Full sidecar JSON: sdk-package-dependency-graph-8bbd725c.json

@eli-ai/contracts

Framework-free request, response, error, and SSE event types through capability subpaths.

@eli-ai/client

A standards-based Fetch client covering all 92 current operations, including authenticated SSE.

@eli-ai/react

An injected provider, generic async hooks, complete capability components, and an optional CSS export.

Headless client

The client accepts a deployment origin, a credential resolver, a workspace resolver, and an injectable Fetch implementation. Dates stay ISO strings, currency stays a decimal string, and route-specific response envelopes stay intact.

package installationbash
npm install @eli-ai/client @eli-ai/contracts
server-side structured queryts
import { createEliClient, EliApiError } from "@eli-ai/client";
import type { StructuredAnswer } from "@eli-ai/contracts/query";

const eli = createEliClient({
  baseUrl: "https://eli.ai",
  apiKey: () => process.env.ELI_API_KEY!,
  workspaceId: process.env.ELI_WORKSPACE_ID,
});

let answer: StructuredAnswer;
try {
  answer = await eli.query.ask({
    question: "Which controls changed this quarter?",
    includeData: true,
  });
} catch (error) {
  if (error instanceof EliApiError && error.status === 403) {
    throw new Error(`Not authorized: ${error.code}`);
  }
  throw error;
}

Capability subpaths

Contracts are imported by grouped capability, so a document integration does not need React or agent stream types. The contracts root deliberately re-exports only shared metadata (common, auth, capabilities, and operations); payload contracts use explicit subpaths. Stable paths are /common, /auth, /query, /documents, /graph, /governance, /data, /agents, /quality, /reports, /connectors, /capabilities, and /operations.

types-only subsetts
import type {
  DocumentMeta,
  CreateDocumentInput,
  DocumentSaveResult,
} from "@eli-ai/contracts/documents";

import type {
  QueuedRun,
  RunEvent,
} from "@eli-ai/contracts/agents";

Authentication and workspace selection

The client adds protocol headers; it does not make an authorization decision. The server still resolves the key, checks the operation's scope, narrows user keys against the owner's live workspace role, and runs tenant reads and writes beneath FORCE row-level security.

SDK authentication boundary

The SDK transports identity; the server remains the trust boundary.

Rendering diagram

Downloads

Concepts

  • Auth flow
  • SDK

Keywords

  • FORCE RLS
  • eli_sk_ or eli_uk_
  • injected fetch
  • Bearer key
  • scope + live capability
  • workspace transaction
  • /api/v1
  • Application
  • EliTransport
  • optional
  • X-Workspace-Id
Source and generation provenance

Status: current

Generated at: 2026-08-12T23:41:59.195Z

Source hash: ed41851a1721220d89d202e25c1b11c75950f72020311ecc83f02e6c0810fb43

Metadata payload hash: 9d0bcbfd3bbd81b41bd9c5ce77a000de52259b38907e407314b19cf02b978f35

Canonical appearance

src/app/(docs)/docs/api/sdk/page.tsx:39 route /docs/api/sdk

All appearances

  • canonicalsrc/app/(docs)/docs/api/sdk/page.tsx:39 route /docs/api/sdk

No mirrored appearances.

Generation versions

App: eli-ai 0.1.0

Mermaid: 11.16.0 · Mermaid CLI: 11.16.0

Node: v26.3.1 · Yarn: 4.17.1

Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101

Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033

Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1

Full sidecar JSON: sdk-authentication-boundary-ed41851a.json

Workspace selection is deterministic: a headless method's per-call workspaceIdoverrides the client transport default. React hooks and components pass the provider's workspace as that per-call override when supplied; otherwise the injected transport's default applies. An explicit x-workspace-id custom header takes final precedence, so do not pass untrusted arbitrary headers through an integration wrapper.

KeyWorkspace rule
eli_sk_…Fixed to one workspace. A different X-Workspace-Id is rejected.
eli_uk_… · one workspaceThe single allowed workspace is selected automatically.
eli_uk_… · multiple/allEvery request must include X-Workspace-Id inside the key grant and live membership.

Do not put a workspace key in browser code

Never ship an eli_sk_ key in a bundle, HTML, local storage, or public runtime configuration. The current API also installs no cross-origin CORS policy. Browser React consumers should use a same-origin server-side BFF or reverse proxy that injects a Bearer key. A shared origin alone does not reuse the application session: /api/v1 still returns 401 without a Bearer credential. Direct browser use is only appropriate for a narrowly scoped user credential under an operator-controlled setup. The injected transport/custom Fetch is the trust boundary.

Durable runs over Fetch-based SSE

Starting an agent returns HTTP 202 with a durable run id and stream path. The worker executes independently; agents.streamRun() attaches to a database-backed replay/tail. Fetch is required instead of native EventSource because the stream needs Authorization and, for some user keys, X-Workspace-Id.

SDK durable run reattachment

A disconnected client does not stop or restart the durable run.

Rendering diagram

Downloads

Concepts

  • Run flow
  • SDK

Keywords

  • eli.ai web
  • model_call / tool_call
  • agents.createRun(slug, input)
  • persist queued run
  • execute + persist steps
  • GET /runs/{id}/stream
  • replay, then tail
  • POST /runs/{id}/approve
  • reconnect stream
  • POST /agents/{slug}/runs
  • Postgres
  • agents.streamRun(runId)
  • App
  • EliClient
  • Worker
  • suspended
  • final
  • error
Source and generation provenance

Status: current

Generated at: 2026-08-12T23:42:01.059Z

Source hash: afc808bcbfad3a043154ed09eac58c0aae0168fe7763ab57d48029b421417c08

Metadata payload hash: e042b0bae3bc6b6a66f9036e90616fe4e9fcc19bc07b641fedc81f97926750fd

Canonical appearance

src/app/(docs)/docs/api/sdk/page.tsx:50 route /docs/api/sdk

All appearances

  • canonicalsrc/app/(docs)/docs/api/sdk/page.tsx:50 route /docs/api/sdk

No mirrored appearances.

Generation versions

App: eli-ai 0.1.0

Mermaid: 11.16.0 · Mermaid CLI: 11.16.0

Node: v26.3.1 · Yarn: 4.17.1

Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101

Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033

Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1

Full sidecar JSON: sdk-durable-run-reattachment-afc808bc.json

durable-run APIts
import type { RunEvent } from "@eli-ai/contracts/agents";

const accepted = await eli.agents.createRun("control-reviewer", {
  input: "Review the latest policy changes.",
});

for await (const event of eli.agents.streamRun(accepted.runId, { signal })) {
  if (event.type === "model_call" || event.type === "tool_call") {
    renderProgress(event);
  }

  if (event.type === "suspended") {
    renderApproval(event.approvalId, event.toolName);
    break;
  }

  if (event.type === "final") {
    renderAnswer(event.text, event.citations);
    break;
  }

  if (event.type === "error") {
    renderError(event.message);
    break;
  }
}

Reconnects replay progress

The current stream replays persisted steps from the beginning and does not implement Last-Event-ID. Reconnecting can repeat progress events. Abort closes the local reader but does not cancel the run; call agents.cancelRun(id) for cooperative cancellation. Streams close on suspended, final, error, or the current ten-minute safety timeout.

React composition

React receives an already-constructed transport, or the transport retained from an aggregate client. That keeps key retrieval, tenant selection, same-origin proxying, and tracing outside the render tree. Each capability component constructs only its matching client module from that transport. Complete components use scoped eli-* classes and the optional CSS export; hooks remain usable with application-owned markup. EliProvider deliberately has no API-key prop.

React installationbash
npm install @eli-ai/react @eli-ai/client react
provider + complete query surfacetsx
import { createEliTransport } from "@eli-ai/client/core";
import { EliProvider } from "@eli-ai/react/provider";
import { EliQuery } from "@eli-ai/react/query";
import "@eli-ai/react/styles.css";

const transport = createEliTransport({
  // Calls a same-origin BFF that injects the credential server-side.
  fetch: sameOriginProxyFetch,
});

export function KnowledgeAnswer({ workspaceId }: { workspaceId: string }) {
  return (
    <EliProvider transport={transport} workspaceId={workspaceId}>
      <EliQuery initialMode="ask" />
    </EliProvider>
  );
}
headless hook + your markuptsx
import { createQueryClient } from "@eli-ai/client/query";
import { useEliMutation } from "@eli-ai/react/hooks";

type QueryClient = ReturnType<typeof createQueryClient>;
type AskAnswer = Awaited<ReturnType<QueryClient["ask"]>>;

export function CompactAsk() {
  const query = useEliMutation<AskAnswer, string>({
    context: "compact-ask",
    mutation: ({ transport, workspaceId }, question, signal) =>
      createQueryClient(transport).ask(
        { question },
        { signal, ...(workspaceId ? { workspaceId } : {}) },
      ),
  });

  return (
    <form onSubmit={(event) => {
      event.preventDefault();
      const data = new FormData(event.currentTarget);
      void query.mutate(String(data.get("question") ?? ""));
    }}>
      <input name="question" aria-label="Question" />
      <button disabled={query.isPending}>Ask</button>
      {query.error instanceof Error && <p role="alert">{query.error.message}</p>}
      {query.data && <p>{query.data.answer}</p>}
    </form>
  );
}

No Next.js dependency

The React package uses ordinary React, URLs, callbacks, and an injected transport. It imports no Next router, Link, Image, font, server-action, or route-handler module.

Current capability coverage

The headless client covers every operation in the current OpenAPI document. React adds complete components by product capability; MCP remains a separate protocol at /api/mcp.

CapabilityCanonical scopesCurrent routesReact surface
Query & searchagents:run · kb:read/query · /searchEliQuery · EliSearch
Documentskb:read · kb:write/documents · verify · lineageEliDocuments · EliDocumentLineage
Entities & governancekb:read · kb:write/entities · /relations · /manifest · change requests · SKOSEliKnowledgeGraph · EliGovernance
Live datadata:read · data:run/data/connectors · /data/queriesEliLiveData
Reportsreports:read · reports:write/reportsEliReports
Agents & runsagents:run · runs:read/agents/{slug}/runs · /runs/{id}/*EliAgentRunner · EliRunDetail
Policy, evals & cachekb:read · kb:write/policy · /evals · /qrels · /cache/statsEliQuality · EliPolicyDecisions · EliEvalMetrics · EliCacheStats
Content connectorsdata:read · kb:write/connectors · /connectors/{id}/syncEliConnectors

Canonical versus accepted read scopes

The SDK operation catalog exposes both scope and acceptedScopes, matching OpenAPI's x-required-scope and x-accepted-scopes. OpenAPI recommends kb:read for graph, lineage, policy, eval, and cache reads; selected compatibility guards also accept older runs:read keys. New integrations should request the canonical scope.

Error behavior

Non-2xx responses become EliApiError, retaining status, machine code, validation issues, parsed details, and the x-request-id when present. Fetch failures become EliTransportError; invalid successful JSON or response content types become EliProtocolError; malformed JSON in an SSE frame becomes EliSseParseError. Abort keeps its native identity. A terminal SSE error payload remains a yielded RunEvent.

  • 400: fix request or workspace selection; do not retry unchanged input.
  • 401: missing, invalid, or revoked credential.
  • 402: monthly agent-spend admission blocked.
  • 403: insufficient scope, live capability, or workspace grant.
  • 404: unknown or cross-workspace resource; the distinction is intentionally hidden.
  • 409: required model is not configured.
  • 429: active-run capacity is full, not a general API throttle.

The current API has no universal pagination envelope, standard idempotency key, general rate limiter, or cross-origin CORS policy. Document enrichment is asynchronous after durable save, and run SSE is the only unified public push channel today.

Repository, registry, and HTTP use

Inside this repository, consume the version 0.1.0 workspace packages directly. Outside it, confirm the package-registry release before running the install commands. The HTTP/OpenAPI contract remains the interoperable fallback and source of truth: