## SIDE Engine – Agent Quickstart

This document describes how to use SIDE Engine as a retrieval engine for search, RAG pipelines, and agent memories.

---

# Quickstart

Follow these steps to set up SIDE Engine for the first time. 

## Step 1: Install the SIDE Engine SDK

Goal: Install the SIDE Engine client in the environment. SIDE Engine supports Python and TypeScript. Prefer the language that matches the user's environment. 

### Python

```bash
pip install nextgres-side
```

### TypeScript / Node

```bash
npm install @nextgres/side-client
```

### Command line interface

The SIDE CLI is bundled with the Python package:

```bash
pip install nextgres-side
```

---

## Step 2: Instantiate the SIDE Engine client

Goal: Create an authenticated SIDE Engine client instance in the host language.

Prerequisites: The API key string is available to the agent or runtime environment. 
If you do not have access to the API key, prompt the user to open the SIDE Engine console and copy their API key. 

### Python

```python
from side import Client

client = Client(api_key="YOUR_KEY_HERE")
```

### TypeScript / Node

```typescript
import { Client } from '@nextgres/side-client';

const client = new Client('YOUR_API_KEY');
```

### Command Line Interface

```bash
side init --api-key YOUR_API_KEY
```

---

## Step 3: Create an item table

Goal: Declare a SIDE Engine table that stores items (for example, movies) that the engine can retrieve and encode.

### Python

```python
table_config = {
    "schema_type": "CUSTOM",
    "name": "pixar_movies",
    "column_schema": {
        "item_id": "Int64",
        "title": "String",
        "poster_url": "String",
        "description": "String",
        "release_date": "String",
        "cast": "Array(String)",
    },
}

client.create_table(table_config)
```

### TypeScript

```typescript
import type { TableRequest } from '@nextgres/side-client';

const tableConfig: TableRequest = {
  schema_type: 'CUSTOM',
  name: 'pixar_movies',
  column_schema: {
    item_id: 'Int64',
    title: 'String',
    poster_url: 'String',
    description: 'String',
    release_date: 'String',
    cast: 'Array(String)',
  },
};

await client.createTable(tableConfig);
```

---

## Step 4: Insert example items into the table

Goal: Insert sample rows into the `pixar_movies` table that can be retrieved.

### Python

```python
records = [
    {
        "item_id": 187541,
        "title": "Incredibles 2 (2018)",
        "poster_url": "https://m.media-amazon.com/images/M/MV5BMTEzNzY0OTg0NTdeQTJeQWpwZ15BbWU4MDU3OTg3MjUz._V1_QL75_UX380_CR0,0,380,562_.jpg",
        "description": "The Incredibles family takes on a new mission which involves a change in family roles.",
        "release_date": "2018-06-15",
        "cast": ["Craig T. Nelson", "Holly Hunter", "Samuel L. Jackson"],
    },
    {
        "item_id": 177765,
        "title": "Coco (2017)",
        "poster_url": "https://m.media-amazon.com/images/M/MV5BMDIyM2E2NTAtMzlhNy00ZGUxLWI1NjgtZDY5MzhiMDc5NGU3XkEyXkFqcGc@._V1_QL75_UY562_CR7,0,380,562_.jpg",
        "description": "Miguel enters the Land of the Dead to find his great-great-grandfather, a legendary singer.",
        "release_date": "2017-11-22",
        "cast": ["Anthony Gonzalez", "Gael García Bernal", "Benjamin Bratt"],
    },
    {
        "item_id": 68954,
        "title": "Up (2009)",
        "poster_url": "https://m.media-amazon.com/images/M/MV5BNmI1ZTc5MWMtMDYyOS00ZDc2LTkzOTAtNjQ4NWIxNjYyNDgzXkEyXkFqcGc@._V1_QL75_UX380_CR0,1,380,562_.jpg",
        "description": "78-year-old Carl Fredricksen travels to South America in his house equipped with balloons.",
        "release_date": "2009-05-29",
        "cast": ["Edward Asner", "Jordan Nagai", "Christopher Plummer"],
    },
]

client.insert_table_rows("pixar_movies", records)
```

### TypeScript

