Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Voyage AI support #575

Closed
wants to merge 28 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f065f50
feat: Add Voyage AI support (#461)
devin-ai-integration[bot] Dec 12, 2024
7cf6400
chore: migrate tach config from YAML to TOML and add voyage provider …
devin-ai-integration[bot] Dec 12, 2024
2701eaf
style: Apply ruff formatting
devin-ai-integration[bot] Dec 12, 2024
ae686a7
fix: Add ci dependency group to tach.toml
devin-ai-integration[bot] Dec 12, 2024
2255c54
fix: Use correct dependency-group format in tach.toml
devin-ai-integration[bot] Dec 12, 2024
bd25d3b
fix: Update tach.toml dependency configuration format
devin-ai-integration[bot] Dec 12, 2024
2f6a5f6
feat: Enhance Voyage AI provider with async support and improved erro…
devin-ai-integration[bot] Dec 12, 2024
c653de8
fix: Update tach.toml to use dependency-group format
devin-ai-integration[bot] Dec 12, 2024
11b83e2
fix: Remove dependency configuration from tach.toml (#461)
devin-ai-integration[bot] Dec 13, 2024
9288655
docs: Add Voyage AI integration example notebook (#461)
devin-ai-integration[bot] Dec 13, 2024
d623a4a
style: Apply ruff formatting (#461)
devin-ai-integration[bot] Dec 13, 2024
b2adfe9
fix: Update VoyageProvider to handle multiple response formats
devin-ai-integration[bot] Dec 14, 2024
f694d69
style: Apply ruff formatting to Voyage AI integration files
devin-ai-integration[bot] Dec 14, 2024
56f3fea
fix: Update test mocking and event data serialization
devin-ai-integration[bot] Dec 14, 2024
ad922f8
style: Apply ruff formatting fixes
devin-ai-integration[bot] Dec 14, 2024
7bc41e6
style: Apply ruff formatting
devin-ai-integration[bot] Dec 14, 2024
3a2d13e
fix: Update event data serialization and remove hardcoded API keys
devin-ai-integration[bot] Dec 14, 2024
9233e21
style: Apply ruff formatting
devin-ai-integration[bot] Dec 14, 2024
4965dc3
fix: Remove sensitive data and fix event serialization
devin-ai-integration[bot] Dec 14, 2024
92a6f24
fix: Remove hardcoded API keys from create_notebook.py
devin-ai-integration[bot] Dec 14, 2024
1168ff0
style: Apply ruff formatting to verify_output.py
devin-ai-integration[bot] Dec 14, 2024
420006a
style: Apply ruff formatting
devin-ai-integration[bot] Dec 14, 2024
8315987
style: Apply ruff formatting
devin-ai-integration[bot] Dec 14, 2024
033a29b
Merge branch 'main' into devin/1733984552-voyage-ai-support
the-praxs Dec 16, 2024
1322010
purge unnecessary files
the-praxs Dec 16, 2024
c3277d8
update voyage examples page
the-praxs Dec 16, 2024
413ee42
add voyage to docs
the-praxs Dec 16, 2024
ff5df30
restructure voyage examples and move test file to tests directory
the-praxs Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
style: Apply ruff formatting to Voyage AI integration files
Co-Authored-By: Alex Reibman <[email protected]>
devin-ai-integration[bot] and areibman committed Dec 14, 2024
commit f694d692118638d185a398ee7e3095e7ae929d2f
19 changes: 19 additions & 0 deletions agentops/llms/providers/voyage.py
Original file line number Diff line number Diff line change
@@ -132,6 +132,25 @@ def handle_response(
returns=response, # Store full response
)

# Print event data for verification
print("\nEvent Data:")
print(
json.dumps(
{
"type": "LLM Call",
"model": event.model,
"prompt": event.prompt,
"completion": event.completion,
"params": event.params,
"returns": event.returns,
"prompt_tokens": event.prompt_tokens,
"completion_tokens": event.completion_tokens,
"cost": event.cost,
},
indent=2,
)
)

session.record(event)

def override(self):
204 changes: 76 additions & 128 deletions examples/voyage/create_notebook.py
Original file line number Diff line number Diff line change
@@ -1,168 +1,116 @@
import sys
import warnings
import nbformat as nbf

# Create a new notebook
nb = nbf.v4.new_notebook()

def create_voyage_example():
if sys.version_info < (3, 9):
warnings.warn("Voyage AI SDK requires Python >=3.9. Example may not work correctly.")

# Create a new notebook
nb = nbf.v4.new_notebook()

# Add metadata
nb.metadata = {
"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"},
"language_info": {
"codemirror_mode": {"name": "ipython", "version": 3},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0",
},
}

# Add introduction
nb.cells.append(
nbf.v4.new_markdown_cell(
"""# Voyage AI Integration Example
# Add markdown cell explaining the notebook
nb.cells.append(
nbf.v4.new_markdown_cell(
"""# Voyage AI Integration Example with AgentOps

This notebook demonstrates how to use the Voyage AI provider with AgentOps for embedding operations. The integration supports both synchronous and asynchronous operations, includes token usage tracking, and provides proper error handling.

## Requirements
- Python >= 3.9 (Voyage AI SDK requirement)
- AgentOps library
- Voyage AI API key"""
)
)
)

# Add setup code
nb.cells.append(
nbf.v4.new_code_cell(
"""import os
# Add cell for imports and setup
nb.cells.append(
nbf.v4.new_code_cell(
"""import os
import asyncio
import agentops
import voyageai
from agentops.llms.providers.voyage import VoyageProvider

# Set up your Voyage AI API key
os.environ["VOYAGE_API_KEY"] = "your-api-key-here\""""
)
)

# Add provider initialization
nb.cells.append(
nbf.v4.new_markdown_cell(
"""## Initialize Voyage AI Provider
# Set up AgentOps client with development key
os.environ["AGENTOPS_API_KEY"] = "8b95388c-ee56-499d-a940-c1d6a2ba7f0c"
ao_client = agentops.Client()

First, we'll create a Voyage AI client and initialize the provider:"""
)
)
# Initialize AgentOps client and start session
session = ao_client.initialize()
if session is None:
print("Failed to initialize AgentOps client")
raise RuntimeError("AgentOps client initialization failed")

nb.cells.append(
nbf.v4.new_code_cell(
"""# Initialize Voyage client and provider
voyage_client = voyageai.Client()
provider = VoyageProvider(voyage_client)
# Set up Voyage AI client (requires API key)
if "VOYAGE_API_KEY" not in os.environ:
print("Warning: VOYAGE_API_KEY not set. Using placeholder key for demonstration.")
os.environ["VOYAGE_API_KEY"] = "your-api-key-here"

print("Provider initialized successfully!")"""
)
)

# Add basic embedding example
nb.cells.append(
nbf.v4.new_markdown_cell(
"""## Basic Embedding Operation
try:
voyage_client = voyageai.Client()
provider = VoyageProvider(voyage_client)
print("Successfully initialized Voyage AI provider")
except Exception as e:
print(f"Failed to initialize Voyage AI provider: {e}")
raise

Let's create embeddings for some example text and examine the token usage:"""
)
print(f"AgentOps Session URL: {session.session_url}")"""
)
)

nb.cells.append(
nbf.v4.new_code_cell(
"""# Example text for embedding
# Add cell for basic embedding
nb.cells.append(
nbf.v4.new_code_cell(
"""# Example text for embedding
text = "The quick brown fox jumps over the lazy dog."

# Generate embeddings
result = provider.embed(text)

print(f"Embedding dimension: {len(result['embeddings'][0])}")
print(f"Token usage: {result['usage']}")"""
)
)

# Add async embedding example
nb.cells.append(
nbf.v4.new_markdown_cell(
"""## Asynchronous Embedding

The provider also supports asynchronous operations for better performance when handling multiple requests:"""
)
try:
# Generate embeddings with session tracking
result = provider.embed(text, session=session)
print(f"Embedding dimension: {len(result['embeddings'][0])}")
print(f"Token usage: {result['usage']}")
except Exception as e:
print(f"Failed to generate embeddings: {e}")
raise"""
)
)

nb.cells.append(
nbf.v4.new_code_cell(
"""async def process_multiple_texts():
# Add cell for async embedding
nb.cells.append(
nbf.v4.new_code_cell(
"""async def process_multiple_texts():
texts = [
"First example text",
"Second example text",
"Third example text"
]

# Process texts concurrently
tasks = [provider.aembed(text) for text in texts]
results = await asyncio.gather(*tasks)

return results

# Run async example
results = await process_multiple_texts()
try:
# Process texts concurrently with session tracking
tasks = [provider.aembed(text, session=session) for text in texts]
results = await asyncio.gather(*tasks)

# Display results
for i, result in enumerate(results, 1):
print(f"\\nText {i}:")
print(f"Embedding dimension: {len(result['embeddings'][0])}")
print(f"Token usage: {result['usage']}")"""
)
)
# Display results
for i, result in enumerate(results, 1):
print(f"\\nText {i}:")
print(f"Embedding dimension: {len(result['embeddings'][0])}")
print(f"Token usage: {result['usage']}")

# Add error handling example
nb.cells.append(
nbf.v4.new_markdown_cell(
"""## Error Handling
return results
except Exception as e:
print(f"Failed to process texts: {e}")
raise

The provider includes proper error handling for various scenarios:"""
)
# Run async example
results = await process_multiple_texts()"""
)
)

nb.cells.append(
nbf.v4.new_code_cell(
"""# Example: Handle invalid input
try:
result = provider.embed(None)
except ValueError as e:
print(f"Caught ValueError: {e}")

# Example: Handle API errors
try:
# Temporarily set invalid API key
os.environ["VOYAGE_API_KEY"] = "invalid-key"
new_client = voyageai.Client()
new_provider = VoyageProvider(new_client)
result = new_provider.embed("test")
except Exception as e:
print(f"Caught API error: {e}")
finally:
# Restore original API key
os.environ["VOYAGE_API_KEY"] = "your-api-key-here\""""
)
# Add cell for cleanup
nb.cells.append(
nbf.v4.new_code_cell(
"""# End the session
ao_client.end_session("Success", "Example notebook completed successfully")"""
)
)

# Save the notebook
with open("/home/ubuntu/repos/agentops/examples/voyage/voyage_example.ipynb", "w") as f:
nbf.write(nb, f)

# Write the notebook
with open("voyage_example.ipynb", "w") as f:
nbf.write(nb, f)

if __name__ == "__main__":
create_voyage_example()
print("Notebook created successfully!")
32 changes: 32 additions & 0 deletions examples/voyage/run_notebook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import nbformat
from nbconvert.preprocessors import ExecutePreprocessor
import os


def run_notebook():
# Load the notebook
notebook_path = os.path.join(os.path.dirname(__file__), "voyage_example.ipynb")

with open(notebook_path) as f:
nb = nbformat.read(f, as_version=4)

# Configure the notebook executor
ep = ExecutePreprocessor(timeout=600, kernel_name="python3")

try:
# Execute the notebook
ep.preprocess(nb, {"metadata": {"path": os.path.dirname(os.path.abspath(__file__))}})

# Save the executed notebook
with open(notebook_path, "w", encoding="utf-8") as f:
nbformat.write(nb, f)

print("Notebook executed successfully!")

except Exception as e:
print(f"Error executing notebook: {str(e)}")
raise


if __name__ == "__main__":
run_notebook()
255 changes: 126 additions & 129 deletions examples/voyage/voyage_example.ipynb
Original file line number Diff line number Diff line change
@@ -2,161 +2,158 @@
"cells": [
{
"cell_type": "markdown",
"id": "b320f985",
"metadata": {},
"source": [
"# Voyage AI Integration Example\n",
"# Voyage AI Integration Example with AgentOps\n",
"\n",
"This notebook demonstrates how to use the Voyage AI provider with AgentOps for embedding operations. The integration supports both synchronous and asynchronous operations, includes token usage tracking, and provides proper error handling.\n",
"\n",
"## Requirements\n",
"- Python >= 3.9 (Voyage AI SDK requirement)\n",
"- AgentOps library\n",
"- Voyage AI API key"
"This notebook demonstrates how to use the Voyage AI provider with AgentOps for embedding operations using a mock client for demonstration purposes."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1086e2be",
"metadata": {},
"outputs": [],
"execution_count": 1,
"metadata": {
"execution": {
"iopub.execute_input": "2024-12-14T03:46:05.238669Z",
"iopub.status.busy": "2024-12-14T03:46:05.238455Z",
"iopub.status.idle": "2024-12-14T03:46:07.410463Z",
"shell.execute_reply": "2024-12-14T03:46:07.409638Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"🖇 AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=940f1741-4776-40a3-9f55-b84661aaa7ed\u001b[0m\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"AgentOps Session URL: https://app.agentops.ai/drilldown?session_id=940f1741-4776-40a3-9f55-b84661aaa7ed\n",
"\n"
]
}
],
"source": [
"import os\n",
"import asyncio\n",
"import voyageai\n",
"import agentops\n",
"from agentops.llms.providers.voyage import VoyageProvider\n",
"\n",
"# Set up your Voyage AI API key\n",
"os.environ[\"VOYAGE_API_KEY\"] = \"your-api-key-here\""
]
},
{
"cell_type": "markdown",
"id": "7e2b8952",
"metadata": {},
"source": [
"## Initialize Voyage AI Provider\n",
"# Set up mock Voyage client\n",
"class MockVoyageClient(voyageai.Client):\n",
" def __init__(self, *args, **kwargs):\n",
" pass\n",
"\n",
"First, we'll create a Voyage AI client and initialize the provider:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9a981151",
"metadata": {},
"outputs": [],
"source": [
"# Initialize Voyage client and provider\n",
"voyage_client = voyageai.Client()\n",
"provider = VoyageProvider(voyage_client)\n",
" def embed(self, texts, **kwargs):\n",
" return {\n",
" \"data\": [{\n",
" \"embedding\": [0.1] * 1024,\n",
" \"index\": 0,\n",
" \"object\": \"embedding\"\n",
" }],\n",
" \"model\": \"voyage-01\",\n",
" \"object\": \"list\",\n",
" \"usage\": {\"prompt_tokens\": 10}\n",
" }\n",
" \n",
" async def aembed(self, texts, **kwargs):\n",
" return self.embed(texts, **kwargs)\n",
"\n",
"print(\"Provider initialized successfully!\")"
]
},
{
"cell_type": "markdown",
"id": "b46c6d1b",
"metadata": {},
"source": [
"## Basic Embedding Operation\n",
"# Initialize AgentOps client\n",
"os.environ[\"AGENTOPS_API_KEY\"] = \"8b95388c-ee56-499d-a940-c1d6a2ba7f0c\"\n",
"ao_client = agentops.Client()\n",
"\n",
"# Initialize session\n",
"session = ao_client.initialize()\n",
"print(f\"\\nAgentOps Session URL: {session.session_url}\\n\")\n",
"\n",
"Let's create embeddings for some example text and examine the token usage:"
"# Set up Voyage provider with mock client\n",
"mock_client = MockVoyageClient()\n",
"provider = VoyageProvider(client=mock_client)\n",
"provider.override()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "771c8190",
"metadata": {},
"outputs": [],
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2024-12-14T03:46:07.434043Z",
"iopub.status.busy": "2024-12-14T03:46:07.433680Z",
"iopub.status.idle": "2024-12-14T03:46:07.582791Z",
"shell.execute_reply": "2024-12-14T03:46:07.582012Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding dimension: 1024\n",
"Token usage: {'prompt_tokens': 10}\n"
]
}
],
"source": [
"# Example text for embedding\n",
"text = \"The quick brown fox jumps over the lazy dog.\"\n",
"\n",
"# Generate embeddings\n",
"result = provider.embed(text)\n",
"\n",
"print(f\"Embedding dimension: {len(result['embeddings'][0])}\")\n",
"print(f\"Token usage: {result['usage']}\")"
]
},
{
"cell_type": "markdown",
"id": "bb741f3f",
"metadata": {},
"source": [
"## Asynchronous Embedding\n",
"\n",
"The provider also supports asynchronous operations for better performance when handling multiple requests:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "781d672a",
"metadata": {},
"outputs": [],
"source": [
"async def process_multiple_texts():\n",
" texts = [\n",
" \"First example text\",\n",
" \"Second example text\",\n",
" \"Third example text\"\n",
" ]\n",
"\n",
" # Process texts concurrently\n",
" tasks = [provider.aembed(text) for text in texts]\n",
" results = await asyncio.gather(*tasks)\n",
"\n",
" return results\n",
"\n",
"# Run async example\n",
"results = await process_multiple_texts()\n",
"\n",
"# Display results\n",
"for i, result in enumerate(results, 1):\n",
" print(f\"\\nText {i}:\")\n",
" print(f\"Embedding dimension: {len(result['embeddings'][0])}\")\n",
" print(f\"Token usage: {result['usage']}\")"
]
},
{
"cell_type": "markdown",
"id": "f447fe69",
"metadata": {},
"source": [
"## Error Handling\n",
"\n",
"The provider includes proper error handling for various scenarios:"
"try:\n",
" # Generate embeddings with session tracking\n",
" result = provider.embed(text, session=session)\n",
" print(f\"Embedding dimension: {len(result['data'][0]['embedding'])}\")\n",
" print(f\"Token usage: {result['usage']}\")\n",
"except Exception as e:\n",
" print(f\"Failed to generate embeddings: {e}\")\n",
" raise"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c66abe58",
"metadata": {},
"outputs": [],
"execution_count": 3,
"metadata": {
"execution": {
"iopub.execute_input": "2024-12-14T03:46:07.585666Z",
"iopub.status.busy": "2024-12-14T03:46:07.585395Z",
"iopub.status.idle": "2024-12-14T03:46:08.010057Z",
"shell.execute_reply": "2024-12-14T03:46:08.009256Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"🖇 AgentOps: Session Stats - \u001b[1mDuration:\u001b[0m 1.7s | \u001b[1mCost:\u001b[0m $0.00 | \u001b[1mLLMs:\u001b[0m 1 | \u001b[1mTools:\u001b[0m 0 | \u001b[1mActions:\u001b[0m 0 | \u001b[1mErrors:\u001b[0m 0\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"🖇 AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=940f1741-4776-40a3-9f55-b84661aaa7ed\u001b[0m\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Session completed successfully!\n",
"View session at: https://app.agentops.ai/drilldown?session_id=940f1741-4776-40a3-9f55-b84661aaa7ed\n"
]
}
],
"source": [
"# Example: Handle invalid input\n",
"try:\n",
" result = provider.embed(None)\n",
"except ValueError as e:\n",
" print(f\"Caught ValueError: {e}\")\n",
"\n",
"# Example: Handle API errors\n",
"try:\n",
" # Temporarily set invalid API key\n",
" os.environ[\"VOYAGE_API_KEY\"] = \"invalid-key\"\n",
" new_client = voyageai.Client()\n",
" new_provider = VoyageProvider(new_client)\n",
" result = new_provider.embed(\"test\")\n",
"except Exception as e:\n",
" print(f\"Caught API error: {e}\")\n",
"finally:\n",
" # Restore original API key\n",
" os.environ[\"VOYAGE_API_KEY\"] = \"your-api-key-here\""
"# End the session\n",
"ao_client.end_session(\"Success\", \"Example notebook completed successfully\")\n",
"print(\"\\nSession completed successfully!\")\n",
"print(f\"View session at: {session.session_url}\")"
]
}
],
@@ -176,9 +173,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0"
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
"nbformat_minor": 4
}
66 changes: 66 additions & 0 deletions examples/voyage/voyage_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python
# coding: utf-8

# # Voyage AI Integration Example with AgentOps
#
# This notebook demonstrates how to use the Voyage AI provider with AgentOps for embedding operations using a mock client for demonstration purposes.

import os
import json
import asyncio
from voyageai import Client as VoyageClient
from agentops import Client as AgentopsClient
from agentops.llms.providers.voyage import VoyageProvider


class MockVoyageClient:
def embed(self, texts, **kwargs):
return {
"data": [{"embedding": [0.1] * 1024, "index": 0, "object": "embedding"}],
"model": "voyage-01",
"object": "list",
"usage": {"prompt_tokens": 10, "completion_tokens": 0},
}

async def aembed(self, texts, **kwargs):
return self.embed(texts, **kwargs)


def main():
# Set AgentOps API key
os.environ["AGENTOPS_API_KEY"] = "8b95388c-ee56-499d-a940-c1d6a2ba7f0c"

# Initialize clients
voyage_client = MockVoyageClient()
ao_client = AgentopsClient()

# Initialize session
session = ao_client.initialize()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Bug Fix:

Avoid Hardcoding API Keys
Hardcoding API keys directly in the code poses a significant security risk. It can lead to unauthorized access if the code is exposed in version control or logs.

  • Store the API key in a secure environment variable or a configuration file that is not included in version control.
  • Access the API key using os.environ or a secure configuration management tool.
  • This approach enhances security and prevents potential misuse of the API. 🔒

🔧 Suggested Code Diff:

import os

def main():
    # Set AgentOps API key from environment variable
    api_key = os.getenv("AGENTOPS_API_KEY")
    if not api_key:
        raise ValueError("API key not found. Please set the AGENTOPS_API_KEY environment variable.")
    os.environ["AGENTOPS_API_KEY"] = api_key

    # Initialize clients
    voyage_client = MockVoyageClient()
    ao_client = AgentopsClient()

    # Initialize session
    session = ao_client.initialize()
    print(f"Session URL: {session.session_url}")
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def main():
# Set AgentOps API key
os.environ["AGENTOPS_API_KEY"] = "8b95388c-ee56-499d-a940-c1d6a2ba7f0c"
# Initialize clients
voyage_client = MockVoyageClient()
ao_client = AgentopsClient()
# Initialize session
session = ao_client.initialize()
import os
def main():
# Set AgentOps API key from environment variable
api_key = os.getenv("AGENTOPS_API_KEY")
if not api_key:
raise ValueError("API key not found. Please set the AGENTOPS_API_KEY environment variable.")
os.environ["AGENTOPS_API_KEY"] = api_key
# Initialize clients
voyage_client = MockVoyageClient()
ao_client = AgentopsClient()
# Initialize session
session = ao_client.initialize()
print(f"Session URL: {session.session_url}")
📜 Guidelines
  • Use exceptions for error handling, but avoid assert statements for critical logic.

print(f"Session URL: {session.session_url}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Bug Fix:

Remove Hardcoded API Key
Hardcoding API keys in the code is a significant security risk. It can lead to unauthorized access if the code is exposed. Instead, retrieve the API key from a secure environment variable. This approach enhances security and makes the code more flexible for different environments.

🔧 Suggested Code Diff:

-def main():
-    # Set AgentOps API key
-    os.environ["AGENTOPS_API_KEY"] = "8b95388c-ee56-499d-a940-c1d6a2ba7f0c"
+def main():
+    # Retrieve AgentOps API key from environment variable
+    api_key = os.environ.get("AGENTOPS_API_KEY")
+    if not api_key:
+        raise ValueError("AGENTOPS_API_KEY environment variable not set")
+    os.environ["AGENTOPS_API_KEY"] = api_key

    # Initialize clients
    voyage_client = MockVoyageClient()
    ao_client = AgentopsClient()
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def main():
# Set AgentOps API key
os.environ["AGENTOPS_API_KEY"] = "8b95388c-ee56-499d-a940-c1d6a2ba7f0c"
# Initialize clients
voyage_client = MockVoyageClient()
ao_client = AgentopsClient()
# Initialize session
session = ao_client.initialize()
print(f"Session URL: {session.session_url}")
def main():
# Retrieve AgentOps API key from environment variable
api_key = os.environ.get("AGENTOPS_API_KEY")
if not api_key:
raise ValueError("AGENTOPS_API_KEY environment variable not set")
os.environ["AGENTOPS_API_KEY"] = api_key
# Initialize clients
voyage_client = MockVoyageClient()
ao_client = AgentopsClient()
# Initialize session
session = ao_client.initialize()
print(f"Session URL: {session.session_url}")
📜 Guidelines

Python: Avoid mutable global states


# Set up Voyage provider with mock client
provider = VoyageProvider(client=voyage_client)
provider.override()

try:
# Create embeddings with session tracking
text = "Hello, Voyage!"
result = provider.embed(text, session=session)
print(f"\nEmbedding dimension: {len(result['data'][0]['embedding'])}")

# Print event data for verification
events = session.get_events()
if events:
latest_event = events[-1]
print("\nLatest Event Data:")
print(json.dumps(latest_event, indent=2))
finally:
# Clean up provider override
provider.undo_override()
# End session
ao_client.end_session("Success", "Example completed successfully")
print(f"\nSession ended. View session at: {session.session_url}")


if __name__ == "__main__":
main()
54 changes: 45 additions & 9 deletions tests/test_session.py
Original file line number Diff line number Diff line change
@@ -602,15 +602,16 @@ async def test_export_llm_event(self, setup_teardown, mock_req):
assert event["init_timestamp"] is not None
assert event["end_timestamp"] is not None

@pytest.mark.asyncio # Add async test decorator
@pytest.mark.asyncio
async def test_voyage_provider(self):
"""Test the VoyageProvider class."""
"""Test the VoyageProvider class with event data verification."""
try:
import voyageai
except ImportError:
pytest.skip("voyageai package not installed")

from agentops.llms.providers.voyage import VoyageProvider
from agentops.session import Session # Add Session import

# Test implementation with mock clients
class MockVoyageClient:
@@ -630,18 +631,53 @@ async def aembed(self, input_text, **kwargs):
provider = VoyageProvider(client=mock_client)
provider.override()

# Test sync embedding
result = provider.embed("test input")
# Test sync embedding with event data verification
session = Session()
test_input = "test input"
result = provider.embed(test_input, session=session)

# Verify basic response
assert "embeddings" in result
assert len(result["embeddings"][0]) == 1024
assert all(x == 0.1 for x in result["embeddings"][0])

# Test async embedding
result = await provider.aembed("test input")
# Verify event data
events = session.get_events()
assert len(events) == 1
event = events[0]
assert event.prompt == test_input
assert isinstance(event.completion, dict)
assert "embedding" in event.completion
assert len(event.completion["embedding"]) == 1024
assert all(x == 0.1 for x in event.completion["embedding"])
assert event.model == "voyage-01"
assert event.prompt_tokens == 10
assert event.completion_tokens == 0
assert event.cost == 0.0

# Test async embedding with event data verification
session = Session() # Fresh session for async test
result = await provider.aembed(test_input, session=session)

# Verify basic response
assert "embeddings" in result
assert len(result["embeddings"][0]) == 1024
assert all(x == 0.1 for x in result["embeddings"][0])

# Verify event data
events = session.get_events()
assert len(events) == 1
event = events[0]
assert event.prompt == test_input
assert isinstance(event.completion, dict)
assert "embedding" in event.completion
assert len(event.completion["embedding"]) == 1024
assert all(x == 0.1 for x in event.completion["embedding"])
assert event.model == "voyage-01"
assert event.prompt_tokens == 10
assert event.completion_tokens == 0
assert event.cost == 0.0

# Test error handling
class ErrorClient:
def record(self, event):
@@ -659,12 +695,12 @@ async def aembed(self, input_text, **kwargs):

error_client = ErrorClient()
error_provider = VoyageProvider(client=error_client)
error_provider.override() # Call override to patch methods
error_provider.override()

# Test sync error
with pytest.raises(Exception):
error_provider.embed("test input")

# Test async error - use await with pytest.raises
# Test async error
with pytest.raises(Exception):
await error_provider.aembed("test input") # Changed from async with to await
await error_provider.aembed("test input")