# TypeScript SDK Documentation

JamAI Base is a **backend-as-a-service for AI applications**. You define tables with columns that automatically process data through AI pipelines.

### Column Types

| Type      | Purpose              | Example                                        |
| --------- | -------------------- | ---------------------------------------------- |
| **Input** | Your data            | `dtype: "str"`, `"file"`, `"image"`, `"audio"` |
| **LLM**   | AI generates content | `gen_config: { model: "...", prompt: "..." }`  |

**Data Types**: `str` (text), `file` (generic), `image` (.jpeg/.jpg/.png/.gif/.webp), `audio` (.mp3/.wav)

### How It Works

{% stepper %}
{% step %}
Define a table with input + AI columns
{% endstep %}

{% step %}
Add a row with input data
{% endstep %}

{% step %}
AI columns auto-generate based on your prompts
{% endstep %}

{% step %}
Read the completed row with all outputs
{% endstep %}
{% endstepper %}

### Available Models

```typescript
// List all chat models
const chatModels = await jamai.llm.modelNames({
  capabilities: ["chat"],
});
console.log(chatModels.slice(0, 5)); // ['openai/gpt-4o', 'openai/gpt-4o-mini', ...]

// List embedding models
const embedModels = await jamai.llm.modelNames({
  capabilities: ["embed"],
});
console.log(embedModels); // ['ellm/BAAI/bge-m3', ...]

// Get full model info
const models = await jamai.llm.modelInfo();
for (const m of models.data.slice(0, 3)) {
  console.log(`${m.id}: context=${m.context_length || "N/A"}`);
}
```

### Row Structure

Every row returned from `listRows` contains:

```typescript
{
    'ID': 'uuid-string',           // Use for updates/deletes
    'Updated at': '2026-01-07...',  // Timestamp
    'column_name': { value: 'actual_data' },  // WRAPPED!
    ...
}
```

{% hint style="warning" %}
**Value Wrapping Context:**

* **SDK reads** (`listRows`, `getRow`): Values ARE wrapped → use `row['col'].value`
* Access values using: `row['column_name'].value` or the helper function below
  {% endhint %}

***

## QUICK REFERENCE

```typescript
// INSTALL
npm install jamaibase

// INITIALIZE
import JamAI from "jamaibase";

const jamai = new JamAI({
    token: "YOUR_PAT",
    projectId: "YOUR_PROJECT_ID"
});

// CRITICAL: Values are wrapped - ALWAYS extract
function getValue(field: any): any {
    if (field && typeof field === 'object' && 'value' in field) {
        return field.value;
    }
    return field;
}

// MAX LIMIT IS 100 - use pagination for more
```

***

## 1. SETUP

### Install

Node.js Version (>= 16.x)

```bash
npm install jamaibase
```

### Get Credentials

{% stepper %}
{% step %}
Sign up: <https://cloud.jamaibase.com/>
{% endstep %}

{% step %}
Create project
{% endstep %}

