# Minds Client Library

> Install @animocabrands/minds-client-lib and orchestrate Minds from your own Node.js app or service.

A lean TypeScript client for Node: typed messaging, reply waiting, and live events.

When you're ready to build on Minds: add this library to the server side of your project so your app can use your Minds. You keep shaping the product (screens, flows, what users see); your coding agent can wire up the connection in code using a clear, consistent interface instead of guessing at raw API calls.

## Install

Requires **Node 22+**.

```bash
npm install @animocabrands/minds-client-lib
```

## Create a client

```typescript
import  from "@animocabrands/minds-client-lib";

const client = createMindsClient();
```

## Minds List

`listMinds()` returns every Mind on your account (`mindId`, `name`, `model`, `species`, and related fields).

```typescript
const minds = await client.listMinds();
const mindId = minds[0]?.mindId;
```

`humanId` is resolved from your Builder API key automatically. Pass `listMinds()` when you need an explicit override.

## Conversations

Bind a stable **alias** (e.g. `main`) to a Mind before messaging:

```typescript
await client.ensureConversation("main", mindId);
```

`ensureConversation` is idempotent — if the alias already exists for that Mind, the existing conversation is returned.

Lower-level helpers when you manage aliases yourself:

```typescript
const conversations = await client.listConversations();
const conversation = await client.getConversation("main");
await client.createConversation();
```

## Send and history

```typescript
await client.sendMessage();

const rows = await client.getHistory("main", );
const after = rows.at(-1)?.fingerprint;
const newer = await client.getHistory("main", );
```

`sendMessage` requires `alias` and `messageText`. Optional `attachments` accept **outbound** objects — prefer a public HTTPS `url` with `fileName` and `mimeType`:

```typescript
await client.sendMessage({
  alias: "main",
  messageText: "Summarize this PDF in one sentence.",
  attachments: [
    {
      url: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
      fileName: "dummy.pdf",
      mimeType: "application/pdf",
      extension: "pdf",
    },
  ],
});
```

Image URLs use the same shape (`mimeType: "image/png"`, etc.). Mind **replies** on `getHistory`, `waitForReply`, and SSE events may include **inbound** artifacts — for example:

```ts
// One attachment on a Mind reply (PDF; artifact body truncated)
{
  artifactId: "7388b65d-144a-49ff-a4dc-cb7c23ded982",
  slug: "whale_watchtower_skill_artifact_1_0_5",
  logicalType: "document",
  mimeType: "application/pdf",
  extension: "pdf",
  artifact: "JVBERi0xLjQK...",
}
```

Outbound send uses `content` for inline payloads; inbound replies use `artifact` for the same role. `slug` and `logicalType` are optional strings, treat values as hints, not a fixed enum. See the [API reference](/docs/api) for field details.

`getLatestHistoryFingerprint` returns the fingerprint of the newest message — pass it as `after` on `getHistory` to fetch only newer rows, or as `afterFingerprint` before `waitForReply` so you spot replies that arrived after you sent.

Resolve which Mind an alias last talked to:

```typescript
const mindId = await client.getMindIdForAlias("main");
```

## Wait for a Mind reply

`waitForReply` listens on the live event stream first, then polls history until a reply arrives or the timeout hits.

```typescript
const before = await client.getLatestHistoryFingerprint("main");

await client.sendMessage();

const outcome = await client.waitForReply({
  alias: "main",
  timeoutMs: 180_000,
  afterFingerprint: before,
  sentMessageText: "Summarize our plan.",
});

if (!outcome.timedOut) {
  console.log(outcome.reply.messageText);
}
```

Use `isReplyEvent` from the package when you filter SSE or history rows yourself.

## Live events (SSE)

Subscribe with callbacks:

```typescript
const sub = client.subscribeEvents({
  alias: "main",
  onEvent: (event) => {
    console.log(event.messageText);
  },
  onError: (err) => console.error(err),
});

// later
sub.close();
```

Or consume the async iterator:

```typescript
for await (const event of client.eventsIterator()) {
  console.log(event.fingerprint, event.messageText);
}
```

Pass `signal` on iterator or subscribe options to cancel when your process shuts down.

## Errors

Failed HTTP calls throw `MindsApiError` with `status`, `code`, and `message`. Map 401/403 to a missing or revoked Builder API key; 429 may include retry guidance.

## Methods

| Area          | Methods                                                                                                 |
| ------------- | ------------------------------------------------------------------------------------------------------- |
| Account       | `listMinds`                                                                                             |
| Conversations | `createConversation`, `listConversations`, `getConversation`, `ensureConversation`, `getMindIdForAlias` |
| Messaging     | `sendMessage`, `getHistory`, `getLatestHistoryFingerprint`                                              |
| Replies       | `waitForReply`, `isReplyEvent`, `isReplyHistoryRow`                                                     |
| Events        | `subscribeEvents`, `eventsIterator`, `parseSseChunk`                                                    |

Types (`BuilderMind`, `Conversation`, `MessageRecord`, `MessagingEvent`, …) and `parseHumanIdFromBuilderApiKey` are exported from the package entry.
