Skip to content

Commit

Permalink
Merge branch 'main' into pypi-logo
Browse files Browse the repository at this point in the history
  • Loading branch information
siyangqiu authored May 4, 2024
2 parents d525548 + 388101a commit ad9b584
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
python-version: [3.11]
python-version: [3.7,3.8,3.9,3.10,3.11,3.12]

steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 6 additions & 2 deletions agentops/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# agentops/__init__.py
from os import environ
from typing import Optional, List
from typing import Optional, List, Union

from .client import Client
from .config import Configuration
Expand All @@ -9,6 +9,7 @@
from .decorators import record_function
from .agent import track_agent
from .log_config import set_logging_level_info, set_logging_level_critial
from .langchain_callback_handler import LangchainCallbackHandler, AsyncLangchainCallbackHandler


def init(api_key: Optional[str] = None,
Expand Down Expand Up @@ -86,7 +87,7 @@ def start_session(tags: Optional[List[str]] = None, config: Optional[Configurati
return Client().start_session(tags, config, inherited_session_id)


def record(event: Event | ErrorEvent):
def record(event: Union[Event, ErrorEvent]):
"""
Record an event with the AgentOps service.
Expand Down Expand Up @@ -128,3 +129,6 @@ def set_parent_key(parent_key):
parent_key (str): The API key of the parent organization to set.
"""
Client().set_parent_key(parent_key)

def stop_instrumenting():
Client().stop_instrumenting()
4 changes: 3 additions & 1 deletion agentops/agent.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import Union

from .log_config import logger
from uuid import uuid4
from agentops import Client
from inspect import isclass, isfunction


def track_agent(name: str | None = None):
def track_agent(name: Union[str, None] = None):
def decorator(obj):
if name:
obj.agent_ops_agent_name = name
Expand Down
10 changes: 6 additions & 4 deletions agentops/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .worker import Worker
from .host_env import get_host_env
from uuid import uuid4
from typing import Optional, List
from typing import Optional, List, Union
import traceback
from .log_config import logger, set_logging_level_info
from decimal import Decimal
Expand Down Expand Up @@ -114,7 +114,6 @@ def add_tags(self, tags: List[str]):
self._session.tags = tags

if self._session is not None and self._worker is not None:
self._session.tags = self._tags
self._worker.update_session(self._session)

def set_tags(self, tags: List[str]):
Expand All @@ -130,14 +129,14 @@ def set_tags(self, tags: List[str]):
self._session.tags = tags
self._worker.update_session(self._session)

def record(self, event: Event | ErrorEvent):
def record(self, event: Union[Event, ErrorEvent]):
"""
Record an event with the AgentOps service.
Args:
event (Event): The event to record.
"""
if not event.end_timestamp or event.init_timestamp == event.end_timestamp:
if isinstance(event, Event) and not event.end_timestamp or event.init_timestamp == event.end_timestamp:
event.end_timestamp = get_ISO_time()
if self._session is not None and not self._session.has_ended and self._worker is not None:
if isinstance(event, ErrorEvent):
Expand Down Expand Up @@ -360,3 +359,6 @@ def set_parent_key(self, parent_key: str):
@property
def parent_key(self):
return self.config.parent_key

def stop_instrumenting(self):
self.llm_tracker.stop_instrumenting()
18 changes: 9 additions & 9 deletions agentops/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"""

from dataclasses import asdict, dataclass, field
from typing import Any, Dict, List, Optional, Sequence
from typing import Any, Dict, List, Optional, Sequence, Union
from .helpers import get_ISO_time, check_call_stack_for_agent_id
from .enums import EventType, Models
from uuid import UUID, uuid4
Expand Down Expand Up @@ -38,8 +38,8 @@ class Event:
"""

event_type: str # EventType.ENUM.value
params: Optional[str | Dict[str, Any]] = None
returns: Optional[str | Dict[str, Any]] = None
params: Optional[Union[str, Dict[str, Any]]] = None
returns: Optional[Union[str, Dict[str, Any]]] = None
init_timestamp: Optional[str] = field(default_factory=get_ISO_time)
end_timestamp: str = field(default_factory=get_ISO_time)
agent_id: Optional[UUID] = field(default_factory=check_call_stack_for_agent_id)
Expand All @@ -60,7 +60,7 @@ class ActionEvent(Event):
event_type: str = EventType.ACTION.value
# TODO: Should not be optional, but non-default argument 'agent_id' follows default argument error
action_type: Optional[str] = None
logs: Optional[str | Sequence[Any]] = None
logs: Optional[Union[str, Sequence[Any]]] = None
screenshot: Optional[str] = None

# May be needed if we keep Optional for agent_id
Expand All @@ -86,11 +86,11 @@ class LLMEvent(Event):

event_type: str = EventType.LLM.value
thread_id: Optional[UUID] = None
prompt: Optional[str | List] = None
prompt: Optional[Union[str, List]] = None
prompt_tokens: Optional[int] = None
completion: str | object = None
completion: Union[str, object] = None
completion_tokens: Optional[int] = None
model: Optional[Models | str] = None
model: Optional[Union[Models, str]] = None


@dataclass
Expand All @@ -104,7 +104,7 @@ class ToolEvent(Event):
"""
event_type: str = EventType.TOOL.value
name: Optional[str] = None
logs: Optional[str | dict] = None
logs: Optional[Union[str, dict]] = None

# Does not inherit from Event because error will (optionally) be linked to an ActionEvent, LLMEvent, etc that will have the details

Expand All @@ -129,7 +129,7 @@ class ErrorEvent():
exception: Optional[BaseException] = None
error_type: Optional[str] = None
code: Optional[str] = None
details: Optional[str | Dict[str, str]] = None
details: Optional[Union[str, Dict[str, str]]] = None
logs: Optional[str] = field(default_factory=traceback.format_exc)
timestamp: str = field(default_factory=get_ISO_time)

Expand Down
4 changes: 3 additions & 1 deletion agentops/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from datetime import datetime
import json
import inspect
from typing import Union

from .log_config import logger
from uuid import UUID
import os
Expand Down Expand Up @@ -76,7 +78,7 @@ def remove_none_values(value):
return json.dumps(cleaned_obj, default=default)


def check_call_stack_for_agent_id() -> UUID | None:
def check_call_stack_for_agent_id() -> Union[UUID, None]:
for frame_info in inspect.stack():
# Look through the call stack for the class that called the LLM
local_vars = frame_info.frame.f_locals
Expand Down
24 changes: 20 additions & 4 deletions agentops/llm_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from typing import Optional
import pprint

original_create = None
original_create_async = None

class LlmTracker:
SUPPORTED_APIS = {
Expand Down Expand Up @@ -71,8 +73,6 @@ def handle_stream_chunk(chunk):
kwargs_str = pprint.pformat(kwargs)
chunk = pprint.pformat(chunk)
logger.warning(
"🖇 AgentOps: Unable to parse a chunk for LLM call %s - skipping upload to AgentOps",
kwargs)
f"🖇 AgentOps: Unable to parse a chunk for LLM call. Skipping upload to AgentOps\n"
f"chunk:\n {chunk}\n"
f"kwargs:\n {kwargs_str}\n"
Expand Down Expand Up @@ -232,6 +232,7 @@ def override_openai_v1_completion(self):
from openai.resources.chat import completions

# Store the original method
global original_create
original_create = completions.Completions.create

def patched_function(*args, **kwargs):
Expand All @@ -247,12 +248,13 @@ def override_openai_v1_async_completion(self):
from openai.resources.chat import completions

# Store the original method
original_create = completions.AsyncCompletions.create
global original_create_async
original_create_async = completions.AsyncCompletions.create

async def patched_function(*args, **kwargs):
# Call the original function with its original arguments
init_timestamp = get_ISO_time()
result = await original_create(*args, **kwargs)
result = await original_create_async(*args, **kwargs)
return self._handle_response_v1_openai(result, kwargs, init_timestamp)

# Override the original method with the patched one
Expand Down Expand Up @@ -347,3 +349,17 @@ def override_api(self):
# Patch openai <v1.0.0 methods
for method_path in self.SUPPORTED_APIS['openai']['0.0.0']:
self._override_method(api, method_path, module)

def stop_instrumenting(self):
self.undo_override_openai_v1_async_completion()
self.undo_override_openai_v1_completion()

def undo_override_openai_v1_completion(self):
global original_create
from openai.resources.chat import completions
completions.Completions.create = original_create

def undo_override_openai_v1_async_completion(self):
global original_create_async
from openai.resources.chat import completions
original_create_async = completions.AsyncCompletions.create
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "agentops"
version = "0.1.7"
version = "0.1.8"
authors = [
{ name="Alex Reibman", email="[email protected]" },
{ name="Shawn Qiu", email="[email protected]" },
Expand All @@ -13,7 +13,7 @@ authors = [
]
description = "Python SDK for developing AI agent evals and observability"
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
Expand Down
4 changes: 3 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# and then run "tox" from this directory.

[tox]
envlist = py310,py311,py312
envlist = py37,py38,py39,py310,py311,py312

[testenv]
deps =
Expand All @@ -17,6 +17,8 @@ deps =
types-requests
psutil
openai
langchain-core
langchain
commands =
coverage run --source agentops -m pytest
coverage report -m
Expand Down

0 comments on commit ad9b584

Please sign in to comment.