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