diff --git a/docs/v1/integrations/rest.mdx b/docs/v1/integrations/rest.mdx index a719ce29..910e5298 100644 --- a/docs/v1/integrations/rest.mdx +++ b/docs/v1/integrations/rest.mdx @@ -22,16 +22,26 @@ When you create a session, you'll use your API key and receive a JWT token in re ```bash curl -curl -X POST https://api.agentops.ai/create_session \ - -H "Content-Type: application/json" \ +curl -X POST https://api.agentops.ai/v2/create_session \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "X-Agentops-Api-Key: your_api_key" \ -d '{ - "id": "550e8400-e29b-41d4-a716-446655440000", - "init_timestamp": "2024-03-14T12:00:00Z" + "session": { + "session_id": "550e8400-e29b-41d4-a716-446655440000", + "init_timestamp": "2024-03-14T12:00:00Z", + "tags": ["production"], + "host_env": { + "OS": { + "OS": "Windows", + "OS Release": "11" + } + } + } }' ``` -```json Success Response +```json Success Response (200 OK) { "status": "success", "jwt": "eyJhbGciOiJIUzI1NiIs...", @@ -39,13 +49,19 @@ curl -X POST https://api.agentops.ai/create_session \ } ``` -```bash Error Response -HTTP/1.1 401 Unauthorized +```json Error Response (401 Unauthorized) { "error": "Invalid API key", "message": "Please check your API key and try again" } ``` + +```json Error Response (400 Bad Request) +{ + "error": "Invalid request", + "message": "Missing required fields or invalid format" +} +``` ### Using JWT Tokens @@ -54,22 +70,42 @@ Use the JWT token in the Authorization header for all subsequent requests: ```bash Example Request -curl -X POST https://api.agentops.ai/create_events \ +curl -X POST https://api.agentops.ai/v2/create_events \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -d '{ "events": [{ - "type": "llm", - "init_timestamp": "2024-03-14T12:01:00Z" + "event_type": "llm", + "init_timestamp": "2024-03-14T12:01:00Z", + "end_timestamp": "2024-03-14T12:01:02Z", + "session_id": "550e8400-e29b-41d4-a716-446655440000", + "model": "gpt-4", + "prompt": [ + {"role": "system", "content": "You are a helpful assistant"}, + {"role": "user", "content": "Analyze this data..."} + ], + "completion": { + "role": "assistant", + "content": "Based on the data..." + }, + "prompt_tokens": 150, + "completion_tokens": 80 }] }' ``` -```bash Error Response -HTTP/1.1 401 Unauthorized +```json Error Response (401 Unauthorized) { "error": "Invalid or expired JWT", - "message": "Please reauthorize using /reauthorize_jwt" + "message": "Please reauthorize using /v2/reauthorize_jwt" +} +``` + +```json Error Response (429 Too Many Requests) +{ + "error": "Rate limit exceeded", + "message": "Please try again later" } ``` @@ -81,21 +117,43 @@ JWTs expire after 24 hours. When a token expires, use your API key to get a new ```bash curl curl -X POST https://api.agentops.ai/v2/reauthorize_jwt \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "X-Agentops-Api-Key: your_api_key" \ -d '{ "session_id": "550e8400-e29b-41d4-a716-446655440000" }' ``` -```json Success Response +```json Success Response (200 OK) { "status": "success", "jwt": "eyJhbGciOiJIUzI1NiIs..." } ``` + +```json Error Response (401 Unauthorized) +{ + "error": "Invalid API key", + "message": "Please check your API key and try again" +} +``` +## Error Handling + +The API uses standard HTTP status codes: + +| Status Code | Description | +|------------|-------------| +| 200 | Success | +| 400 | Invalid Request - Check request format and required fields | +| 401 | Unauthorized - Invalid or missing API key/JWT | +| 408 | Request Timeout | +| 413 | Payload Too Large | +| 429 | Too Many Requests - Rate limit exceeded | +| 500 | Internal Server Error | + ## Session Management Sessions require a unique identifier that you generate client-side. While any unique string will work, we recommend using UUIDs for consistency. Here's how to generate one in Python: @@ -115,11 +173,12 @@ Start a new monitoring session using your generated session ID: ```bash curl curl -X POST https://api.agentops.ai/v2/create_session \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "X-Agentops-Api-Key: your_api_key" \ -d '{ "session": { - "id": "550e8400-e29b-41d4-a716-446655440000", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "init_timestamp": "2024-03-14T12:00:00Z", "tags": ["production", "customer-service"], "host_env": { @@ -155,7 +214,7 @@ X-Agentops-Api-Key: your_api_key { "session": { - "id": "550e8400-e29b-41d4-a716-446655440000", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "init_timestamp": "2024-03-14T12:00:00Z", "tags": ["production", "customer-service"], "host_env": { @@ -192,11 +251,12 @@ Update an existing session (e.g., when it ends): ```bash curl curl -X POST https://api.agentops.ai/v2/update_session \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "Authorization: Bearer your_jwt_token" \ -d '{ "session": { - "id": "550e8400-e29b-41d4-a716-446655440000", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "end_timestamp": "2024-03-14T12:05:00Z", "end_state": "Success", "end_state_reason": "Task successfully completed", @@ -212,7 +272,7 @@ Authorization: Bearer your_jwt_token { "session": { - "id": "550e8400-e29b-41d4-a716-446655440000", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "end_timestamp": "2024-03-14T12:05:00Z", "end_state": "Success", "end_state_reason": "Task successfully completed", @@ -231,14 +291,17 @@ Track LLM calls, tool usage, or other events: ```bash curl curl -X POST https://api.agentops.ai/v2/create_events \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "Authorization: Bearer your_jwt_token" \ -d '{ "events": [ { - "type": "llm", + "id": "550e8400-e29b-41d4-a716-446655440001", + "event_type": "llm", "init_timestamp": "2024-03-14T12:01:00Z", "end_timestamp": "2024-03-14T12:01:02Z", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "gpt-4", "prompt": [ {"role": "system", "content": "You are a helpful assistant"}, @@ -252,7 +315,8 @@ curl -X POST https://api.agentops.ai/v2/create_events \ "completion_tokens": 80 }, { - "type": "tool", + "id": "550e8400-e29b-41d4-a716-446655440002", + "event_type": "tool", "name": "database_query", "init_timestamp": "2024-03-14T12:01:03Z", "end_timestamp": "2024-03-14T12:01:04Z", @@ -262,6 +326,7 @@ curl -X POST https://api.agentops.ai/v2/create_events \ ] }' ``` + ```bash Request POST https://api.agentops.ai/v2/create_events @@ -271,9 +336,11 @@ Authorization: Bearer your_jwt_token { "events": [ { - "type": "llm", + "id": "550e8400-e29b-41d4-a716-446655440001", + "event_type": "llm", "init_timestamp": "2024-03-14T12:01:00Z", "end_timestamp": "2024-03-14T12:01:02Z", + "session_id": "550e8400-e29b-41d4-a716-446655440000", "model": "gpt-4", "prompt": [ {"role": "system", "content": "You are a helpful assistant"}, @@ -287,7 +354,8 @@ Authorization: Bearer your_jwt_token "completion_tokens": 80 }, { - "type": "tool", + "id": "550e8400-e29b-41d4-a716-446655440002", + "event_type": "tool", "name": "database_query", "init_timestamp": "2024-03-14T12:01:03Z", "end_timestamp": "2024-03-14T12:01:04Z", @@ -296,8 +364,6 @@ Authorization: Bearer your_jwt_token } ] } -``` - ### Update Events @@ -306,7 +372,8 @@ Update existing events (e.g., adding completion information): ```bash curl curl -X POST https://api.agentops.ai/v2/update_events \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "Authorization: Bearer your_jwt_token" \ -d '{ "events": [ @@ -347,7 +414,8 @@ Register a new agent in a session: ```bash curl curl -X POST https://api.agentops.ai/v2/create_agent \ - -H "Content-Type: application/json" \ + -H "Content-Type: application/json; charset=UTF-8" \ + -H "Accept: */*" \ -H "Authorization: Bearer your_jwt_token" \ -d '{ "id": "agent-123", @@ -376,34 +444,69 @@ Here's a complete example using Python's requests library: import requests import uuid from datetime import datetime, timezone +import json # Configuration API_KEY = "your_api_key" BASE_URL = "https://api.agentops.ai" +HEADERS = { + "Content-Type": "application/json; charset=UTF-8", + "Accept": "*/*" +} + +def handle_response(response): + """Handle API response and common errors""" + try: + response.raise_for_status() + return response.json() + except requests.exceptions.HTTPError as e: + if response.status_code == 401: + print("Authentication error. Check your API key or JWT token.") + elif response.status_code == 429: + print("Rate limit exceeded. Please try again later.") + elif response.status_code == 400: + print("Invalid request format:", response.json().get("message")) + else: + print(f"HTTP error occurred: {e}") + return None + except Exception as e: + print(f"An error occurred: {e}") + return None # Create session session_id = str(uuid.uuid4()) -response = requests.post( +create_session_headers = {**HEADERS, "X-Agentops-Api-Key": API_KEY} +session_response = requests.post( f"{BASE_URL}/v2/create_session", - headers={"X-Agentops-Api-Key": API_KEY}, + headers=create_session_headers, json={ "session": { - "id": session_id, + "session_id": session_id, "init_timestamp": datetime.now(timezone.utc).isoformat(), "tags": ["example"] } } ) -jwt_token = response.json()["jwt"] + +session_data = handle_response(session_response) +if not session_data: + print("Failed to create session") + exit(1) + +jwt_token = session_data["jwt"] # Track LLM call -requests.post( +event_headers = {**HEADERS, "Authorization": f"Bearer {jwt_token}"} +event_response = requests.post( f"{BASE_URL}/v2/create_events", - headers={"Authorization": f"Bearer {jwt_token}"}, + headers=event_headers, json={ "events": [{ - "type": "llm", + "id": str(uuid.uuid4()), # Required field for actions table + "event_type": "llm", "init_timestamp": datetime.now(timezone.utc).isoformat(), + "end_timestamp": datetime.now(timezone.utc).isoformat(), + "session_id": session_id, "model": "gpt-4", "prompt": "Hello, world!", "completion": "Hi there!", @@ -413,17 +516,24 @@ requests.post( } ) +if not handle_response(event_response): + print("Failed to create event") + exit(1) + # End session -requests.post( +end_response = requests.post( f"{BASE_URL}/v2/update_session", - headers={"Authorization": f"Bearer {jwt_token}"}, + headers=event_headers, json={ "session": { - "id": session_id, + "session_id": session_id, "end_timestamp": datetime.now(timezone.utc).isoformat(), - "end_state": "completed" + "end_state": "Success" } } ) + +if not handle_response(end_response): + print("Failed to end session") ``` diff --git a/tests/test_rest_api.py b/tests/test_rest_api.py new file mode 100644 index 00000000..db5c1b59 --- /dev/null +++ b/tests/test_rest_api.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +import os +import requests +import json +import uuid +from typing import Dict, Optional +import requests_mock +from datetime import datetime, timezone + + +class TestRestApi: + def __init__(self): + self.api_key = "11111111-1111-4111-8111-111111111111" # Mock API key in UUID format + self.base_url = "https://api.agentops.ai" + self.jwt_token: Optional[str] = None + self.session_id: str = str(uuid.uuid4()) + self.mock = requests_mock.Mocker() + self.mock.start() + + # Setup mock responses + self.mock.post(f"{self.base_url}/v2/create_session", json={"status": "success", "jwt": "mock_jwt_token"}) + self.mock.post(f"{self.base_url}/v2/create_events", json={"status": "ok"}) + self.mock.post(f"{self.base_url}/v2/update_session", json={"status": "success", "token_cost": 5}) + + def __del__(self): + self.mock.stop() + + def _make_request(self, method: str, endpoint: str, data: Dict, use_jwt: bool = False) -> requests.Response: + """Make HTTP request with proper headers""" + headers = {"Content-Type": "application/json; charset=UTF-8", "Accept": "*/*"} + + if use_jwt and self.jwt_token: + headers["Authorization"] = f"Bearer {self.jwt_token}" + else: + headers["X-Agentops-Api-Key"] = self.api_key + + response = requests.request(method=method, url=f"{self.base_url}{endpoint}", headers=headers, json=data) + + print(f"\n=== {endpoint} ===") + print(f"Status: {response.status_code}") + print(f"Response: {response.text}\n") + + return response + + def test_create_session(self) -> bool: + """Test /v2/create_session endpoint""" + now = datetime.now(timezone.utc).isoformat() + + # Payload structure from OpenAPI spec + payload = {"session_id": self.session_id, "init_timestamp": now, "tags": ["test"], "host_env": {"test": True}} + + response = self._make_request("POST", "/v2/create_session", payload) + + if response.status_code == 200: + self.jwt_token = response.json().get("jwt") + return True + return False + + def test_create_events(self) -> bool: + """Test /v2/create_events endpoint""" + if not self.jwt_token: + print("Error: JWT token required. Run test_create_session first.") + return False + + now = datetime.now(timezone.utc).isoformat() + + payload = { + "events": [ + { + "id": str(uuid.uuid4()), + "event_type": "llm", + "init_timestamp": now, + "end_timestamp": now, + "session_id": self.session_id, + "model": "gpt-4", + "prompt": [ + {"role": "system", "content": "You are a helpful assistant"}, + {"role": "user", "content": "Analyze this data..."}, + ], + "completion": {"role": "assistant", "content": "Based on the data..."}, + "prompt_tokens": 150, + "completion_tokens": 80, + }, + { + "id": str(uuid.uuid4()), + "event_type": "tool", + "name": "database_query", + "init_timestamp": now, + "end_timestamp": now, + "session_id": self.session_id, + "input": "SELECT * FROM users", + "output": "Retrieved 5 users", + }, + ] + } + + response = self._make_request("POST", "/v2/create_events", payload, use_jwt=True) + + return response.status_code == 200 + + def test_update_session(self) -> bool: + """Test /v2/update_session endpoint""" + if not self.jwt_token: + print("Error: JWT token required. Run test_create_session first.") + return False + + now = datetime.now(timezone.utc).isoformat() + + payload = { + "session_id": self.session_id, + "end_timestamp": now, + "end_state": "Success", + "end_state_reason": "Test completed", + } + + response = self._make_request("POST", "/v2/update_session", payload, use_jwt=True) + + return response.status_code == 200 + + def run_all_tests(self): + """Run all API endpoint tests""" + print("Starting REST API endpoint tests...") + + if not self.test_create_session(): + print("❌ create_session test failed") + return + print("✅ create_session test passed") + + if not self.test_create_events(): + print("❌ create_events test failed") + return + print("✅ create_events test passed") + + if not self.test_update_session(): + print("❌ update_session test failed") + return + print("✅ update_session test passed") + + +if __name__ == "__main__": + tester = TestRestApi() + tester.run_all_tests()