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.
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();
}
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:
credentials: An explicit credential source instance.apiKey: An API key string.JENNAH_API_KEY: Environment variable.- Stored CLI session: Session credentials created by
jnh loginin~/.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,formMemorywith formation keys and per-call deadlines, and how to read a formation receipt. (GitHub)