```typescript
const records: Array<Record<string, any>> = [
  {
    item_id: 187541,
    title: 'Incredibles 2 (2018)',
    poster_url: 'https://m.media-amazon.com/images/M/MV5BMTEzNzY0OTg0NTdeQTJeQWpwZ15BbWU4MDU3OTg3MjUz._V1_QL75_UX380_CR0,0,380,562_.jpg',
    description: 'The Incredibles family takes on a new mission which involves a change in family roles.',
    release_date: '2018-06-15',
    cast: ['Craig T. Nelson', 'Holly Hunter', 'Samuel L. Jackson'],
  },
  {
    item_id: 177765,
    title: 'Coco (2017)',
    poster_url: 'https://m.media-amazon.com/images/M/MV5BMDIyM2E2NTAtMzlhNy00ZGUxLWI1NjgtZDY5MzhiMDc5NGU3XkEyXkFqcGc@._V1_QL75_UY562_CR7,0,380,562_.jpg',
    description: 'Miguel enters the Land of the Dead to find his great-great-grandfather, a legendary singer.',
    release_date: '2017-11-22',
    cast: ['Anthony Gonzalez', 'Gael García Bernal', 'Benjamin Bratt'],
  },
  {
    item_id: 68954,
    title: 'Up (2009)',
    poster_url: 'https://m.media-amazon.com/images/M/MV5BNmI1ZTc5MWMtMDYyOS00ZDc2LTkzOTAtNjQ4NWIxNjYyNDgzXkEyXkFqcGc@._V1_QL75_UX380_CR0,1,380,562_.jpg',
    description: '78-year-old Carl Fredricksen travels to South America in his house equipped with balloons.',
    release_date: '2009-05-29',
    cast: ['Edward Asner', 'Jordan Nagai', 'Christopher Plummer'],
  },
];

await client.insertTableRows('pixar_movies', records);
```

### Command Line Interface

When using the CLI, you should upload a CSV file. 

```bash
cat > pixar_movies.jsonl <<'EOF'
{"item_id":187541,"title":"Incredibles 2 (2018)","poster_url":"https://m.media-amazon.com/images/M/MV5BMTEzNzY0OTg0NTdeQTJeQWpwZ15BbWU4MDU3OTg3MjUz._V1_QL75_UX380_CR0,0,380,562_.jpg","description":"The Incredibles family takes on a new mission which involves a change in family roles.","release_date":"2018-06-15","cast":["Craig T. Nelson","Holly Hunter","Samuel L. Jackson"]}
{"item_id":177765,"title":"Coco (2017)","poster_url":"https://m.media-amazon.com/images/M/MV5BMDIyM2E2NTAtMzlhNy00ZGUxLWI1NjgtZDY5MzhiMDc5NGU3XkEyXkFqcGc@._V1_QL75_UY562_CR7,0,380,562_.jpg","description":"Miguel enters the Land of the Dead to find his great-great-grandfather, a legendary singer.","release_date":"2017-11-22","cast":["Anthony Gonzalez","Gael García Bernal","Benjamin Bratt"]}
{"item_id":68954,"title":"Up (2009)","poster_url":"https://m.media-amazon.com/images/M/MV5BNmI1ZTc5MWMtMDYyOS00ZDc2LTkzOTAtNjQ4NWIxNjYyNDgzXkEyXkFqcGc@._V1_QL75_UX380_CR0,1,380,562_.jpg","description":"78-year-old Carl Fredricksen travels to South America in his house equipped with balloons.","release_date":"2009-05-29","cast":["Edward Asner","Jordan Nagai","Christopher Plummer"]}
EOF

side table-insert \
  --table-name pixar_movies \
  --file pixar_movies.jsonl \
  --type jsonl
```

---

## Step 5: Create a semantic search engine

Goal: Configure a SIDE Engine named `semantic_search` that can index and retrieve from a connected table.

