# 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);
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.jamaibase.com/developer-reference/typescript-sdk-documentation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
