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

Autogen latency v2 #30

Closed
wants to merge 15 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
182 changes: 171 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,27 @@
</div>

<p align="center">
<a href="https://twitter.com/agentopsai/">🐦 Twitter</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://discord.gg/FagdcwwXRR">📢 Discord</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://app.agentops.ai/?ref=gh">🖇️ Dashboard</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://docs.agentops.ai/introduction">📙 Documentation</a>
<span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
<a href="https://entelligence.ai/AgentOps-AI&agentops">💬 Chat with Docs</a>
<a href="https://twitter.com/agentopsai/">
<img src="https://img.shields.io/twitter/follow/agentopsai?style=social" alt="Twitter" style="height: 20px;">
</a>
<a href="https://discord.gg/FagdcwwXRR">
<img src="https://img.shields.io/badge/discord-7289da.svg?style=flat-square&logo=discord" alt="Discord" style="height: 20px;">
</a>
<a href="https://app.agentops.ai/?ref=gh">
<img src="https://img.shields.io/badge/Dashboard-blue.svg?style=flat-square" alt="Dashboard" style="height: 20px;">
</a>
<a href="https://docs.agentops.ai/introduction">
<img src="https://img.shields.io/badge/Documentation-orange.svg?style=flat-square" alt="Documentation" style="height: 20px;">
</a>
<a href="https://entelligence.ai/AgentOps-AI&agentops">
<img src="https://img.shields.io/badge/Chat%20with%20Docs-green.svg?style=flat-square" alt="Chat with Docs" style="height: 20px;">
</a>
</p>



<div style="justify-content: center">
<img src="docs/images/external/app_screenshots/dashboard_banner.png" alt="Dashboard Banner">
<img src="docs/images/external/app_screenshots/dashboard-banner.png" alt="Dashboard Banner">
</div>

