Skip to content

TypeScript SDK

The jennah-sdk-ts package provides TypeScript bindings for the Jennah gRPC API. The package includes compiled JavaScript alongside type declarations, supporting both TypeScript and plain JavaScript environments.

npm install jennah-sdk-ts

The SDK requires Node.js 22.12 or later. It is distributed as an ES module and also supports CommonJS via require().

Server-side only

The SDK is intended for server environments only and will not load in a web browser. Browser-based applications should proxy requests through their backend server to protect credentials.

Quickstart

Authenticate using jnh login (see CLI overview) or by setting the JENNAH_API_KEY environment variable. The following example creates an agent, stores a vector chunk, and performs semantic search:

import { randomUUID } from "node:crypto";
import { Client } from "jennah-sdk-ts";

const client = new Client(); // uses `jnh login` or $JENNAH_API_KEY
const agentInstanceId = `quickstart-${randomUUID().slice(0, 8)}`;
await client.agents.createAgent({ agentInstanceId });
try {
  // Store a vector chunk. Raw content is embedded automatically.
  await client.memory.commitMemory({
    agentInstanceId,
    vectors: [
      {
        chunkId: "pref-1",
        rawContent:
          "The customer prefers invoices in Japanese yen, " +
          "sent on the 5th.",
      },
    ],
  });

  // Semantic search query.
  const { semantic } = await client.memory.queryMemory({
    agentInstanceId,
    semantic: {
      queryText: "what currency does the customer want to be billed in?",
      limit: 3,
    },
  });
  for (const m of semantic?.matches ?? []) {
    console.log(`${m.distance.toFixed(3)}  ${m.rawContent}`);
  }
} finally {
  await client.agents.deleteAgent({ agentInstanceId });
  client.close();
}
0.235  The customer prefers invoices in Japanese yen, sent on the 5th.

Services

API services are available directly on the client, bound to the authenticated connection:

Property Service Description
agents AgentService Agent lifecycle management
memory MemoryService Commit, query, inspect, form, and supersede memory operations
scopes ScopeService Scope isolation and access control
datasets, schema, data Datastore services Application datastore management and queries
auth AuthService Identity, organization members, API keys, and roles
approvals ApprovalService Operation approvals workflow
billing, platform Platform services Subscriptions and platform locations

Requests are plain objects matching generated message definitions, with message types exported from the generated modules (for example, jennah-sdk-ts/gen/jennah/agent/v1/memory_pb). Every method accepts an options object as its second argument, supporting timeoutMs and signal (an AbortSignal).

To bind additional or newer services to the client, pass the service descriptor to client.service(SomeService).

Transport management

Custom transports bypass SDK credential resolution and token renewal. Use the services provided by Client.

Authentication and credentials

Credentials are resolved in the following order of precedence:

  1. credentials: An explicit credential source instance.
  2. apiKey: An API key string.
  3. JENNAH_API_KEY: Environment variable.
  4. Stored CLI session: Session credentials created by jnh login in ~/.config/jennah/credentials.

When an access token expires during a request, the client automatically requests a renewed token and retries the call. The updated session is written back to ~/.config/jennah/credentials to keep CLI commands and other client instances synchronized.

client.credential returns metadata describing the active credential type and source without exposing secrets.

Serving many users

A server handling requests on behalf of multiple users can share a single connection while supplying each user's access token:

import { Client, Connection, StaticSource } from "jennah-sdk-ts";

const connection = new Connection(); // one HTTP/2 connection, reused

function clientFor(accessToken: string): Client {
  return new Client({
    connection,
    credentials: new StaticSource(accessToken),
  });
}

A StaticSource token is passed as-is and is not renewed by the SDK. Closing a client leaves a shared connection open; call connection.close() when the server shuts down.

Error handling

Remote service failures reject with a ConnectError carrying the gRPC status. Use code(err) to read status codes uniformly across SDK errors and service errors:

import { Code, code } from "jennah-sdk-ts";

try {
  await client.agents.getAgent({ agentInstanceId: "no-such-agent" });
} catch (err) {
  if (code(err) === Code.NotFound) {
    // ...
  }
}

Authentication and credential resolution failures reject with dedicated SDK errors:

  • NoCredentialError: No credentials were found across configured sources.
  • CorruptSessionError: Stored session file cannot be parsed.
  • SessionExpiredError: Stored session has expired and cannot be refreshed.
  • CredentialRefusedError: Server rejected the supplied API key.
  • SessionPersistError: A renewed session could not be written back to the credentials file.

Calls safe to retry are automatically repeated on Unavailable status: read operations, and writes that supply an idempotency key (such as commitData with an idempotencyKey). Pass retry: { disabled: true } to disable retries, or configure maxAttempts to change the limit.

Examples

  • memchat (TypeScript): Interactive chatbot built on Client, showing semantic recall, formMemory with formation keys and per-call deadlines, and how to read a formation receipt. (GitHub)