Skip to content

Python SDK

The jennah-sdk-py package provides Python bindings for the Jennah gRPC API, offering both synchronous and asynchronous clients.

pip install jennah-sdk-py

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 uuid

from jennah import Client
from jennah.agent.v1 import agent_pb2, memory_pb2

with Client() as client:  # uses `jnh login` or $JENNAH_API_KEY
    agent_id = f"quickstart-{uuid.uuid4().hex[:8]}"
    client.agents.CreateAgent(
        agent_pb2.CreateAgentRequest(agent_instance_id=agent_id)
    )
    agent = client.agent(agent_id)

    # Store a vector chunk. Raw content is embedded automatically.
    agent.vectors.upsert(memory_pb2.VectorChunk(
        chunk_id="pref-1",
        raw_content="The customer prefers invoices in Japanese yen, "
        "sent on the 5th.",
    ))

    # Semantic search query.
    result = agent.vectors.search(memory_pb2.SemanticQuery(
        query_text="what currency does the customer want to be "
        "billed in?",
        limit=3,
    ))
    for m in result.matches:
        print(f"{m.distance:.3f}  {m.raw_content}")

    client.agents.DeleteAgent(
        agent_pb2.DeleteAgentRequest(agent_instance_id=agent_id)
    )
0.235  The customer prefers invoices in Japanese yen, sent on the 5th.

Synchronous and asynchronous clients

Both Client and AsyncClient expose identical service stubs and methods:

Client Runtime Example Call
Client Scripts, notebooks, evaluation harnesses, and synchronous workflows client.agents.ListAgents(req)
AsyncClient Asyncio applications, web frameworks, and agent runtimes await client.agents.ListAgents(req)

AsyncClient is built on grpc.aio and handles non-blocking I/O for all RPCs, including background credential renewal. For asyncio programs, use AsyncClient directly rather than executing Client in a thread executor.

import asyncio

from jennah import AsyncClient
from jennah.agent.v1 import memory_pb2


async def main():
    async with AsyncClient() as client:
        query = memory_pb2.SemanticQuery(
            query_text="billing preferences", limit=3
        )
        result = await client.agent("my-agent").vectors.search(query)
        print(result.matches)


asyncio.run(main())

Service stubs and agent helpers

API services are accessible directly as stubs bound to the authenticated connection:

Attribute 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

To bind additional or newer gRPC stubs to the authenticated channel, pass the stub class to client.stub(SomeServiceStub).

Channel management

Manual gRPC channels bypass SDK credential resolution and token refresh interceptors. Use stubs provided by Client or AsyncClient.

Agent memory helpers

client.agent(id) provides convenience helpers for single-section memory operations:

Helper Operation
memory.commit(**fields) Issues a CommitMemory request
memory.query(**fields) Issues a QueryMemory request
logs.create(step) / logs.recent(query) Execution log section operations
vectors.upsert(*chunks) / vectors.search(query) Vector section operations
graph.write(write) / graph.query(traversal) Graph section operations

Authentication and credentials

Credentials are resolved in the following order of precedence:

  1. credentials=: An explicit credentials provider instance.
  2. api_key=: 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 sensitive secrets.

Error handling

Authentication and credential resolution errors raise dedicated SDK exceptions:

  • jennah.NoCredentialError: No credentials were found across configured sources.
  • jennah.CorruptSessionError: Stored session file cannot be parsed.
  • jennah.SessionExpiredError: Stored session has expired and cannot be refreshed, or the server rejected an explicitly supplied token.
  • jennah.CredentialRefusedError: Server rejected the supplied API key.

Remote service failures raise grpc.RpcError. Use jennah.code(err) to extract gRPC status codes uniformly across SDK and gRPC exceptions.

Examples

  • memchat (Python): Interactive chatbot built on Client demonstrating semantic recall, FormMemory with formation keys and deadlines, and formation receipt processing. (GitHub)
  • LangChain adapter: LangChain BaseRetriever and memory formation integration built on AsyncClient, featuring an example agent with asynchronous background memory formation. (GitHub)