# Elektric TypeScript SDK

Canonical documentation: [Quickstart](../../docs/getting-started.md) · [AI coding agents](../../docs/guides/ai-coding-agents.md) · [llms.txt](../../public/llms.txt)

One provider-neutral TypeScript interface for chat, media, tools, Web, jobs, and realtime.

## Install

```bash
npm install elektric-ai
```

This is the official [`elektric-ai` package on npm](https://www.npmjs.com/package/elektric-ai). Do not substitute a similarly named package.

## Configure and make a request

```ts
import { Elektric } from "elektric-ai";

const elektric = new Elektric({ apiKey: process.env.ELEKTRIC_API_KEY! });
const result = await elektric.chat({
  userId: "customer-456",
  conversationId: "support-123",
  message: "What is our refund policy?",
});
console.log(result.message, result.requestId);
```

The production URL, `https://elektric.ai`, is built in. `baseUrl` is available for development and testing. `elektric-auto` is implicit in this simple method. It does not send provider, retrieval, or Context controls, and the SDK never automatically retries an AI execution.

## Persistent conversations

```ts
const result = await elektric.chat({
  conversationId: "support-123",
  userId: "customer-456",
  message: "What about enterprise?",
});
```

Both IDs are required by the native beta chat method. The same `userId` and `conversationId` continues a thread; a new `conversationId` starts a new thread while retaining that user's durable Memory. Knowledge configured for the API-key project is used automatically when relevant.

```ts
const conversation = await elektric.conversations.get({ conversationId: "support-123" });
const recent = await elektric.conversations.list({ userId: "customer-456", limit: 20 });
await elektric.conversations.delete({ conversationId: "support-123" });
```

Conversation lists are newest-updated-first and cursor-paginated. GET returns up to 100 chronological messages; pass `messageCursor` to continue. Deleting a Conversation does not delete Memory, Knowledge, or other Conversations. A later chat may deterministically create a new thread with the same external ID.

Memory is durable user-specific information across Conversations. It remains automatic during chat. Inspect or correct it with `elektric.memory.list/get/update/delete`; these methods are scoped to the API-key project and require `userId`. Manual create is intentionally deferred because stable conceptual keys remain owned by the certified updater.

```ts
const memories = await elektric.memory.list({ userId: "customer-456" });
const card = await elektric.memory.get({ userId: "customer-456", memoryId: memories.data[0].id });
await elektric.memory.update({ userId: "customer-456", memoryId: card.id, summary: "User prefers concise prose." });
await elektric.memory.delete({ userId: "customer-456", memoryId: card.id });
```

Deleting Memory deactivates that card immediately but does not erase its source Conversation or prevent History from recalling legitimate past events. Conversation is the current thread, History finds details from older threads, and Knowledge contains project/company reference material.

## OpenAI-compatible requests

```ts
const raw = await elektric.chat.completions.create({
  model: "elektric-auto",
  conversation_id: "support-123",
  messages: [{ role: "user", content: "What about enterprise?" }],
});
```

The convenience result exposes normalized `text`, `id`, `usage`, and `requestId`, plus the original completion at `result.raw`. Direct HTTP and OpenAI-compatible clients use the same `/v1/chat/completions` backend.

## Streaming

```ts
for await (const event of elektric.chat.stream({ userId: "customer-456", conversationId: "support-123", message: "Explain our policy." })) {
  if (event.type === "text_delta") process.stdout.write(event.text);
}
```

Pass `signal` to cancel locally. Streaming accepts conversation and user IDs, but the current backend intentionally does not persist or inject conversation Context for streaming requests. Cancellation does not imply that upstream work or billing was stopped. The deprecated `chatStream()` alias remains for compatibility.

## Files and multimodal input

```ts
const file = await elektric.files.upload({ file: pdfBytes, mediaType: "application/pdf" });
const answer = await elektric.chat({ messages: [{ role: "user", content: [
  { type: "text", text: "Summarize this." },
  { type: "file", fileId: file.id },
] }] });
```

Use `files` for uploads and `assets` for normalized generated media metadata/downloads. Assets expose opaque Elektric IDs, never storage or upstream IDs.

## Tools and Web

```ts
const weather = elektric.tool<{ city: string }>({
  name: "weather", description: "Read the current weather.",
  inputSchema: { type: "object", properties: { city: { type: "string" } }, required: ["city"] },
});
const response = await elektric.chat({ messages, tools: [weather], web: true });
console.log(response.text, response.sources, response.toolCalls);
```

Your application authorizes and executes tool calls, then returns an `ElektricToolResult` in the next request. Elektric does not execute customer tools.



## Images, audio, video, and jobs

```ts
const image = (await elektric.images.generate({ prompt: "A lighthouse at sunrise" })).images[0];
const job = await elektric.video.generate({ image: image.fileId, prompt: "Slow camera push." });
const completed = await elektric.jobs.wait(job.id, { signal: abortController.signal });
```

Use `audio.transcribe`, `audio.speech`, `images.generate`, `images.edit`, `video.analyze`, and `video.generate`. Async operations return an `ElektricJob`; `job.wait()` is sugar for `elektric.jobs.wait(job.id)`.

## Embeddings and realtime

Default embedding usage is `elektric.embeddings.create({ input })`. Profiles are discoverable at `elektric.embeddingProfiles` and remain available at `elektric.embeddings.profiles` for compatibility. `elektric.realtime.connect()` returns a normalized session with `sendText`, `sendAudio`, `commitAudio`, `interrupt`, `on`, and `close`.

## Errors and runtimes

```ts
import { ElektricError } from "elektric-ai";
try { await elektric.chat({ messages }); }
catch (error) { if (error instanceof ElektricError) console.error(error.code, error.requestId); }
```

Errors expose safe Elektric `code`, `status`, `requestId`, and optional `details`; upstream errors are never returned. Supported environments are ESM, fetch-compatible Node.js 18+, Cloudflare Workers, and other server/edge runtimes with standard Web APIs. Realtime additionally requires WebSocket support. Use `ELEKTRIC_API_KEY` in server-side code. Never ship an Elektric secret key in a public browser bundle; a browser app should call your backend, which calls Elektric.

The native SDK is recommended for the complete Elektric platform. OpenAI compatibility is available for rapidly migrating existing OpenAI-compatible code. See [Elektric documentation](https://elektric.ai/docs).

## Knowledge management

Knowledge is project-level reference material used automatically when relevant. Use `knowledge.add`, `list`, `get`, and `delete`; poll until `status === "ready"`. Upload accepts Web bytes and Node Buffer with a filename/MIME type. Retry is deferred: delete and re-upload failed sources.

## Streaming Web sources

Pass `web: true` to `elektric.chat.stream()` or `chatStream()`. Streams emit normalized `source` events in addition to existing text/content and finish events. Sources may arrive before, during, or after text and are de-duplicated by URL; the underlying SSE ends after the finish chunk with `[DONE]`.
