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

Copy of PR #385 - Dead letter queue #13

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .github/workflows/python-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
matrix:
python-version: [3.7,3.8,3.9,3.10,3.11,3.12]

env:
ENVIRONMENT: test

steps:
- uses: actions/checkout@v2
- name: Set up Python
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,5 @@ cython_debug/
.DS_Store

agentops_time_travel.json
.agentops_time_travel.yaml
.agentops_time_travel.yaml
.agentops/
2 changes: 2 additions & 0 deletions agentops/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from uuid import UUID

from .log_config import logger
from .singleton import singleton


@singleton
class Configuration:
def __init__(self):
Copy link

Choose a reason for hiding this comment

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

Comment: Use of environment variables for configuration.

Solution: Consider using a library like python-dotenv to manage environment variables more securely.
!! Make sure the following suggestion is correct before committing it !!

Suggested change
def __init__(self):
self.api_key: Optional[str] = os.getenv('API_KEY')

self.api_key: Optional[str] = None
Comment on lines 2 to 11

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🔴

Thread Safety of Singleton Implementation

The introduction of the singleton pattern to the Configuration class is a good design choice for ensuring a single instance. However, ensure that the singleton implementation is thread-safe to prevent issues in multi-threaded environments.

+@singleton
Commitable Code Suggestion:
Suggested change
from uuid import UUID
from .log_config import logger
from .singleton import singleton
@singleton
class Configuration:
def __init__(self):
self.api_key: Optional[str] = None
@singleton

Comment on lines 2 to 11

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🟡

Singleton Implementation Safety

The addition of the @singleton decorator to the Configuration class is a good design choice to ensure a single instance is used throughout the application. However, ensure that the singleton implementation is thread-safe to avoid potential issues in a multi-threaded environment.

Expand Down
18 changes: 17 additions & 1 deletion agentops/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import http.client
import json
from importlib.metadata import version, PackageNotFoundError

from .log_config import logger
from uuid import UUID
from importlib.metadata import version
import os


def get_ISO_time():
Expand Down Expand Up @@ -179,3 +179,19 @@ def wrapper(self, *args, **kwargs):
return func(self, *args, **kwargs)

return wrapper


def ensure_dead_letter_queue():
# Define file path
file_path = os.path.join(".agentops", "dead_letter_queue.json")

# Check if directory exists
if not os.path.exists(".agentops"):
os.makedirs(".agentops")

# Check if file exists
if not os.path.isfile(file_path):
with open(file_path, "w") as f:
json.dump({"messages": []}, f)

return file_path
Comment on lines 179 to +197

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

⚠️ Critical Issue 🔴

Lack of Error Handling in DLQ Creation

The ensure_dead_letter_queue function creates a directory and a file without handling potential exceptions. If the directory creation fails due to permission issues or other IO errors, it could lead to unhandled exceptions in the application. Consider adding error handling to manage these scenarios gracefully.

+    try:
+        if not os.path.exists('.agentops'):
+            os.makedirs('.agentops')
+    except OSError as e:
+        logger.error(f'Error creating directory: {e}')
+        raise
Commitable Code Suggestion:
Suggested change
return func(self, *args, **kwargs)
return wrapper
def ensure_dead_letter_queue():
# Define file path
file_path = os.path.join(".agentops", "dead_letter_queue.json")
# Check if directory exists
if not os.path.exists(".agentops"):
os.makedirs(".agentops")
# Check if file exists
if not os.path.isfile(file_path):
with open(file_path, "w") as f:
json.dump({"messages": []}, f)
return file_path
try:
if not os.path.exists('.agentops'):
os.makedirs('.agentops')
except OSError as e:
logger.error(f'Error creating directory: {e}')
raise

🔒 Security Suggestion 🔴

Potential Security Risk in JSON File Creation

The function ensure_dead_letter_queue creates a JSON file without validating the contents. If the application is compromised, an attacker could potentially manipulate the file. Consider implementing validation for the contents of the JSON file before writing to it.