SIDE Engine supports any [sentence-transformers](https://huggingface.co/models?library=sentence-transformers) model on Hugging Face.

For quick-start, use `sentence-transformers/all-MiniLM-L6-v2`. The example below uses the `pixar_movies` table created previously.

Note: Encoding is asynchronous. Downstream search calls should assume a short delay until embeddings are ready.

### Python

```python
from side import Client
from side.autogen.models.engine_config_v2 import EngineConfigV2
from side.autogen.models.data_config import DataConfig
from side.autogen.models.data_config_interaction_table import DataConfigInteractionTable
from side.autogen.models.reference_table_config import ReferenceTableConfig
from side.autogen.models.index_config import IndexConfig
from side.autogen.models.embedding_config import EmbeddingConfig
from side.autogen.models.encoder import Encoder
from side.autogen.models.hugging_face_encoder import HuggingFaceEncoder

client = Client(api_key="YOUR_KEY_HERE")

fields_to_encode = ["title", "description"]
embedding_model = "sentence-transformers/all-MiniLM-L6-v2"

semantic_search_engine = EngineConfigV2(
    name="semantic_search",
    data=DataConfig(
        item_table=DataConfigInteractionTable(
            ReferenceTableConfig(
                name="pixar_movies",
            )
        )
    ),
    index=IndexConfig(
        embeddings=[
            EmbeddingConfig(
                name="movie_text_embedding",
                encoder=Encoder(
                    HuggingFaceEncoder(
                        model_name=embedding_model,
                        item_fields=fields_to_encode,
                    )
                ),
            )
        ]
    ),
)

client.create_engine(engine_config=semantic_search_engine)
```

### TypeScript

```typescript
import { Client, Engine } from '@nextgres/side-client';

const client = new Client('YOUR_API_KEY');

const fieldsToEncode = ['title', 'description'];
const embeddingModel = 'sentence-transformers/all-MiniLM-L6-v2';

const semanticSearchEngine = new Engine('semantic_search').items('pixar_movies');

semanticSearchEngine.withEmbedding({
  name: 'movie_text_embedding',
  encoder: {
    type: 'hugging_face',
    model_name: embeddingModel,
    item_fields: fieldsToEncode,
  },
});

await client.createEngine(semanticSearchEngine);
```

### Command Line Interface

```bash
# engine.yaml
cat > engine.yaml <<EOF
version: v2
name: basic_engine
data:
  item_table:
    name: movielens_items # change this to your table name
    type: table
index:
  embeddings:
    - name: content_embedding # enables vector search
      encoder:
        type: hugging_face
        model_name: sentence-transformers/all-MiniLM-L6-v2
        batch_size: 256
        item_fields: # update these to your table's text columns
          - movie_title
          - description
EOF

side create-engine --config engine.yaml
```

---

## Step 6: Query the semantic search engine

Goal: Execute a text query against `semantic_search` and retrieve matching movies based on vector similarity.

Use the `text_search` retriever with `mode = 'vector'`.
The raw text query is automatically embedded; no manual vector construction is required.

### Python

```python
query_string = """
SELECT *
FROM retrieve(
  text_search(
    query = '$query',
    mode = 'vector',
    text_embedding_ref = 'title_embedding',
    limit = 50
  )
)
LIMIT 200
"""

results = client.execute_query(
    engine_name="semantic_search",
    query=query_string,
    parameters={"query": "Incredibles"},
    return_metadata=True,
)
```

### TypeScript

```typescript
const queryString = `
SELECT *
FROM retrieve(
  text_search(
    query = '$query',
    mode = 'vector',
    text_embedding_ref = 'title_embedding',
    limit = 50
  )
)
LIMIT 200
`;

const results = await client.executeQuery(
  'semantic_search',
  queryString,
  { query: 'Incredibles' },
  true,
);
```

### SIDEQL (SQL-like) only

```sql
SELECT *
FROM retrieve(
  text_search(
    query = '$query',
    mode = 'vector',
    text_embedding_ref = 'title_embedding',
    limit = 50
  )
)
LIMIT 200
```

### Command Line Interface

```bash
side query \
  --engine-name semantic_search \
  --query "SELECT * FROM retrieve( text_search( query = '$query', mode = 'vector', text_embedding_ref = 'title_embedding', limit = 50 )) LIMIT 200" 
```

---

# Other common tasks

This section covers other common operations when working with SIDE Engine. 

## Create an image embedding

Goal: Choose a specific embedding model that encodes images into searchable vectors.

SIDE Engine supports any [CLIP](https://huggingface.co/models?other=clip) model on Hugging Face.

These models convert images into vectors that can be searched. 

For quick-start, use `openai/clip-vit-base-patch32`.

Encoding is asynchronous.
Downstream search calls should assume a short delay until embeddings are ready.

### Python

```python
from side import Client
from side.autogen.models.engine_config_v2 import EngineConfigV2
from side.autogen.models.data_config import DataConfig
from side.autogen.models.data_config_interaction_table import DataConfigInteractionTable
from side.autogen.models.reference_table_config import ReferenceTableConfig
from side.autogen.models.index_config import IndexConfig
from side.autogen.models.embedding_config import EmbeddingConfig
from side.autogen.models.encoder import Encoder
from side.autogen.models.hugging_face_encoder import HuggingFaceEncoder

client = Client(api_key="YOUR_KEY_HERE")

embedding_model = "openai/clip-vit-base-patch32"

image_search_engine = EngineConfigV2(
    name="image_search",
    data=DataConfig(
        item_table=DataConfigInteractionTable(
            ReferenceTableConfig(
                name="pixar_movies",
            )
        )
    ),
    index=IndexConfig(
        embeddings=[
            EmbeddingConfig(
                name="image_embedding",
                encoder=Encoder(
                    HuggingFaceEncoder(
                        model_name=embedding_model,
                        item_fields=["poster_url"],
                    )
                ),
            )
        ]
    ),
)

client.create_engine(engine_config=image_search_engine)
```

### TypeScript

```typescript
import { Client, Engine } from '@nextgres/side-client';

const client = new Client('YOUR_API_KEY');

const embeddingModel = 'openai/clip-vit-base-patch32';

const imageSearchEngine = new Engine('image_search').items('pixar_movies');

imageSearchEngine.withEmbedding({
  name: 'image_embedding',
  encoder: {
    type: 'hugging_face',
    model_name: embeddingModel,
    item_fields: ['poster_url'],
  },
});

await client.createEngine(imageSearchEngine);
```

## Choose an embedding model

SIDE Engine supports any [sentence-transformers](https://huggingface.co/models?library=sentence-transformers) model on Hugging Face.

For quick-start, use `sentence-transformers/all-MiniLM-L6-v2`.