diff --git a/content/Cloud/agents.mdx b/content/Cloud/agents.mdx
index 1951c397..5a7a5ea1 100644
--- a/content/Cloud/agents.mdx
+++ b/content/Cloud/agents.mdx
@@ -156,7 +156,7 @@ For Email sources, you can configure your agent at a unique agent email address.
An email source can only be triggered by an email sent to the agent's email address and not via the API.
-The response from the API will contain an informational message if successful. Additionally, the `Location` header will contain the URL that can be used to read the agent output. This URL will block until the agent has started streaming the output response.
+After an email is received, the platform will enqueue processing and your agent will handle the message asynchronously. Any replies will be delivered via the configured destination(s).
#### Discord Source
diff --git a/content/Guides/vector-db.mdx b/content/Guides/vector-db.mdx
index 103e3e76..ffa5173c 100644
--- a/content/Guides/vector-db.mdx
+++ b/content/Guides/vector-db.mdx
@@ -48,6 +48,13 @@ Vector storage is created automatically when your agent first calls `context.vec
The `upsert` operation inserts new documents or updates existing ones. You can provide either text (which gets automatically converted to embeddings) or pre-computed embeddings.
+**SDK Differences:**
+- **JavaScript SDK**: No key field required, search returns `distance` (0 = perfect match)
+- **Python SDK**: Requires `key` field for each document, search returns `similarity` (1.0 = perfect match)
+
+**Idempotent Behavior:**
+The upsert operation is idempotent - upserting with an existing key updates the existing vector rather than creating a duplicate. The same internal vector ID is reused, ensuring your vector storage remains clean and efficient.
+
```javascript
// JavaScript/TypeScript
@@ -79,26 +86,29 @@ const embeddingIds = await context.vector.upsert(
# Upsert documents with text
documents = [
{
+ "key": "doc_1", # Required: unique identifier for this vector
"document": "Agentuity is an agent-native cloud platform",
"metadata": {"category": "platform", "source": "docs"}
},
{
+ "key": "doc_2", # Required: unique identifier for this vector
"document": "Vector storage enables semantic search capabilities",
"metadata": {"category": "features", "source": "docs"}
}
]
-ids = await context.vector.upsert("knowledge-base", *documents)
+ids = await context.vector.upsert("knowledge-base", documents)
# Upsert with embeddings
embedding_docs = [
{
+ "key": "embedding_1", # Required: unique identifier for this vector
"embeddings": [0.1, 0.2, 0.3, 0.4],
"metadata": {"id": "doc-1", "type": "custom"}
}
]
-ids = await context.vector.upsert("custom-embeddings", *embedding_docs)
+ids = await context.vector.upsert("custom-embeddings", embedding_docs)
```
@@ -137,9 +147,8 @@ results = await context.vector.search(
# Process results
for result in results:
- similarity_score = 1.0 - result.distance
print(f"Found: {result.metadata['source']}")
- print(f"Similarity: {similarity_score}")
+ print(f"Similarity: {result.similarity}")
```
@@ -151,7 +160,7 @@ for result in results:
### Deleting Vectors
-Remove specific vectors from storage using their IDs.
+Remove specific vectors from storage using their IDs (JavaScript) or keys (Python).
```javascript
@@ -169,7 +178,7 @@ const bulkDeleteCount = await context.vector.delete(
```python
# Python
# Delete single vector
-count = await context.vector.delete("knowledge-base", "vector-id-1")
+count = await context.vector.delete("knowledge-base", "doc_1")
# Note: Python SDK currently supports single deletion
# For bulk operations, call delete multiple times
diff --git a/content/SDKs/python/api-reference.mdx b/content/SDKs/python/api-reference.mdx
index 56037a46..a8624310 100644
--- a/content/SDKs/python/api-reference.mdx
+++ b/content/SDKs/python/api-reference.mdx
@@ -105,7 +105,6 @@ from agentuity.io.email import EmailAttachment
async def handler(request: AgentRequest, response: AgentResponse, context: AgentContext):
# Get the incoming email
- email = request.data.email()
email = await request.data.email()
# Create an attachment
attachment = EmailAttachment(
@@ -368,18 +367,20 @@ The Vector Storage API provides a way to store and search for data using vector
#### upsert
-`async upsert(name: str, *documents: VectorUpsertParams) -> list[str]`
+`async upsert(name: str, documents: List[VectorUpsertParams]) -> list[str]`
Inserts or updates vectors in the vector storage.
**Parameters**
- `name`: The name of the vector storage
-- `documents`: An array of documents to upsert, each with either embeddings or text
+- `documents`: A list of documents to upsert. Each document must include a unique `key` and either `document` (text) or `embeddings`
**Return Value**
-Returns a list of string IDs for the upserted vectors.
+Returns a list of string IDs for the upserted vectors (internal system IDs, not your provided keys).
+
+Note: Upserting with an existing `key` updates that vector (idempotent operation).
**Example**
@@ -402,6 +403,7 @@ async def index_products(context: AgentContext, products: List[Dict[str, Any]])
documents = []
for product in products:
documents.append({
+ "key": product["id"], # REQUIRED: unique key for each document
"document": product["description"],
"metadata": {
"product_id": product["id"],
@@ -442,18 +444,25 @@ ids2 = await context.vector.upsert(
#### search
-`async search(name: str, query: str, limit: int, similarity: float, metadata: Optional[dict]) -> list[VectorSearchResult]`
+`async search(name: str, query: str, limit: int = 10, similarity: float = 0.5, metadata: Optional[dict] = None) -> list[VectorSearchResult]`
Searches for vectors in the vector storage.
**Parameters**
- `name`: The name of the vector storage
-- `params`: Search parameters including query, limit, similarity threshold, and metadata filters
+- `query`: The query text to search against
+- `limit`: (optional) Maximum number of results to return. Defaults to 10
+- `similarity`: (optional) Minimum similarity threshold (0.0-1.0). Defaults to 0.5
+- `metadata`: (optional) Exact-match metadata filters applied at search time. Defaults to None
**Return Value**
-Returns a list of search results, each containing an ID, metadata, and distance score.
+Returns a list of search results with the following attributes:
+- `id`: Internal vector ID (e.g., "vector_94c98660c8afa3a2")
+- `key`: The unique key for this vector
+- `similarity`: Similarity score from 0.0 to 1.0 (1.0 = perfect match)
+- `metadata`: The associated metadata dictionary
**Example**
@@ -463,8 +472,9 @@ from typing import List, Dict, Any
# Search for similar products with error handling
try:
- results = await context.vector.search("product-descriptions",
- query="comfortable office chair",
+ results = await context.vector.search(
+ "product-descriptions",
+ "comfortable office chair",
limit=5,
similarity=0.7,
metadata={"category": "furniture"}
@@ -474,7 +484,7 @@ try:
if results:
context.logger.info(f"Found {len(results)} matching products")
for result in results:
- print(f"Product ID: {result.id}, Similarity: {result.distance}")
+ print(f"Product ID: {result.id}, Similarity: {result.similarity}")
print(f"Metadata: {result.metadata}")
else:
context.logger.info("No matching products found")
@@ -496,7 +506,7 @@ Deletes a vector from the vector storage.
**Return Value**
-Returns the number of vectors that were deleted (0 or 1).
+Returns the number of vectors that were deleted (0 if the key didn't exist, 1 if successfully deleted).
**Example**
@@ -505,7 +515,7 @@ from agentuity.sdk import AgentContext
# Delete a single vector with error handling
try:
- deleted_count = await context.vector.delete("product-descriptions", "id1")
+ deleted_count = await context.vector.delete("product-descriptions", "key_123")
context.logger.info(f"Deleted {deleted_count} vector(s)")
except Exception as e:
context.logger.error(f"Failed to delete vector: {str(e)}")
diff --git a/content/SDKs/python/examples/index.mdx b/content/SDKs/python/examples/index.mdx
index 09689990..7c4891ee 100644
--- a/content/SDKs/python/examples/index.mdx
+++ b/content/SDKs/python/examples/index.mdx
@@ -199,7 +199,7 @@ async def run(request: AgentRequest, response: AgentResponse, context: AgentCont
{
"id": result.id,
"key": result.key,
- "similarity": 1.0 - result.distance,
+ "similarity": result.similarity,
"metadata": result.metadata
}
for result in results