+    # Validate the content before writing
+    content = {'messages': []}
+    if not isinstance(content, dict):
+        raise ValueError('Invalid content for dead letter queue')
+    json.dump(content, f)
Commitable Code Suggestion:
Suggested change
return func(self, *args, **kwargs)
return wrapper
def ensure_dead_letter_queue():
# Define file path
file_path = os.path.join(".agentops", "dead_letter_queue.json")
# Check if directory exists
if not os.path.exists(".agentops"):
os.makedirs(".agentops")
# Check if file exists
if not os.path.isfile(file_path):
with open(file_path, "w") as f:
json.dump({"messages": []}, f)
return file_path
# Validate the content before writing
content = {'messages': []}
if not isinstance(content, dict):
raise ValueError('Invalid content for dead letter queue')
json.dump(content, f)

Comment on lines 179 to +197

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

⚠️ Critical Issue 🔴

Lack of Error Handling in Dead Letter Queue Setup

The ensure_dead_letter_queue function creates a directory and a file without handling potential exceptions. If the directory creation fails (e.g., due to permission issues), the function will not handle this gracefully, which could lead to unhandled exceptions in the application. Consider adding error handling to manage these scenarios.

+    try:
+        if not os.path.exists('.agentops'):
+            os.makedirs('.agentops')
+    except OSError as e:
+        logger.error(f'Failed to create directory: {e}')
+        return None
Commitable Code Suggestion:
Suggested change
return func(self, *args, **kwargs)
return wrapper
def ensure_dead_letter_queue():
# Define file path
file_path = os.path.join(".agentops", "dead_letter_queue.json")
# Check if directory exists
if not os.path.exists(".agentops"):
os.makedirs(".agentops")
# Check if file exists
if not os.path.isfile(file_path):
with open(file_path, "w") as f:
json.dump({"messages": []}, f)
return file_path
try:
if not os.path.exists('.agentops'):
os.makedirs('.agentops')
except OSError as e:
logger.error(f'Failed to create directory: {e}')
return None

🔒 Security Suggestion 🔴

Data Validation Before Writing to File

The ensure_dead_letter_queue function writes to a JSON file without validating the contents or ensuring that the data being written is safe. This could lead to potential security issues if the data is manipulated. Consider validating the data before writing it to the file.

+    # Validate data before writing
+    data_to_write = {'messages': []}
+    if isinstance(data_to_write, dict):
+        json.dump(data_to_write, f)
Commitable Code Suggestion:
Suggested change
return func(self, *args, **kwargs)
return wrapper
def ensure_dead_letter_queue():
# Define file path
file_path = os.path.join(".agentops", "dead_letter_queue.json")
# Check if directory exists
if not os.path.exists(".agentops"):
os.makedirs(".agentops")
# Check if file exists
if not os.path.isfile(file_path):
with open(file_path, "w") as f:
json.dump({"messages": []}, f)
return file_path
# Validate data before writing
data_to_write = {'messages': []}
if isinstance(data_to_write, dict):
json.dump(data_to_write, f)

217 changes: 176 additions & 41 deletions agentops/http_client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
from datetime import datetime
from enum import Enum
from typing import Optional
from typing import Optional, List, Union

import jwt
from requests.adapters import Retry, HTTPAdapter
import requests
from agentops.log_config import logger
from .config import Configuration

from .exceptions import ApiServerException
from dotenv import load_dotenv
import os

from .helpers import ensure_dead_letter_queue, filter_unjsonable, safe_serialize
import json

load_dotenv()

JSON_HEADER = {"Content-Type": "application/json; charset=UTF-8", "Accept": "*/*"}

Expand All @@ -21,8 +33,49 @@ class HttpStatus(Enum):
UNKNOWN = -1


class Response:
class DeadLetterQueue:
def __init__(self):
self.queue: List[dict] = []
self.is_testing = os.environ.get("ENVIRONMENT") == "test"

# if not self.is_testing:
self.file_path = ensure_dead_letter_queue()

def read_queue(self):
if not self.is_testing:
with open(self.file_path, "r") as f:
return json.load(f)["messages"]
else:
return []

def write_queue(self):
if not self.is_testing:
with open(self.file_path, "w") as f:
json.dump({"messages": safe_serialize(self.queue)}, f)

def add(self, request_data: dict):
if not self.is_testing:
self.queue.append(request_data)
self.write_queue()

def get_all(self) -> List[dict]:
return self.queue

def remove(self, request_data: dict):
if not self.is_testing:
if request_data in self.queue:
self.queue.remove(request_data)
self.write_queue()

def clear(self):
self.queue.clear()
self.write_queue()


dead_letter_queue = DeadLetterQueue()


