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 #31

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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>
Comment on lines 24 to 48

Choose a reason for hiding this comment

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

ℹ️ Performance Improvement

Optimize Badge Images for Performance

The update to use badge images for social links in the README.md file enhances the visual appeal and provides a more interactive experience for users. However, ensure that the badge images are optimized for performance to prevent any unnecessary loading delays, especially on slower connections.


<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>
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

Choose a reason for hiding this comment

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

ℹ️ Logic Error

Ensure Default Values for Metadata Retrieval

The change from dist.metadata["Name"] to dist.metadata.get("Name") and similarly for Version introduces a potential issue where None could be returned if the metadata keys do not exist. This could lead to unexpected behavior when the returned dictionary is used. Consider providing a default value to ensure the dictionary always contains valid strings.

-                dist.metadata.get("Name"): dist.metadata.get("Version")
+                dist.metadata.get("Name", "Unknown"): dist.metadata.get("Version", "0.0.0")
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()
}
}
dist.metadata.get("Name", "Unknown"): dist.metadata.get("Version", "0.0.0")

Expand Down
Loading
Loading