<br/>
Expand Down Expand Up @@ -83,7 +91,13 @@ All your sessions can be viewed on the [AgentOps dashboard](https://app.agentops
<details>
<summary>Agent Debugging</summary>
<a href="https://app.agentops.ai?ref=gh">
<img src="docs/images/external/app_screenshots/session-overview.png" style="width: 90%;" alt="Agent Debugging"/>
<img src="docs/images/external/app_screenshots/session-drilldown-metadata.png" style="width: 90%;" alt="Agent Metadata"/>
</a>
<a href="https://app.agentops.ai?ref=gh">
<img src="docs/images/external/app_screenshots/chat-viewer.png" style="width: 90%;" alt="Chat Viewer"/>
</a>
<a href="https://app.agentops.ai?ref=gh">
<img src="docs/images/external/app_screenshots/session-drilldown-graphs.png" style="width: 90%;" alt="Event Graphs"/>
</a>
</details>

Expand All @@ -99,6 +113,9 @@ All your sessions can be viewed on the [AgentOps dashboard](https://app.agentops
<a href="https://app.agentops.ai?ref=gh">
<img src="docs/images/external/app_screenshots/overview.png" style="width: 90%;" alt="Summary Analytics"/>
</a>
<a href="https://app.agentops.ai?ref=gh">
<img src="docs/images/external/app_screenshots/overview-charts.png" style="width: 90%;" alt="Summary Analytics Charts"/>
</a>
</details>


Expand Down Expand Up @@ -353,6 +370,149 @@ async def main() -> None:
print(message.content)


await main()
```
</details>

### Mistral 〽️

Track agents built with the Anthropic Python SDK (>=0.32.0).

- [AgentOps integration example](./examples/mistral//mistral_example.ipynb)
- [Official Mistral documentation](https://docs.mistral.ai)

<details>
<summary>Installation</summary>

```bash
pip install mistralai
```

Sync

```python python
from mistralai import Mistral
import agentops

# Beginning of program's code (i.e. main.py, __init__.py)
agentops.init(<INSERT YOUR API KEY HERE>)

client = Mistral(
# This is the default and can be omitted
api_key=os.environ.get("MISTRAL_API_KEY"),
)

message = client.chat.complete(
messages=[
{
"role": "user",
"content": "Tell me a cool fact about AgentOps",
}
],
model="open-mistral-nemo",
)
print(message.choices[0].message.content)

agentops.end_session('Success')
```

Streaming

```python python
from mistralai import Mistral
import agentops

# Beginning of program's code (i.e. main.py, __init__.py)
agentops.init(<INSERT YOUR API KEY HERE>)

client = Mistral(
# This is the default and can be omitted
api_key=os.environ.get("MISTRAL_API_KEY"),
)

message = client.chat.stream(
messages=[
{
"role": "user",
"content": "Tell me something cool about streaming agents",
}
],
model="open-mistral-nemo",
)

response = ""
for event in message:
if event.data.choices[0].finish_reason == "stop":
print("\n")
print(response)
print("\n")
else:
response += event.text

agentops.end_session('Success')
```

Async

```python python
import asyncio
from mistralai import Mistral

client = Mistral(
# This is the default and can be omitted
api_key=os.environ.get("MISTRAL_API_KEY"),
)


async def main() -> None:
message = await client.chat.complete_async(
messages=[
{
"role": "user",
"content": "Tell me something interesting about async agents",
}
],
model="open-mistral-nemo",
)
print(message.choices[0].message.content)


await main()
```

Async Streaming

```python python
import asyncio
from mistralai import Mistral

client = Mistral(
# This is the default and can be omitted
api_key=os.environ.get("MISTRAL_API_KEY"),
)


async def main() -> None:
message = await client.chat.stream_async(
messages=[
{
"role": "user",
"content": "Tell me something interesting about async streaming agents",
}
],
model="open-mistral-nemo",
)

response = ""
async for event in message:
if event.data.choices[0].finish_reason == "stop":
print("\n")
print(response)
print("\n")
else:
response += event.text


await main()
```
</details>
Comment on lines 370 to 518
Copy link

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

ℹ️ Performance Improvement

Optimize HTTP Requests with Class-Level Session

The introduction of a class-level session object for HTTP requests in agentops/http_client.py is a significant improvement. This change reduces the overhead of creating a new session for each request, enhancing performance and reliability. Ensure that the session is properly closed when no longer needed to prevent resource leaks.

🔒 Security Suggestion

Secure Handling of Sensitive Information

In the agentops/init.py and agentops/client.py, ensure that sensitive information such as API keys are not logged. Consider using environment variables or secure vaults to manage sensitive data securely.

ℹ️ Logic Error

Clarify Default Session End State

In the agentops/session.py, setting the default session end state to 'Indeterminate' could lead to confusion if not properly documented or handled. Ensure that the logic for determining the session end state is robust and clearly documented to avoid misinterpretation.

Expand Down
12 changes: 6 additions & 6 deletions agentops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
except ModuleNotFoundError:
pass

if "autogen" in sys.modules:
Client().configure(instrument_llm_calls=False)
Client().add_default_tags(["autogen"])

if "crewai" in sys.modules:
crew_version = version.parse(get_version("crewai"))

Expand Down Expand Up @@ -69,10 +65,15 @@ def init(
(i.e. Crew determining when tasks are complete and ending the session)
Attributes:
"""

if "autogen" in sys.modules:
Client().configure(instrument_llm_calls=False)
Client()._initialize_autogen_logger()
Client().add_default_tags(["autogen"])

Client().unsuppress_logs()
t = threading.Thread(target=check_agentops_update)
t.start()

if Client().is_initialized:
return logger.warning(
"AgentOps has already been initialized. If you are trying to start a session, call agentops.start_session() instead."
Expand Down Expand Up @@ -101,7 +102,6 @@ def init(
"auto_start_session is set to False - inherited_session_id will not be used to automatically start a session"
)
return Client().initialize()

Client().configure(auto_start_session=False)
Client().initialize()
return Client().start_session(inherited_session_id=inherited_session_id)
Expand Down
8 changes: 3 additions & 5 deletions agentops/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,13 @@ def initialize(self) -> Union[Session, None]:
return

self.unsuppress_logs()

if self._config.api_key is None:
return logger.error(
"Could not initialize AgentOps client - API Key is missing."
+ "\n\t Find your API key at https://app.agentops.ai/settings/projects"
)

self._handle_unclean_exits()
self._initialize_partner_framework()

self._initialized = True

if self._config.instrument_llm_calls:
Expand All @@ -116,7 +113,7 @@ def initialize(self) -> Union[Session, None]:

return session

def _initialize_partner_framework(self) -> None:
def _initialize_autogen_logger(self) -> None:
try:
import autogen
from .partners.autogen_logger import AutogenLogger
Expand Down Expand Up @@ -305,7 +302,8 @@ def create_agent(
self._pre_init_queue["agents"].append(
{"name": name, "agent_id": agent_id}
)
session.create_agent(name=name, agent_id=agent_id)
else:
session.create_agent(name=name, agent_id=agent_id)

return agent_id

Expand Down
54 changes: 36 additions & 18 deletions agentops/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from datetime import datetime, timezone
import inspect
from typing import Union
import http.client
import requests
import json
from importlib.metadata import version, PackageNotFoundError

Expand All @@ -22,6 +22,24 @@ def get_ISO_time():
return datetime.now(timezone.utc).isoformat()


def format_duration(start_time, end_time):
start = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
end = datetime.fromisoformat(end_time.replace("Z", "+00:00"))
duration = end - start

hours, remainder = divmod(duration.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)

parts = []
if hours > 0:
parts.append(f"{int(hours)}h")
if minutes > 0:
parts.append(f"{int(minutes)}m")
parts.append(f"{seconds:.1f}s")

return " ".join(parts)


def is_jsonable(x):
try:
json.dumps(x)
Expand Down Expand Up @@ -127,25 +145,25 @@ def get_agentops_version():


def check_agentops_update():
# using http.client to avoid this call being caught by requests_mock on tests
conn = http.client.HTTPSConnection("pypi.org")
conn.request("GET", "/pypi/agentops/json")
response = conn.getresponse()
data = response.read().decode()
json_data = json.loads(data)
try:
response = requests.get("https://pypi.org/pypi/agentops/json")

if response.status == 200:
latest_version = json_data["info"]["version"]
if response.status_code == 200:
json_data = response.json()
latest_version = json_data["info"]["version"]

try:
current_version = version("agentops")
except PackageNotFoundError:
return None

if not latest_version == current_version:
logger.warning(
f" WARNING: agentops is out of date. Please update with the command: 'pip install --upgrade agentops'"
)
try:
current_version = version("agentops")
except PackageNotFoundError:
return None

if not latest_version == current_version:
logger.warning(
f" WARNING: agentops is out of date. Please update with the command: 'pip install --upgrade agentops'"
)
except Exception as e:
logger.debug(f"Failed to check for updates: {e}")
return None


# Function decorator that prints function name and its arguments to the console for debug purposes
Expand Down
4 changes: 1 addition & 3 deletions agentops/host_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,11 @@ def get_sys_packages():


def get_installed_packages():

try:
return {
# TODO: test
# TODO: add to opt out
"Installed Packages": {
dist.metadata["Name"]: dist.version
dist.metadata.get("Name"): dist.metadata.get("Version")
for dist in importlib.metadata.distributions()
}
}
Comment on lines 47 to 57
Copy link

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

ℹ️ Logic Error

Handle None Values in Metadata

The change from dist.metadata["Name"] to dist.metadata.get("Name") and similarly for Version is a good practice to avoid KeyError if the metadata is missing. However, this change introduces a potential issue where None values could be included in the dictionary if the metadata is not present. This could lead to unexpected behavior when processing the installed packages list.

 def get_installed_packages():
     try:
         return {
             "Installed Packages": {
-                dist.metadata.get("Name"): dist.metadata.get("Version")
+                name: version
+                for dist in importlib.metadata.distributions()
+                if (name := dist.metadata.get("Name")) is not None
+                and (version := dist.metadata.get("Version")) is not None
             }
         }
Commitable Code Suggestion:
Suggested change
def get_installed_packages():
try:
return {
# TODO: test
# TODO: add to opt out
"Installed Packages": {
dist.metadata["Name"]: dist.version
dist.metadata.get("Name"): dist.metadata.get("Version")
for dist in importlib.metadata.distributions()
}
}
def get_installed_packages():
try:
return {
"Installed Packages": {
name: version
for dist in importlib.metadata.distributions()
if (name := dist.metadata.get("Name")) is not None
and (version := dist.metadata.get("Version")) is not None
}
}

Expand Down
Loading
Loading