class Response:
def __init__(
self, status: HttpStatus = HttpStatus.UNKNOWN, body: Optional[dict] = None
):
Comment on lines 33 to 81

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🔴

Add Error Handling for File Operations

The DeadLetterQueue class writes to a file without handling potential I/O exceptions. Consider adding error handling to manage cases where the file cannot be accessed or written to, which could lead to unhandled exceptions during runtime.

+    def write_queue(self):
+        try:
+            if not self.is_testing:
+                with open(self.file_path, "w") as f:
+                    json.dump({"messages": safe_serialize(self.queue)}, f)
+        except IOError as e:
+            logger.error(f"Failed to write to dead letter queue: {e}")
Commitable Code Suggestion:
Suggested change
UNKNOWN = -1
class Response:
class DeadLetterQueue:
def __init__(self):
self.queue: List[dict] = []
self.is_testing = os.environ.get("ENVIRONMENT") == "test"
# if not self.is_testing:
self.file_path = ensure_dead_letter_queue()
def read_queue(self):
if not self.is_testing:
with open(self.file_path, "r") as f:
return json.load(f)["messages"]
else:
return []
def write_queue(self):
if not self.is_testing:
with open(self.file_path, "w") as f:
json.dump({"messages": safe_serialize(self.queue)}, f)
def add(self, request_data: dict):
if not self.is_testing:
self.queue.append(request_data)
self.write_queue()
def get_all(self) -> List[dict]:
return self.queue
def remove(self, request_data: dict):
if not self.is_testing:
if request_data in self.queue:
self.queue.remove(request_data)
self.write_queue()
def clear(self):
self.queue.clear()
self.write_queue()
dead_letter_queue = DeadLetterQueue()
class Response:
def __init__(
self, status: HttpStatus = HttpStatus.UNKNOWN, body: Optional[dict] = None
):
try:
if not self.is_testing:
with open(self.file_path, "w") as f:
json.dump({"messages": safe_serialize(self.queue)}, f)
except IOError as e:
logger.error(f"Failed to write to dead letter queue: {e}")

📜 Guidelines:
Handle I/O exceptions when performing file operations to ensure robustness.

Expand Down Expand Up @@ -57,15 +110,13 @@ def get_status(code: int) -> HttpStatus:


class HttpClient:

@staticmethod
def post(
url: str,
payload: bytes,
api_key: Optional[str] = None,
parent_key: Optional[str] = None,
jwt: Optional[str] = None,
header=None,
token: Optional[str] = None,
) -> Response:
result = Response()
try:
Comment on lines 110 to 122

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🟡

Consolidate Exception Handling

The error handling in the post method could be improved by consolidating the exception handling for requests.exceptions.Timeout and requests.exceptions.HTTPError. This will reduce code duplication and improve readability.

-        except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
-            HttpClient._handle_failed_request(
-                url, payload, api_key, parent_key, token, type(e).__name__
-            )
+        except requests.exceptions.RequestException as e:
+            HttpClient._handle_failed_request(
+                url, payload, api_key, parent_key, token, type(e).__name__
+            )
Commitable Code Suggestion:
Suggested change
class HttpClient:
@staticmethod
def post(
url: str,
payload: bytes,
api_key: Optional[str] = None,
parent_key: Optional[str] = None,
jwt: Optional[str] = None,
header=None,
token: Optional[str] = None,
) -> Response:
result = Response()
try:
except requests.exceptions.RequestException as e:
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, type(e).__name__
)

📜 Guidelines:
Consolidate similar exception handling to improve code readability.

