> For the complete documentation index, see [llms.txt](https://docs.telys.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.telys.ai/working-with-data/add-and-upsert.md).

# Add & upsert

Telys has two ingest verbs and two input shapes — four methods:

| Method                               | Input                                  | Behavior                                                                               |
| ------------------------------------ | -------------------------------------- | -------------------------------------------------------------------------------------- |
| `add(vectors, ids, metadata)`        | precomputed vectors `(n, dim)` float32 | insert **new rows only** — `KeyError` if an id already exists                          |
| `add_texts(texts, ids, metadata)`    | strings (embedded for you)             | insert **new rows only** — `KeyError` on a duplicate id; `RuntimeError` if no embedder |
| `upsert(vectors, ids, metadata)`     | precomputed vectors `(n, dim)` float32 | **insert new + replace existing**                                                      |
| `upsert_texts(texts, ids, metadata)` | strings (embedded for you)             | **insert new + replace existing** — needs an embedder                                  |

All four take parallel `ids` and `metadata` lists and **return the external ids** they wrote. Each `metadata` dict supplies the partition key column (and any `filter_columns`) for its row.

{% hint style="info" %}
The `*_texts` methods need an embedder on the collection (attached at [creation](/working-with-data/create-a-collection.md) or via `open_collection`); without one they raise `RuntimeError`. Raw `add` / `upsert` never embed and work on any collection.
{% endhint %}

## Add new records from text

```python
from telys import Telys
from telys.embedding import AlgentaMultigramEmbedder

telys = Telys("telys-store")
embedder = AlgentaMultigramEmbedder()
memories = telys.create_collection(
    "memories",
    dim=embedder.profile.dimension,
    partition_by="scope",
    embedder=embedder,
)

ids = memories.add_texts(
    texts=[
        "the mitochondria is the powerhouse of the cell",
        "photosynthesis converts light into chemical energy",
    ],
    ids=["bio-1", "bio-2"],
    metadata=[
        {"scope": "user:42", "topic": "biology"},
        {"scope": "user:42", "topic": "biology"},
    ],
)
memories.save()
```

Each metadata dict includes `scope`, the partition key. `add_texts` returns `["bio-1", "bio-2"]`.

## add is new-only — duplicates raise

`add` and `add_texts` never overwrite. Re-adding an existing id raises `KeyError`:

```python
>>> memories.add_texts(
...     ["a different note"],
...     ids=["bio-1"],                       # already present
...     metadata=[{"scope": "user:42"}],
... )
KeyError: "id 'bio-1' already exists"
```

## upsert to insert-or-replace

To overwrite, use `upsert_texts` (or `upsert` for vectors): new ids are inserted, existing ids replaced in place.

```python
ids = memories.upsert_texts(
    texts=["the mitochondria produces most of the cell's ATP"],
    ids=["bio-1"],                            # replaced, not rejected
    metadata=[{"scope": "user:42", "topic": "biology"}],
)
# -> ["bio-1"]
```

## Add precomputed vectors

Skip embedding by passing vectors directly. Use a NumPy array of shape `(n, dim)`, dtype `float32`, with the row count matching `ids` and `metadata`.

```python
import numpy as np

vectors = np.random.rand(2, embedder.profile.dimension).astype("float32")
memories.add(
    vectors,
    ids=["v-1", "v-2"],
    metadata=[{"scope": "user:7"}, {"scope": "user:7"}],
)
```

## Expected result

Each call returns the external ids it wrote, and `len(col)` grows by the number of new ids. `add`/`add_texts` reject duplicates; `upsert`/`upsert_texts` accept them as replacements.

```python
>>> memories.add_texts(["note"], ids=["bio-3"], metadata=[{"scope": "user:42"}])
['bio-3']
>>> len(memories)
5
>>> "bio-3" in memories
True
```

Writes stay in memory until you persist. `memories.save()` commits and returns the collection directory.

## Next steps

* [Add text vs vectors](/working-with-data/add-text-vs-vectors.md) — when to embed vs bring your own vectors.
* [Update records](/working-with-data/update-records.md) — replace existing rows only, without inserting new ones.
* [Records, IDs & payloads](/understand-telys/records-ids-payloads.md) — how ids and metadata are stored.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.telys.ai/working-with-data/add-and-upsert.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