{% step %}
Get PAT key: Click on your user name on top right corner > [⚙ Account Settings](https://cloud.jamaibase.com/settings/account) > Create a Personal Access Token
{% endstep %}

{% step %}
Get Project ID: from project URL
{% endstep %}
{% endstepper %}

### Initialize Client

To start using the JamAI SDK, you need to create an instance of the client by passing a configuration object. Below are the configurable parameters:

| Parameter                 | Type          | Required | Description                                                                                                           |
| ------------------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `token`                   | string        | Yes\*    | Your Personal Access Token (PAT) to authenticate API requests.                                                        |
| `projectId`               | string        | Yes\*    | The ID of the Jamaibase project you want to interact with.                                                            |
| `baseURL`                 | string        | No       | Set a custom API endpoint (useful for self-hosted/OSS instances).                                                     |
| `maxRetries`              | number        | No       | Maximum number of times to retry a failed request (default: 0, i.e., no retries).                                     |
| `timeout`                 | number        | No       | Request timeout in milliseconds.                                                                                      |
| `httpClient`              | AxiosInstance | No       | Provide a custom Axios instance if you need advanced request handling.                                                |
| `dangerouslyAllowBrowser` | boolean       | No       | If `true`, allows use in browser environments (only for advanced/OSS use). **Not recommended due to security risks.** |
| `userId`                  | string        | No       | Optionally set a user ID for multi-user or impersonation scenarios.                                                   |

**Note**: Both `token` and `projectId` are required unless `baseURL` is specified for OSS/self-hosted use, in which case you may override authentication per your server's configuration.

#### Example Usage

```typescript
import JamAI from "jamaibase";

// Standard usage with required credentials
const jamai = new JamAI({
  token: "YOUR_PAT",
  projectId: "YOUR_PROJECT_ID",
});

// Specify a custom API endpoint (for OSS/self-hosted setups)
const jamaiCustom = new JamAI({
  baseURL: "http://localhost:6969",
  token: "YOUR_PAT",
  projectId: "YOUR_PROJECT_ID",
});

// With optional advanced settings
const jamaiWithOptions = new JamAI({
  token: "YOUR_PAT",
  projectId: "YOUR_PROJECT_ID",
  maxRetries: 3,
  timeout: 10000,
});
```

#### Example .env File

You may wish to keep your credentials out of your source code by using environment variables:

```env
JAMAI_API_KEY=your_PAT
JAMAI_PROJECT_ID=your_project_id

# Optional
JAMAI_API_BASE=https://api.jamaibase.com
```

> ⚠️ You must ensure you pass the config to the SDK in your code when using environment variables:
>
> ```typescript
> const jamai = new JamAI({
>   token: process.env.JAMAI_API_KEY!,
>   projectId: process.env.JAMAI_PROJECT_ID!,
> });
> ```

***

## 2. TABLE TYPES

| Type        | Use Case                       | Create Method            |
| ----------- | ------------------------------ | ------------------------ |
| `action`    | AI chains, document processing | `createActionTable()`    |
| `knowledge` | RAG, embeddings, vector search | `createKnowledgeTable()` |
| `chat`      | Conversational AI with context | `createChatTable()`      |

***

## 3. ACTION TABLES (Most Common)

### Create

```typescript
const table = await jamai.table.createActionTable({
  id: "my_table",
  cols: [
    // Input column
    {
      id: "input",
      dtype: "str",
    },

    // File input
    {
      id: "image",
      dtype: "file",
    },

    // LLM output column
    {
      id: "output",
      dtype: "str",
      gen_config: {
        model: "openai/gpt-4o-mini",
        system_prompt: "You are helpful.",
        prompt: "Process: ${input}\nImage: ${image}",
        temperature: 0.7,
        max_tokens: 500,
      },
    },
  ],
});
```

### Column Reference Syntax

Use `${column_name}` in prompts to reference other columns. At runtime, each reference is replaced with the corresponding cell value from the current row.

```typescript
// Example prompt
prompt: 'Translate "${input}" into Italian:';

// If input column contains "Good morning", actual prompt sent to LLM:
// "Translate \"Good morning\" into Italian:"
```

### How LLM Columns Work

{% stepper %}
{% step %}
Gather prompts — System Prompt and Prompt (which can reference upstream columns).
{% endstep %}

{% step %}
Optional RAG — Augment prompt with references from a Knowledge Table.
{% endstep %}

{% step %}
Send to LLM — With your chosen generation settings (model, temperature, max\_tokens).
{% endstep %}

{% step %}
Write response — Model's response becomes the cell value.
{% endstep %}
{% endstepper %}

### LLM Generation Settings

| Parameter       | Description                                                             |
| --------------- | ----------------------------------------------------------------------- |
| `model`         | LLM model to use (e.g., `openai/gpt-4o-mini`)                           |
| `system_prompt` | Passed as-is as system message. Define role, style, global instructions |
| `prompt`        | Main user message with `${column}` references                           |
| `temperature`   | Controls randomness (0.0-2.0)                                           |
| `max_tokens`    | Maximum output length                                                   |

### RAG (Retrieval Augmented Generation)

Link an LLM column to a Knowledge Table for grounded responses. See [Section 9](file:///#9-knowledge-tables-rag) for full Knowledge Table setup.

{% stepper %}
{% step %}
Formulate query — LLM generates retrieval query from your Prompt
{% endstep %}

{% step %}
Retrieve — Fetch relevant rows from Knowledge Table
{% endstep %}

{% step %}
Rerank — Optional reranking model (RRF Ranker by default)
{% endstep %}

{% step %}
Inject — Top-k references added to prompt
{% endstep %}

{% step %}
Cite — Optional inline citations: `[@ref0; @ref1; @ref2]`
{% endstep %}
{% endstepper %}

```typescript
{
    id: "answer",
    dtype: "str",
    gen_config: {
        model: "openai/gpt-4o-mini",
        prompt: "${question}",
        rag_params: {
            table_id: "my_knowledge_table",  // Must exist (see Section 9)
            k: 3,  // Number of references to inject
            // reranking_model: "...",  // Optional
        },
        max_tokens: 500
    }
}
```

### Prompting Tips

Separate column references using XML tags or Markdown headings:

```typescript
// XML tags (recommended)
prompt: `
<user-query>
\${input}
</user-query>

Translate user query into Italian.
`;

// Markdown headings
prompt: `

# User Query
\${input}

# Instruction
Translate user query into Italian.
`;
```

***

## 4. ADD ROWS

### Non-Streaming (Wait for Complete Response)

```typescript
const response = await jamai.table.addRow({
  table_type: "action",
  table_id: "my_table",
  data: [{ input: "Hello world" }, { input: "Goodbye world" }],
  concurrent: false,
});

// Get LLM output
console.log(
  response?.rows?.[0]?.columns["output"]?.choices[0]?.message?.content
);
```

### Streaming (Real-time Output)

```typescript
const stream = await jamai.table.addRowStream({
  table_type: "action",
  table_id: "my_table",
  data: [{ input: "Hello" }],
});

// Format: Async iterator-style for cleaner usage
for await (const value of stream) {
  if (value.object === "gen_table.completion.chunk") {
    console.log(value.choices?.[0]?.message?.content);
  }
}
```

### With File Upload

```typescript
// Upload file first
const fileResponse = await jamai.file.uploadFile({
  file_path: "/path/to/image.png",
});

// Use URI in row
await jamai.table.addRow({
  table_type: "action",
  table_id: "my_table",
  data: [
    {
      image: fileResponse.uri,
      input: "Describe this",
    },
  ],
  concurrent: false,
});
```

### Get Row ID After Adding (Non-Streaming)

```typescript
const response = await jamai.table.addRow({
  table_type: "action",
  table_id: "my_table",
  data: [{ input: "Hello" }],
  concurrent: false,
});

// Get the row ID for later updates/deletes
const rowId = response.rows[0]?.row_id;
console.log(`Created row: ${rowId}`);

// Get LLM output
const output =
  response.rows[0]?.columns["output"]?.choices[0]?.message?.content;
```

### Get Row ID After Adding (Streaming)

```typescript
const stream = await jamai.table.addRowStream({
  table_type: "action",
  table_id: "my_table",
  data: [{ input: "Hello" }],
});

let rowId: string | null = null;

for await (const value of stream) {
  if (value && "row_id" in value && value.row_id) {
    rowId = value.row_id;
  }

  if (
    value.object === "gen_table.completion.chunk" &&
    value.choices?.[0]?.message?.content
  ) {
    console.log(value.choices[0].message.content);
  }
}

console.log(`\nRow ID: ${rowId}`);
```

***

## 5. READ ROWS

### Basic List

```typescript
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "my_table",
  offset: 0,
  limit: 100, // MAX IS 100!
});

for (const row of rows.items) {
  // IMPORTANT: Extract value from wrapper
  const value = row["input"].value; // or use getValue()
  console.log(value);
}
```

### With WHERE Filter

```typescript
// Syntax: "column" (double quotes) = 'value' (single quotes)
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "my_table",
  where: "\"status\" = 'active'",
});

// LIKE pattern
// where: '"name" LIKE \'%Smith%\''

// AND conditions
// where: '"status" = \'active\' AND "type" = \'premium\''
```

### Select Specific Columns

```typescript
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "my_table",
  columns: ["input", "output"], // ID, Updated at always included
});
```

### Full-Text Search

```typescript
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "my_table",
  search_query: "machine learning",
});
```

### Pagination (REQUIRED for >100 rows)

```typescript
import { TableTypes } from "@/resources/gen_tables/tables";
async function getAllRows(tableId: string, tableType: TableTypes = "action") {
  const allRows: any[] = [];
  let offset = 0;

  while (true) {
    const response = await jamai.table.listRows({
      table_type: tableType,
      table_id: tableId,
      offset: offset,
      limit: 100,
    });

    allRows.push(...response.items);

    if (response.items.length < 100) {
      break;
    }

    offset += 100;
  }

  return allRows;
}
```

### Get Single Row

```typescript
const row = await jamai.table.getRow({
  table_type: "action",
  table_id: "my_table",
  row_id: "row-uuid",
});
```

***

## 6. UPDATE ROWS

### Basic Update

```typescript
await jamai.table.updateRows({
  table_type: "action",
  table_id: "my_table",
  data: {
    "row-uuid-1": { column1: "new_value" },
    "row-uuid-2": { column1: "value", column2: "value2" },
  },
});
```

### Regenerate Rows (Non-Streaming)

```typescript
// List rows to get row IDs
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "my_table",
});

const rowIds = rows.items.map((item) => item.ID);

// Regenerate rows
const response = await jamai.table.regenRow({
  table_type: "action",
  table_id: "my_table",
  row_ids: rowIds,
  concurrent: true,
});
```

### Regenerate Rows (Streaming)

```typescript
const stream = await jamai.table.regenRowStream({
  table_type: "action",
  table_id: "my_table",
  row_ids: rowIds,
  concurrent: true,
});

for await (const value of stream) {
  if (
    value.object === "gen_table.completion.chunk" &&
    value.choices?.[0]?.message?.content
  ) {
    console.log(value.choices[0].message.content);
  }
}
```

***

## 7. DELETE ROWS

```typescript
await jamai.table.deleteRows({
  table_type: "action",
  table_id: "my_table",
  row_ids: ["uuid1", "uuid2"],
});
```

***

## 8. TABLE OPERATIONS

### List Tables

```typescript
const tables = await jamai.table.listTables({
  table_type: "action",
  count_rows: true,
});

for (const t of tables.items) {
  console.log(`${t.id}: ${t.num_rows} rows`);
}
```

### Get Schema

```typescript
const table = await jamai.table.getTable({
  table_type: "action",
  table_id: "my_table",
});

for (const col of table.cols) {
  console.log(`${col.id}: ${col.dtype}`);
}
```

### Delete Table

```typescript
await jamai.table.deleteTable({
  table_type: "action",
  table_id: "my_table",
});
```

### Duplicate Table

```typescript
// With data
const newTable = await jamai.table.duplicateTable({
  table_type: "action",
  table_id_src: "source",
  table_id_dst: "copy",
  include_data: true,
});

// Schema only
const schemaOnly = await jamai.table.duplicateTable({
  table_type: "action",
  table_id_src: "source",
  table_id_dst: "copy",
  include_data: false,
});
```

### Rename Table

```typescript
const renamedTable = await jamai.table.renameTable({
  table_type: "action",
  table_id_src: "old_name",
  table_id_dst: "new_name",
});
```

### Column Management

```typescript
// Add columns
const updatedTable = await jamai.table.addActionColumns({
  id: "my_table",
  cols: [{ id: "new_column", dtype: "str" }],
});

// Rename columns
await jamai.table.renameColumns({
  table_type: "action",
  table_id: "my_table",
  column_map: {
    old_name: "new_name",
  },
});

// Reorder columns
await jamai.table.reorderColumns({
  table_type: "action",
  table_id: "my_table",
  column_names: ["col1", "col2", "col3"],
});

// Drop columns
await jamai.table.dropColumns({
  table_type: "action",
  table_id: "my_table",
  column_names: ["col_to_remove"],
});
```

### Hybrid Search

```typescript
const results = await jamai.table.hybridSearch({
  table_type: "action",
  table_id: "my_table",
  query: "search term",
  limit: 10,
  metric: "dot",
  reranking_model: null,
});

for (const result of results) {
  console.log(result);
}
```

### Import/Export Data

```typescript
// Export table data to CSV
const csvData = await jamai.table.exportTableData({
  table_type: "action",
  table_id: "my_table",
});
// csvData is a Uint8Array containing CSV data

// Export table data to TSV
const tsvData = await jamai.table.exportTableData({
  table_type: "action",
  table_id: "my_table",
  delimiter: "\t",
});

// Import table data from CSV file
const importResponse = await jamai.table.importTableData({
  file_path: "/path/to/data.csv",
  table_id: "my_table",
  table_type: "action",
});
console.log(importResponse.rows.length);

// Import with streaming
const importStream = await jamai.table.importTableDataStream({
  file_path: "/path/to/data.csv",
  table_id: "my_table",
  table_type: "action",
});

const reader = importStream.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(value);
}
```

### Progress Tracking for Long Operations

Track progress of long-running operations like table imports:

```typescript
import { PROGRESS_STATES } from "jamaibase";

// Get current progress
const progress = await jamai.tasks.getProgress("key");
console.log(`Progress: ${progress.state}`);

// Poll for completion
const result = await jamai.tasks.pollProgress("key", {
  initialWait: 0.5, // Initial wait in seconds
  maxWait: 60, // Maximum wait time in seconds
  verbose: true, // Log progress updates
});

if (result?.state === PROGRESS_STATES.COMPLETED) {
  console.log("Import completed successfully!");
} else if (result?.state === PROGRESS_STATES.FAILED) {
  console.error(`Import failed: ${result.error}`);
} else {
  console.log("Import timed out");
}
```

**Available Progress States:**

* `PROGRESS_STATES.PENDING` - Task is queued
* `PROGRESS_STATES.RUNNING` - Task is in progress
* `PROGRESS_STATES.COMPLETED` - Task completed successfully
* `PROGRESS_STATES.FAILED` - Task failed with error

***

## 9. KNOWLEDGE TABLES (RAG)

### Create

```typescript
const table = await jamai.table.createKnowledgeTable({
  id: "my_kb",
  cols: [], // Title, Text auto-created
  embedding_model: "ellm/BAAI/bge-m3",
});
```

### Add Data

```typescript
await jamai.table.addRow({
  table_type: "knowledge",
  table_id: "my_kb",
  data: [
    {
      Title: "Doc1",
      Text: "Content here...",
    },
  ],
  concurrent: false,
});
```

### Embed File

```typescript
import { File } from "formdata-node";

// Create a File object
const file = new File(
  ["I bought a Mofusand book in 2024.\n\nI went to Italy in 2018."],
  "text.txt",
  { type: "text/plain" }
);

// Embed the file
const response = await jamai.table.embedFile({
  file: file,
  table_id: "my_kb",
});

console.log(response.ok); // true
```

### Create RAG Action Table

```typescript
const table = await jamai.table.createActionTable({
  id: "rag_qa",
  cols: [
    { id: "question", dtype: "str" },
    {
      id: "answer",
      dtype: "str",
      gen_config: {
        model: "openai/gpt-4o-mini",
        prompt: "${question}",
        rag_params: {
          table_id: "my_kb", // Link to Knowledge Table
          k: 3, // Top k chunks
        },
        max_tokens: 200,
      },
    },
  ],
});
```

***

## 10. CHAT TABLES

### Create

```typescript
const table = await jamai.table.createChatTable({
  id: "my_chatbot",
  cols: [
    { id: "User", dtype: "str" },
    {
      id: "AI",
      dtype: "str",
      gen_config: {
        model: "openai/gpt-4o-mini",
        system_prompt: "You are helpful.",
        max_tokens: 500,
      },
    },
  ],
});
```

### Chat (Streaming)

```typescript
const stream = await jamai.table.addRowStream({
  table_type: "chat",
  table_id: "my_chatbot",
  data: [{ User: "Hello!" }],
});

for await (const value of stream) {
  if (
    value.object === "gen_table.completion.chunk" &&
    value.choices?.[0]?.message?.content
  ) {
    console.log(value.choices[0].message.content);
  }
}
```

### How Chat History Works

Chat tables **automatically maintain conversation history**. Each row added becomes part of the context for subsequent rows.

```typescript
// Turn 1
await jamai.table.addRow({
  table_type: "chat",
  table_id: "my_chatbot",
  data: [{ User: "My name is Alice" }],
  concurrent: false,
});

// Turn 2 - AI remembers the name from Turn 1
await jamai.table.addRow({
  table_type: "chat",
  table_id: "my_chatbot",
  data: [{ User: "What's my name?" }],
  concurrent: false,
});
// AI will respond: "Your name is Alice"

// View conversation history (getValue defined in Quick Reference)
const rows = await jamai.table.listRows({
  table_type: "chat",
  table_id: "my_chatbot",
  limit: 100,
});

for (const row of rows.items) {
  console.log(`User: ${getValue(row["User"])}`);
  console.log(`AI: ${getValue(row["AI"])}\n`);
}
```

**Note**: Each chat table is a separate conversation. Create multiple tables for multiple users/sessions.

***

## 11. FILE OPERATIONS

### Upload

```typescript
// Upload by file path
const fileResponse = await jamai.file.uploadFile({
  file_path: "/path/to/file.png",
});
const s3Uri = fileResponse.uri; // s3://devcloud-file/...

// Upload audio file
const audioUpload = await jamai.file.uploadFile({
  file_path: "/path/to/audio.mp3",
});
console.log(audioUpload.uri);
```

### Get Presigned URLs

```typescript
// Get raw URLs for uploaded files
const rawUrls = await jamai.file.getRawUrls({
  uris: [fileResponse.uri],
});
console.log(rawUrls.urls[0]);

// Get thumbnail URLs for uploaded images
const thumbUrls = await jamai.file.getThumbUrls({
  uris: [fileResponse.uri],
});
console.log(thumbUrls.urls[0]);
```

***

## 12. DIRECT API (No Tables)

### Chat Completions (Non-Streaming)

```typescript
const completion = await jamai.llm.generateChatCompletions({
  model: "openai/gpt-4o-mini",
  messages: [
    { role: "system", content: "You are helpful." },
    { role: "user", content: "Hello" },
  ],
  max_tokens: 100,
  temperature: 0.1,
  top_p: 0.1,
});

console.log(completion.choices[0]?.message?.content);
```

### Chat Completions (Streaming)

```typescript
const stream = await jamai.llm.generateChatCompletionsStream({
  model: "openai/gpt-4o-mini",
  messages: [
    { role: "system", content: "You are a concise assistant." },
    { role: "user", content: "What is a llama?" },
  ],
  temperature: 0.001,
  top_p: 0.001,
  max_tokens: 10,
});

for await (const value of stream) {
  if (
    value.object === "chat.completion.chunk" &&
    value?.choices[0]?.delta?.content
  ) {
    console.log(value.choices[0].delta.content);
  }
}
```

### Embeddings

```typescript
const texts = ["What is love?", "What is a llama?"];

const embeddings = await jamai.llm.generateEmbeddings({
  model: "ellm/BAAI/bge-m3",
  input: texts,
});

// Inspect one of the embeddings
console.log(embeddings.data[0]?.embedding.slice(0, 3));

// Print the text and its embedding
for (let i = 0; i < texts.length; i++) {
  console.log(texts[i], embeddings.data[i]?.embedding.slice(0, 3));
}
```

### Model Info

```typescript
// Get all model info
const models = await jamai.llm.modelInfo();
const model = models.data[0];
console.log(`Model: ${model?.id}  Context length: ${model?.context_length}`);

// Get specific model info
const specificModel = await jamai.llm.modelInfo({
  model: "openai/gpt-4o",
});
console.log(specificModel.data[0]);

// Filter based on capability: "chat", "embed", "rerank", "image"
const chatModels = await jamai.llm.modelInfo({
  capabilities: ["chat"],
});
for (const model of chatModels.data) {
  console.log(model);
}

const embedModels = await jamai.llm.modelInfo({
  capabilities: ["embed"],
});
for (const model of embedModels.data) {
  console.log(model);
}

const rerankModels = await jamai.llm.modelInfo({
  capabilities: ["rerank"],
});
for (const model of rerankModels.data) {
  console.log(model);
}

// Get model IDs/names
const modelNames = await jamai.llm.modelNames();
console.log(modelNames);

// Model IDs with the preferred model at the top if available
const preferredModels = await jamai.llm.modelNames({
  prefer: "openai/gpt-4o",
});
console.log(preferredModels[0]);

// Filter based on capability
const chatModelNames = await jamai.llm.modelNames({
  capabilities: ["chat"],
});
console.log(chatModelNames);
```

***

## 13. ORGANIZATIONS & PROJECTS

### Organizations

```typescript
// Create organization
const org = await jamai.organizations.createOrganization({
  name: "My Organization",
});
console.log(org.id, org.name);

// List organizations
const orgs = await jamai.organizations.listOrganizations({});
for (const org of orgs.items) {
  console.log(org.id, org.name);
}

// List organizations with pagination
const paginatedOrgs = await jamai.organizations.listOrganizations({
  limit: 10,
  offset: 0,
});

// Get specific organization
const specificOrg = await jamai.organizations.getOrganization(org.id);
console.log(specificOrg);

// Update organization
const updatedOrg = await jamai.organizations.updateOrganization(org.id, {
  name: "Updated Organization Name",
});
console.log(updatedOrg.name);

// Delete organization
const deleteResponse = await jamai.organizations.deleteOrganization(org.id);
console.log(deleteResponse.ok); // true

// List organization members
const members = await jamai.organizations.listMembers(org.id, {});
for (const member of members.items) {
  console.log(member.user_id, member.role);
}

// Get specific member
const currentUser = await jamai.users.getUser();
const member = await jamai.organizations.getMember(currentUser.id, org.id);
console.log(member.role);

// Get model catalogue for organization
const catalogue = await jamai.organizations.modelCatalogue(org.id, {});
for (const model of catalogue.items) {
  console.log(model.id);
}

// Create organization invite
const invite = await jamai.organizations.createInvite({
  user_email: "user@example.com",
  organization_id: org.id,
  role: "MEMBER",
  valid_days: 7,
});
console.log(invite.id);

// List organization invites
const invites = await jamai.organizations.listInvites(org.id, {});
for (const invite of invites.items) {
  console.log(invite.user_email, invite.role);
}

// Revoke organization invite
const revokeResponse = await jamai.organizations.revokeInvite(invite.id);
console.log(revokeResponse.ok); // true

// Refresh organization quota
const refreshedOrg = await jamai.organizations.refreshQuota(org.id);
console.log(refreshedOrg.quota_reset_at);
```

### Usage & Billing Metrics

Monitor usage and costs for your organization:

```typescript
// Get LLM usage metrics
const fromDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(); // 7 days ago
const toDate = new Date().toISOString();

const llmMetrics = await jamai.meters.getUsageMetrics({
  type: "llm",
  from: fromDate,
  to: toDate,
  windowSize: "1d", // Options: "1h", "1d", "7d"
  orgIds: [org.id],
  groupBy: ["org_id"],
});
console.log("LLM Usage:", llmMetrics.data);

// Get embedding usage metrics
const embeddingMetrics = await jamai.meters.getUsageMetrics({
  type: "embedding",
  from: fromDate,
  to: toDate,
  windowSize: "1d",
  orgIds: [org.id],
});

// Get reranking usage metrics
const rerankingMetrics = await jamai.meters.getUsageMetrics({
  type: "reranking",
  from: fromDate,
  to: toDate,
  windowSize: "1d",
  orgIds: [org.id],
});

// Get billing metrics (cost information)
const billingMetrics = await jamai.meters.getBillingMetrics({
  from: fromDate,
  to: toDate,
  windowSize: "1d",
  orgIds: [org.id],
});
console.log("Billing:", billingMetrics.data);

// Get bandwidth metrics
const bandwidthMetrics = await jamai.meters.getBandwidthMetrics({
  from: fromDate,
  to: toDate,
  windowSize: "1d",
  orgIds: [org.id],
});

// Get storage metrics
const storageMetrics = await jamai.meters.getStorageMetrics({
  from: fromDate,
  to: toDate,
  windowSize: "1d",
  orgIds: [org.id],
});
```

**Window Size Options:**

* `"1h"` - Hourly metrics
* `"1d"` - Daily metrics
* `"7d"` - Weekly metrics

**Group By Options:**

* `["org_id"]` - Group by organization
* `["project_id"]` - Group by project
* `["model"]` - Group by model (for LLM metrics)

### Projects

```typescript
// Create project
const project = await jamai.projects.createProject({
  organization_id: org.id,
  name: "My Project",
});
console.log(project.id, project.name);

// List projects
const projects = await jamai.projects.listProjects(org.id, {});
for (const project of projects.items) {
  console.log(project.id, project.name);
}

// List projects with pagination
const paginatedProjects = await jamai.projects.listProjects(org.id, {
  limit: 10,
  offset: 0,
});

// Get specific project
const specificProject = await jamai.projects.getProject(project.id);
console.log(specificProject);

// Update project
const updatedProject = await jamai.projects.updateProject(project.id, {
  name: "Updated Project Name",
  description: "Updated description",
});
console.log(updatedProject.name, updatedProject.description);

// Delete project
const deleteProjectResponse = await jamai.projects.deleteProject(project.id);
console.log(deleteProjectResponse.ok); // true

// List project members
const projectMembers = await jamai.projects.listMembers(project.id, {});
for (const member of projectMembers.items) {
  console.log(member.user_id, member.role);
}

// Get specific project member
const projectMember = await jamai.projects.getMember(
  currentUser.id,
  project.id
);
console.log(projectMember.role);

// Create project invite
const projectInvite = await jamai.projects.createInvite({
  user_email: "user@example.com",
  project_id: project.id,
  role: "MEMBER",
  valid_days: 7,
});
console.log(projectInvite.id);

// List project invites
const projectInvites = await jamai.projects.listInvites(project.id, {});
for (const invite of projectInvites.items) {
  console.log(invite.user_email, invite.role);
}

// Revoke project invite
const revokeProjectInvite = await jamai.projects.revokeInvite(projectInvite.id);
console.log(revokeProjectInvite.ok); // true

// Export project
const exportData = await jamai.projects.exportProject(project.id);
// exportData is a Uint8Array containing the exported project data
console.log(exportData.length);
```

***

## 14. USERS & AUTHENTICATION

```typescript
// Get current user
const currentUser = await jamai.users.getUser();
console.log(currentUser.id, currentUser.name, currentUser.email);

// List users
const users = await jamai.users.listUsers({});
for (const user of users.items) {
  console.log(user.id, user.name);
}

// List users with pagination
const paginatedUsers = await jamai.users.listUsers({
  limit: 10,
  offset: 0,
});

// Update current user
const updatedUser = await jamai.users.updateUser({
  name: "Updated Name",
});
console.log(updatedUser.name);

// Create personal access token (PAT)
const pat = await jamai.users.createPat({
  name: "My API Token",
});
console.log(pat.id, pat.name);

// List personal access tokens
const pats = await jamai.users.listPats({});
for (const token of pats.items) {
  console.log(token.id, token.name);
}

// Update personal access token
const updatedPat = await jamai.users.updatePat(pat.id, {
  name: "Updated Token Name",
});
console.log(updatedPat.name);

// Delete personal access token
const deletePat = await jamai.users.deletePat(pat.id);
console.log(deletePat.ok); // true

// Create email verification code
const verificationCode = await jamai.users.createEmailVerificationCode();
console.log(verificationCode.id);

// List email verification codes
const codes = await jamai.users.listEmailVerificationCodes({});
for (const code of codes.items) {
  console.log(code.id);
}

// Get specific email verification code
const specificCode = await jamai.users.getEmailVerificationCode(
  verificationCode.id
);
console.log(specificCode);

// Revoke email verification code
const revokeCode = await jamai.users.revokeEmailVerificationCode(
  verificationCode.id
);
console.log(revokeCode.ok); // true
```

***

## 15. SECRETS MANAGEMENT

Manage secrets and API keys at the organization level.

```typescript
// Create secret
const secret = await jamai.secrets.createSecret(
  {
    name: "MY_API_KEY",
    value: "secret-value-here",
  },
  org.id
);
console.log(secret.name, secret.organization_id);

// Create secret with allowed projects
const secretWithProjects = await jamai.secrets.createSecret(
  {
    name: "PROJECT_API_KEY",
    value: "secret-value",
    allowed_projects: [project.id],
  },
  org.id
);

// List secrets
const secrets = await jamai.secrets.listSecrets(org.id, {});
for (const secret of secrets.items) {
  console.log(secret.name, secret.value); // value is masked
}

// List secrets with pagination
const paginatedSecrets = await jamai.secrets.listSecrets(org.id, {
  limit: 10,
  offset: 0,
});

// Get specific secret
const specificSecret = await jamai.secrets.getSecret(org.id, "MY_API_KEY");
console.log(specificSecret.value); // value is masked

// Update secret
const updatedSecret = await jamai.secrets.updateSecret(org.id, "MY_API_KEY", {
  value: "new-secret-value",
});
console.log(updatedSecret.value); // value is unmasked on update

// Delete secret
const deleteSecret = await jamai.secrets.deleteSecret(org.id, "MY_API_KEY");
console.log(deleteSecret.ok); // true
```

{% hint style="info" %}
**Secret names must:**

* Start with a letter or underscore
* Contain only alphanumeric characters and underscores
* Be uppercase (automatically converted)
  {% endhint %}

***

## 16. TEMPLATES

Templates provide pre-built table configurations that you can use as starting points:

```typescript
// List available templates
const templates = await jamai.template.listTemplates();
for (const template of templates.items) {
  console.log(`Template: ${template.id} - ${template.name}`);
}

// Get template details
const template = await jamai.template.getTemplate({
  template_id: "template_id",
});
console.log(template);

// List tables in a template
const tables = await jamai.template.listTables({
  template_id: "template_id",
  table_type: "action",
});
for (const table of tables.items) {
  console.log(`Table: ${table.id}`);
}

// Get specific table from template
const table = await jamai.template.getTable({
  template_id: "template_id",
  table_type: "action",
  table_id: "table_id",
});
console.log(table);

// List rows in a template table
const rows = await jamai.template.listTableRows({
  template_id: "template_id",
  table_type: "action",
  table_id: "table_id",
});
for (const row of rows.items) {
  console.log(row);
}
```

**Use Cases:**

* Explore pre-built table configurations
* Learn best practices for table design
* Quick-start with proven table structures
* Browse example data and prompts

## 17. CONVERSATIONS

Manage conversations with AI agents (Chat Tables).

```typescript
// Create a chat table (agent) first
const agent = await jamai.table.createChatTable({
  id: "my-agent",
  cols: [
    { id: "User", dtype: "str" },
    {
      id: "AI",
      dtype: "str",
      gen_config: {
        model: "openai/gpt-4o-mini",
        system_prompt: "You are a helpful assistant.",
      },
    },
  ],
});

// List agents
const agents = await jamai.conversations.listAgents({});
for (const agent of agents.items) {
  console.log(agent.conversation_id, agent.title);
}

// Get specific agent
const agentDetails = await jamai.conversations.getAgent("my-agent");
console.log(agentDetails.agent_id, agentDetails.title);

// Create a conversation
const conversationStream = await jamai.conversations.createConversation({
  agent_id: "my-agent",
  title: "My Conversation",
  data: {},
});

// Read the stream to get conversation ID
const reader = conversationStream.getReader();
let conversationId: string | null = null;

try {
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    if (value && typeof value === "object" && "conversation_id" in value) {
      conversationId = value.conversation_id as string;
      break;
    }
  }
} finally {
  reader.releaseLock();
}

// List conversations
const conversations = await jamai.conversations.listConversations({});
for (const conv of conversations.items) {
  console.log(conv.conversation_id, conv.title);
}

// List conversations with limit
const limitedConversations = await jamai.conversations.listConversations({
  limit: 10,
});

// Get specific conversation
const conversation = await jamai.conversations.getConversation(conversationId!);
console.log(conversation.title);

// Rename conversation title
const updatedConv = await jamai.conversations.renameConversationTitle(
  conversationId!,
  "Updated Title"
);
console.log(updatedConv.title);

// Send message to conversation
const messageStream = await jamai.conversations.sendMessage({
  conversation_id: conversationId!,
  data: { User: "Hello, how are you?" },
});

const messageReader = messageStream.getReader();
try {
  while (true) {
    const { done, value } = await messageReader.read();
    if (done) break;
    console.log(value);
  }
} finally {
  messageReader.releaseLock();
}

// List messages in a conversation
const messages = await jamai.conversations.listMessages(conversationId!, {});
console.log(messages);

// Get conversation threads
const threads = await jamai.conversations.getThreads(conversationId!);
console.log(threads.threads);

// Delete conversation
const deleteConv = await jamai.conversations.deleteConversation(
  conversationId!
);
console.log(deleteConv.ok); // true
```

***

## 18. COMPLETE EXAMPLE

End-to-end example: Create table, add row, read result, cleanup.

```typescript
import JamAI from "jamaibase";

// Initialize (auto-loads JAMAI_API_KEY, JAMAI_PROJECT_ID from env)
const jamai = new JamAI();

// Helper function (use throughout your code)
function getValue(field: any): any {
  if (field && typeof field === "object" && "value" in field) {
    return field.value;
  }
  return field;
}

async function main() {
  // 1. Create table with LLM column
  const TABLE_ID = "qa_demo";

  // Delete if exists
  try {
    await jamai.table.deleteTable({
      table_type: "action",
      table_id: TABLE_ID,
    });
  } catch (error) {
    // Table didn't exist, continue
  }

  await jamai.table.createActionTable({
    id: TABLE_ID,
    cols: [
      { id: "question", dtype: "str" },
      {
        id: "answer",
        dtype: "str",
        gen_config: {
          model: "openai/gpt-4o-mini",
          system_prompt: "You are a helpful assistant. Be concise.",
          prompt: "Question: ${question}",
          max_tokens: 100,
        },
      },
    ],
  });
  console.log(`Created table: ${TABLE_ID}`);

  // 2. Add row (non-streaming)
  const response = await jamai.table.addRow({
    table_type: "action",
    table_id: TABLE_ID,
    data: [{ question: "What is TypeScript?" }],
    concurrent: false,
  });

  const rowId = response.rows[0]?.row_id;
  const answer =
    response.rows[0]?.columns["answer"]?.choices[0]?.message?.content;
  console.log(`Row ID: ${rowId}`);
  console.log(`Answer: ${answer}`);

  // 3. Read rows
  const rows = await jamai.table.listRows({
    table_type: "action",
    table_id: TABLE_ID,
    limit: 100,
  });

  for (const row of rows.items) {
    const q = getValue(row["question"]);
    const a = getValue(row["answer"]);
    console.log(`Q: ${q}\nA: ${a}\n`);
  }

  // 4. Cleanup
  await jamai.table.deleteTable({
    table_type: "action",
    table_id: TABLE_ID,
  });
  console.log("Cleanup complete");
}

main().catch(console.error);
```

***

## QUICK COPY-PASTE

```typescript
// === IMPORTS ===
import JamAI from "jamaibase";

// === INIT ===
const jamai = new JamAI(); // Auto-loads from JAMAI_API_KEY, JAMAI_PROJECT_ID env vars

// === HELPER (ALWAYS USE) ===
function getValue(field: any): any {
  if (field && typeof field === "object" && "value" in field) {
    return field.value;
  }
  return field;
}

// === ADD ROWS ===
const response = await jamai.table.addRow({
  table_type: "action",
  table_id: "TABLE",
  data: [{ col: "val" }],
  concurrent: false,
});
const rowId = response.rows[0]?.row_id;
const output =
  response.rows[0]?.columns["output_col"]?.choices[0]?.message?.content;

// === LIST ROWS (MAX 100!) ===
const rows = await jamai.table.listRows({
  table_type: "action",
  table_id: "TABLE",
  limit: 100,
});
for (const row of rows.items) {
  const value = getValue(row["column"]);
}

// === WITH WHERE FILTER ===
const filteredRows = await jamai.table.listRows({
  table_type: "action",
  table_id: "TABLE",
  where: "\"status\" = 'active'",
});

// === UPDATE ROWS ===
await jamai.table.updateRows({
  table_type: "action",
  table_id: "TABLE",
  data: {
    "row-id": { col: "new_val" },
  },
});

// === DELETE ROWS ===
await jamai.table.deleteRows({
  table_type: "action",
  table_id: "TABLE",
  row_ids: ["row-id-1", "row-id-2"],
});

// === FILE UPLOAD ===
const fileResp = await jamai.file.uploadFile({
  file_path: "/path/to/file.png",
});
const uri = fileResp.uri; // Use in row data

// === STREAMING ===
const stream = await jamai.table.addRowStream({
  table_type: "action",
  table_id: "TABLE",
  data: [{ col: "val" }],
});

for await (const value of stream) {
  if (
    value.object === "gen_table.completion.chunk" &&
    value.choices?.[0]?.message?.content
  ) {
    console.log(value.choices[0].message.content);
  }
}
```