Expand All @@ -79,34 +130,47 @@ def post(
if parent_key is not None:
JSON_HEADER["X-Agentops-Parent-Key"] = parent_key

if jwt is not None:
JSON_HEADER["Authorization"] = f"Bearer {jwt}"
if token is not None:
decoded_jwt = jwt.decode(
token,
algorithms=["HS256"],
options={"verify_signature": False},
)

# if token is expired, reauth
if datetime.fromtimestamp(decoded_jwt["exp"]) < datetime.now():
new_jwt = reauthorize_jwt(
token,
api_key,
decoded_jwt["session_id"],
)
token = new_jwt

JSON_HEADER["Authorization"] = f"Bearer {token}"

res = request_session.post(
url, data=payload, headers=JSON_HEADER, timeout=20
)

result.parse(res)
except requests.exceptions.Timeout:
result.code = 408
result.status = HttpStatus.TIMEOUT
raise ApiServerException(
"Could not reach API server - connection timed out"

if result.code == 200:
HttpClient._retry_dlq_requests()

except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, type(e).__name__
)
except requests.exceptions.HTTPError as e:
try:
result.parse(e.response)
except Exception:
result = Response()
result.code = e.response.status_code
result.status = Response.get_status(e.response.status_code)
result.body = {"error": str(e)}
raise ApiServerException(f"HTTPError: {e}")
raise ApiServerException(f"{type(e).__name__}: {e}")
except requests.exceptions.RequestException as e:
result.body = {"error": str(e)}
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, "RequestException"
)
raise ApiServerException(f"RequestException: {e}")

if result.code == 401:
if result.body.get("message") == "Expired Token":
raise ApiServerException(f"API server: jwt token expired.")
raise ApiServerException(
f"API server: invalid API key: {api_key}. Find your API key at https://app.agentops.ai/settings/projects"
)
Comment on lines 130 to 176

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

🔒 Security vulnerability 🔴

JWT Signature Verification Missing

The JWT token is decoded without verifying the signature, which poses a security risk. Always verify the JWT signature to ensure its authenticity before using the token.

+                decoded_jwt = jwt.decode(
+                    token,
+                    algorithms=["HS256"],
+                    options={"verify_signature": True},
+                )
Commitable Code Suggestion:
Suggested change
if parent_key is not None:
JSON_HEADER["X-Agentops-Parent-Key"] = parent_key
if jwt is not None:
JSON_HEADER["Authorization"] = f"Bearer {jwt}"
if token is not None:
decoded_jwt = jwt.decode(
token,
algorithms=["HS256"],
options={"verify_signature": False},
)
# if token is expired, reauth
if datetime.fromtimestamp(decoded_jwt["exp"]) < datetime.now():
new_jwt = reauthorize_jwt(
token,
api_key,
decoded_jwt["session_id"],
)
token = new_jwt
JSON_HEADER["Authorization"] = f"Bearer {token}"
res = request_session.post(
url, data=payload, headers=JSON_HEADER, timeout=20
)
result.parse(res)
except requests.exceptions.Timeout:
result.code = 408
result.status = HttpStatus.TIMEOUT
raise ApiServerException(
"Could not reach API server - connection timed out"
if result.code == 200:
HttpClient._retry_dlq_requests()
except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, type(e).__name__
)
except requests.exceptions.HTTPError as e:
try:
result.parse(e.response)
except Exception:
result = Response()
result.code = e.response.status_code
result.status = Response.get_status(e.response.status_code)
result.body = {"error": str(e)}
raise ApiServerException(f"HTTPError: {e}")
raise ApiServerException(f"{type(e).__name__}: {e}")
except requests.exceptions.RequestException as e:
result.body = {"error": str(e)}
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, "RequestException"
)
raise ApiServerException(f"RequestException: {e}")
if result.code == 401:
if result.body.get("message") == "Expired Token":
raise ApiServerException(f"API server: jwt token expired.")
raise ApiServerException(
f"API server: invalid API key: {api_key}. Find your API key at https://app.agentops.ai/settings/projects"
)
decoded_jwt = jwt.decode(
token,
algorithms=["HS256"],
options={"verify_signature": True},
)

📜 Guidelines:
Always verify JWT signatures to ensure authenticity.

Comment on lines 130 to 176

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

🔒 Security vulnerability 🔴

JWT Signature Verification Missing

The new implementation decodes the JWT token without verifying its signature, which poses a security risk. Ensure that the token is verified before using its claims to prevent potential attacks.

+                decoded_jwt = jwt.decode(
+                    token,
+                    algorithms=["HS256"],
+                    options={"verify_signature": True},
+                )
Commitable Code Suggestion:
Suggested change
if parent_key is not None:
JSON_HEADER["X-Agentops-Parent-Key"] = parent_key
if jwt is not None:
JSON_HEADER["Authorization"] = f"Bearer {jwt}"
if token is not None:
decoded_jwt = jwt.decode(
token,
algorithms=["HS256"],
options={"verify_signature": False},
)
# if token is expired, reauth
if datetime.fromtimestamp(decoded_jwt["exp"]) < datetime.now():
new_jwt = reauthorize_jwt(
token,
api_key,
decoded_jwt["session_id"],
)
token = new_jwt
JSON_HEADER["Authorization"] = f"Bearer {token}"
res = request_session.post(
url, data=payload, headers=JSON_HEADER, timeout=20
)
result.parse(res)
except requests.exceptions.Timeout:
result.code = 408
result.status = HttpStatus.TIMEOUT
raise ApiServerException(
"Could not reach API server - connection timed out"
if result.code == 200:
HttpClient._retry_dlq_requests()
except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, type(e).__name__
)
except requests.exceptions.HTTPError as e:
try:
result.parse(e.response)
except Exception:
result = Response()
result.code = e.response.status_code
result.status = Response.get_status(e.response.status_code)
result.body = {"error": str(e)}
raise ApiServerException(f"HTTPError: {e}")
raise ApiServerException(f"{type(e).__name__}: {e}")
except requests.exceptions.RequestException as e:
result.body = {"error": str(e)}
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, "RequestException"
)
raise ApiServerException(f"RequestException: {e}")
if result.code == 401:
if result.body.get("message") == "Expired Token":
raise ApiServerException(f"API server: jwt token expired.")
raise ApiServerException(
f"API server: invalid API key: {api_key}. Find your API key at https://app.agentops.ai/settings/projects"
)
decoded_jwt = jwt.decode(
token,
algorithms=["HS256"],
options={"verify_signature": True},
)```
<br>
</details>
<details>
<summary>📜 Guidelines:</summary>
<br>
Ensure that JWT tokens are verified before use to prevent security vulnerabilities.
<br><br>
</details>

Expand All @@ -116,6 +180,9 @@ def post(
else:
raise ApiServerException(f"API server: {result.body}")
if result.code == 500:
HttpClient._handle_failed_request(
url, payload, api_key, parent_key, token, "ServerError"
)
raise ApiServerException("API server: - internal server error")

return result
Expand All @@ -124,8 +191,7 @@ def post(
def get(
url: str,
api_key: Optional[str] = None,
jwt: Optional[str] = None,
header=None,
token: Optional[str] = None,
) -> Response:
result = Response()
try:
Expand All @@ -136,29 +202,25 @@ def get(
if api_key is not None:
JSON_HEADER["X-Agentops-Api-Key"] = api_key

if jwt is not None:
JSON_HEADER["Authorization"] = f"Bearer {jwt}"
if token is not None:
JSON_HEADER["Authorization"] = f"Bearer {token}"

res = request_session.get(url, headers=JSON_HEADER, timeout=20)

result.parse(res)
except requests.exceptions.Timeout:
result.code = 408
result.status = HttpStatus.TIMEOUT
raise ApiServerException(
"Could not reach API server - connection timed out"

if result.code == 200:
HttpClient._retry_dlq_requests()

except (requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
HttpClient._handle_failed_request(
url, None, api_key, None, token, type(e).__name__
)
except requests.exceptions.HTTPError as e:
try:
result.parse(e.response)
except Exception:
result = Response()
result.code = e.response.status_code
result.status = Response.get_status(e.response.status_code)
result.body = {"error": str(e)}
raise ApiServerException(f"HTTPError: {e}")
raise ApiServerException(f"{type(e).__name__}: {e}")
except requests.exceptions.RequestException as e:
result.body = {"error": str(e)}
HttpClient._handle_failed_request(
url, None, api_key, None, token, "RequestException"
)
raise ApiServerException(f"RequestException: {e}")

if result.code == 401:
Expand All @@ -171,6 +233,79 @@ def get(
else:
raise ApiServerException(f"API server: {result.body}")
if result.code == 500:
HttpClient._handle_failed_request(
url, None, api_key, None, jwt, "ServerError"
)
raise ApiServerException("API server: - internal server error")

return result

@staticmethod
def _retry_dlq_requests():
"""Retry requests in the DLQ"""
for failed_request in dead_letter_queue.get_all():
dead_letter_queue.clear()
try:
if "payload" in failed_request:
# Retry POST request from DLQ
HttpClient.post(
failed_request["url"],
json.dumps(filter_unjsonable(failed_request["payload"])).encode(
"utf-8"
),
failed_request["api_key"],
failed_request["parent_key"],
failed_request["jwt"],
)
else:
# Retry GET request from DLQ
HttpClient.get(
failed_request["url"],
failed_request["api_key"],
failed_request["jwt"],
)
except ApiServerException as e:
dead_letter_queue.add(failed_request)
# If it still fails, keep it in the DLQ
except Exception as e:
dead_letter_queue.add(failed_request)

@staticmethod
def _handle_failed_request(
url: str,
payload: Optional[bytes],
api_key: Optional[str],
parent_key: Optional[str],
jwt: Optional[str],
error_type: str,
):
dead_letter_queue.add(
{
"url": url,
"payload": payload,
"api_key": api_key,
"parent_key": parent_key,
"jwt": jwt,
"error_type": error_type,
}
)

logger.warning(
f"An error occurred while communicating with the server: {error_type}"
)


def reauthorize_jwt(old_jwt: str, api_key: str, session_id: str) -> Union[str, None]:
payload = {"jwt": old_jwt, "session_id": session_id}
serialized_payload = json.dumps(filter_unjsonable(payload)).encode("utf-8")
config = Configuration()
res = HttpClient.post(
f"{config.endpoint}/v2/reauthorize_jwt",
serialized_payload,
api_key,
)

if res.code != 200:
return None

return res.body.get("jwt", None)
8 changes: 4 additions & 4 deletions agentops/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def format_duration(start_time, end_time):
res = HttpClient.post(
f"{self.config.endpoint}/v2/update_session",
json.dumps(filter_unjsonable(payload)).encode("utf-8"),
jwt=self.jwt,
token=self.jwt,
)
except ApiServerException as e:
return logger.error(f"Could not end session - {e}")
Comment on lines 125 to 131

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

🔒 Security Suggestion 🔴

Clarify Token Usage

Changing the parameter name from jwt to token in the HTTP client calls may lead to confusion if the token is still a JWT. Ensure that the token being passed is indeed a JWT and that this change does not affect any existing functionality that relies on the jwt parameter.

Comment on lines 125 to 131

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

🔒 Security Suggestion 🔴

Token Naming Consistency

Changing the parameter name from jwt to token may lead to confusion if the token is still a JWT. Ensure that the new naming convention is consistent throughout the codebase and that the token is validated properly to prevent unauthorized access.

-                    jwt=self.jwt,
+                    token=self.jwt,
Commitable Code Suggestion:
Suggested change
res = HttpClient.post(
f"{self.config.endpoint}/v2/update_session",
json.dumps(filter_unjsonable(payload)).encode("utf-8"),
jwt=self.jwt,
token=self.jwt,
)
except ApiServerException as e:
return logger.error(f"Could not end session - {e}")
token=self.jwt,

Expand Down Expand Up @@ -289,7 +289,7 @@ def _update_session(self) -> None:
res = HttpClient.post(
f"{self.config.endpoint}/v2/update_session",
json.dumps(filter_unjsonable(payload)).encode("utf-8"),
jwt=self.jwt,
token=self.jwt,
)
except ApiServerException as e:
return logger.error(f"Could not update session - {e}")
Comment on lines 289 to 295

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🔴

Ensure Consistency in Parameter Naming

The change from jwt to token should be consistently applied across all relevant methods. Ensure that all parts of the codebase that interact with these methods are updated accordingly to prevent any potential runtime errors.

Comment on lines 289 to 295

Choose a reason for hiding this comment

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

Entelligence AI Bot Icon Entelligence AI Bot v4

💻 Code maintainability 🔴

Update Documentation for Token Usage

The change from jwt to token should be reflected in all related documentation and comments to avoid confusion for future developers. Ensure that any references to JWT in the code are updated to reflect the new token usage.

Expand All @@ -311,7 +311,7 @@ def _flush_queue(self) -> None:
HttpClient.post(
f"{self.config.endpoint}/v2/create_events",
serialized_payload,
jwt=self.jwt,
token=self.jwt,
)
except ApiServerException as e:
return logger.error(f"Could not post events - {e}")
Expand Down Expand Up @@ -360,7 +360,7 @@ def create_agent(self, name, agent_id):
HttpClient.post(
f"{self.config.endpoint}/v2/create_agent",
serialized_payload,
jwt=self.jwt,
token=self.jwt,
)
except ApiServerException as e:
return logger.error(f"Could not create agent - {e}")
Expand Down
Loading
Loading