From 0f11a9d033dfb14753c6694adf71771a897b9078 Mon Sep 17 00:00:00 2001 From: Howard Gil Date: Wed, 3 Apr 2024 01:03:40 -0700 Subject: [PATCH 1/6] Setting session to none if server does not return 200 for /sessions --- agentops/client.py | 6 +++++- agentops/worker.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/agentops/client.py b/agentops/client.py index 8c2fa188..4001d4d1 100644 --- a/agentops/client.py +++ b/agentops/client.py @@ -212,7 +212,11 @@ def start_session(self, tags: Optional[List[str]] = None, config: Optional[Confi self._session = Session(uuid4(), tags or self._tags, host_env=get_host_env()) self._worker = Worker(config or self.config) - self._worker.start_session(self._session) + start_session_result = self._worker.start_session(self._session) + if not start_session_result: + self._session = None + return logging.warning("AgentOps: Cannot start session") + logging.info('View info on this session at https://app.agentops.ai/drilldown?session_id={}' .format(self._session.session_id)) diff --git a/agentops/worker.py b/agentops/worker.py index d409ee10..6b7320ef 100644 --- a/agentops/worker.py +++ b/agentops/worker.py @@ -49,10 +49,15 @@ def start_session(self, session: Session) -> None: "session": session.__dict__ } serialized_payload = json.dumps(filter_unjsonable(payload)).encode("utf-8") - HttpClient.post(f'{self.config.endpoint}/sessions', - serialized_payload, - self.config.api_key, - self.config.parent_key) + res = HttpClient.post(f'{self.config.endpoint}/sessions', + serialized_payload, + self.config.api_key, + self.config.parent_key) + + if res.code != 200: + return False + + return True def end_session(self, session: Session) -> None: self.stop_flag.set() From af29a63fb1076b55af282736090695f8271a94f5 Mon Sep 17 00:00:00 2001 From: Howard Gil Date: Fri, 3 May 2024 17:38:19 -0700 Subject: [PATCH 2/6] Fixed crash on end_timestamp does not exist --- agentops/client.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/agentops/client.py b/agentops/client.py index 3ed8f1cb..f4ee9306 100644 --- a/agentops/client.py +++ b/agentops/client.py @@ -77,7 +77,8 @@ def __init__(self, self._worker = None self._tags_for_future_session = None - self._env_data_opt_out = os.getenv('AGENTOPS_ENV_DATA_OPT_OUT') and os.getenv('AGENTOPS_ENV_DATA_OPT_OUT').lower() == 'true' + self._env_data_opt_out = os.getenv('AGENTOPS_ENV_DATA_OPT_OUT') and os.getenv( + 'AGENTOPS_ENV_DATA_OPT_OUT').lower() == 'true' try: self.config = Configuration(api_key=api_key, @@ -136,19 +137,24 @@ def record(self, event: Event | ErrorEvent): Args: event (Event): The event to record. """ - if 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: + if self._session is None or self._session.has_ended: + logger.warning("🖇 AgentOps: Cannot record event - no current session") + return + + # Need to update end_timestamp for ErrorEvent so creating this event_local pointer + event_local = event.trigger_event if isinstance(event, ErrorEvent) else event + if event_local: # ErrorEvent may not have a trigger_event set + if not event_local.end_timestamp or event_local.init_timestamp == event_local.end_timestamp: + event_local.end_timestamp = get_ISO_time() + if isinstance(event, ErrorEvent): - if event.trigger_event: - event.trigger_event_id = event.trigger_event.id - event.trigger_event_type = event.trigger_event.event_type - self._worker.add_event(event.trigger_event.__dict__) - event.trigger_event = None # removes trigger_event from serialization - self._worker.add_event(event.__dict__) - else: - logger.warning( - "🖇 AgentOps: Cannot record event - no current session") + # Extract trigger_event info from ErrorEvent and log trigger_event + event.trigger_event_id = event_local.id + event.trigger_event_type = event_local.event_type + self._worker.add_event(event_local.__dict__) + event.trigger_event = None # removes trigger_event from serialization + + self._worker.add_event(event.__dict__) def _record_event_sync(self, func, event_name, *args, **kwargs): init_time = get_ISO_time() @@ -240,7 +246,8 @@ def start_session(self, tags: Optional[List[str]] = None, config: Optional[Confi if not config and not self.config: return logger.warning("🖇 AgentOps: Cannot start session - missing configuration") - self._session = Session(inherited_session_id or uuid4(), tags or self._tags_for_future_session, host_env=get_host_env(self._env_data_opt_out)) + self._session = Session(inherited_session_id or uuid4(), + tags or self._tags_for_future_session, host_env=get_host_env(self._env_data_opt_out)) self._worker = Worker(config or self.config) start_session_result = self._worker.start_session(self._session) if not start_session_result: From 8fa8cacb53a386932eda720a16da3631673bf3b2 Mon Sep 17 00:00:00 2001 From: Shawn Qiu Date: Fri, 3 May 2024 19:54:00 -0700 Subject: [PATCH 3/6] notebook update --- examples/recording-events.ipynb | 143 +++++++++++++++++--------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/examples/recording-events.ipynb b/examples/recording-events.ipynb index 0f224f8a..9c766b58 100644 --- a/examples/recording-events.ipynb +++ b/examples/recording-events.ipynb @@ -2,44 +2,50 @@ "cells": [ { "cell_type": "markdown", - "source": [ - "# Recording Events\n", - "AgentOps has a number of different [Event Types](https://docs.agentops.ai/v1/details/events)" - ], + "id": "dc8cfd2cfa8a594b", "metadata": { "collapsed": false }, - "id": "dc8cfd2cfa8a594b" + "source": [ + "# Recording Events\n", + "AgentOps has a number of different [Event Types](https://docs.agentops.ai/v1/details/events)" + ] }, { "cell_type": "code", + "execution_count": null, + "id": "168ecd05cc123de0", + "metadata": { + "collapsed": false, + "is_executing": true + }, "outputs": [], "source": [ + "import agentops\n", "# Create new session\n", - "agentops.start_session()\n", + "agentops.init()\n", "\n", "# Optionally, we can add tags to the session\n", - "# agentops.start_session(['Hello Tracker'])" - ], - "metadata": { - "collapsed": false, - "is_executing": true - }, - "id": "168ecd05cc123de0", - "execution_count": null + "# agentops.init(tags=['Hello Tracker'])" + ] }, { "cell_type": "markdown", - "source": [ - "The easiest way to record actions is through the use of AgentOp's decorators" - ], + "id": "c6d06ee8c66dad17", "metadata": { "collapsed": false }, - "id": "c6d06ee8c66dad17" + "source": [ + "The easiest way to record actions is through the use of AgentOp's decorators" + ] }, { "cell_type": "code", + "execution_count": null, + "id": "b460318317adc624", + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "from agentops import record_function\n", @@ -49,25 +55,25 @@ " return x + y\n", "\n", "add(2,4)" - ], - "metadata": { - "collapsed": false - }, - "id": "b460318317adc624", - "execution_count": 0 + ] }, { "cell_type": "markdown", - "source": [ - "We can also manually craft an event exactly the way we want" - ], + "id": "9068a4cdd328f652", "metadata": { "collapsed": false }, - "id": "9068a4cdd328f652" + "source": [ + "We can also manually craft an event exactly the way we want" + ] }, { "cell_type": "code", + "execution_count": null, + "id": "b62ad88921ff26f2", + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "from agentops import ActionEvent\n", @@ -78,38 +84,38 @@ "\n", "if \"hello\" in str(response.choices[0].message.content).lower():\n", " agentops.record(ActionEvent(action_type=\"Agent says hello\", params=str(message), returns=str(response.choices[0].message.content) ))" - ], - "metadata": { - "collapsed": false - }, - "id": "b62ad88921ff26f2", - "execution_count": 0 + ] }, { "cell_type": "code", - "outputs": [], - "source": [ - "agentops.end_session('Success')" - ], + "execution_count": null, + "id": "e10a89e06fe6b2be", "metadata": { "collapsed": false }, - "id": "e10a89e06fe6b2be", - "execution_count": null + "outputs": [], + "source": [ + "agentops.end_session('Success')" + ] }, { "cell_type": "markdown", - "source": [ - "## Tool Event\n", - "Agents use tools. These tools are useful to track with information such as name, end status, runtime, etc. To record tool usage, you can create and record a `ToolEvent` similar to above." - ], + "id": "f7c947d815f581e7", "metadata": { "collapsed": false }, - "id": "f7c947d815f581e7" + "source": [ + "## Tool Event\n", + "Agents use tools. These tools are useful to track with information such as name, end status, runtime, etc. To record tool usage, you can create and record a `ToolEvent` similar to above." + ] }, { "cell_type": "code", + "execution_count": null, + "id": "5d387a071a1c70cf", + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "from agentops import ToolEvent, record\n", @@ -118,41 +124,42 @@ " result = integration.scrape_website(data) # perform tool logic\n", " tool_event.returns = result\n", " record(tool_event)" - ], - "metadata": { - "collapsed": false - }, - "id": "5d387a071a1c70cf" + ] }, { "cell_type": "markdown", - "source": [ - "## Error Events\n", - "Error events can be used alone or in reference to another event. Lets add a catch block to the code above" - ], + "id": "968d1503dd0aae9a", "metadata": { "collapsed": false }, - "id": "968d1503dd0aae9a" + "source": [ + "## Error Events\n", + "Error events can be used alone or in reference to another event. Lets add a catch block to the code above" + ] }, { "cell_type": "code", + "execution_count": null, + "id": "eb23c1325298e22f", + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "from agentops import ToolEvent, record, ErrorEvent\n", + "\n", "def scrape_website(url: str):\n", " tool_event = ToolEvent(name='scrape_website', params={'url':url}) # the start timestamp is set when the obj is created\n", + "\n", " try:\n", - " result = integration.scrape_website(data) # perform tool logic\n", - " tool_event.returns = result\n", - " except Error as e:\n", - " record(ErrorEvent(message=e, trigger_event=tool_event))\n", - " record(tool_event)" - ], - "metadata": { - "collapsed": false - }, - "id": "eb23c1325298e22f" + " 1 / 0 # Ooops! Something went wrong\n", + " except Exception as e:\n", + " record(ErrorEvent(exception=e, trigger_event=tool_event))\n", + "\n", + "scrape_website('https://app.agentops.ai') \n", + "\n", + "agentops.end_session('Success')" + ] } ], "metadata": { @@ -164,14 +171,14 @@ "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" + "pygments_lexer": "ipython3", + "version": "3.12.3" } }, "nbformat": 4, From b35955e52608f9215c1ce5286d926762b93e23c7 Mon Sep 17 00:00:00 2001 From: Shawn Qiu Date: Fri, 3 May 2024 19:55:30 -0700 Subject: [PATCH 4/6] bump version number --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a3f14a93..cd97b497 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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="areibman@gmail.com" }, { name="Shawn Qiu", email="siyangqiu@gmail.com" }, From 6249ee46dbcdd63f5d2f204e2da6577d3e320001 Mon Sep 17 00:00:00 2001 From: Howard Gil Date: Mon, 6 May 2024 14:26:52 -0700 Subject: [PATCH 5/6] end_timestamp optional --- agentops/client.py | 2 +- agentops/event.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/agentops/client.py b/agentops/client.py index f4ee9306..d6512441 100644 --- a/agentops/client.py +++ b/agentops/client.py @@ -144,7 +144,7 @@ def record(self, event: Event | ErrorEvent): # Need to update end_timestamp for ErrorEvent so creating this event_local pointer event_local = event.trigger_event if isinstance(event, ErrorEvent) else event if event_local: # ErrorEvent may not have a trigger_event set - if not event_local.end_timestamp or event_local.init_timestamp == event_local.end_timestamp: + if event_local.init_timestamp == event_local.end_timestamp: event_local.end_timestamp = get_ISO_time() if isinstance(event, ErrorEvent): diff --git a/agentops/event.py b/agentops/event.py index 1a047f18..2d34c08a 100644 --- a/agentops/event.py +++ b/agentops/event.py @@ -40,11 +40,10 @@ class Event: event_type: str # EventType.ENUM.value params: Optional[dict] = None returns: Optional[str] = None - init_timestamp: Optional[str] = field(default_factory=get_ISO_time) - end_timestamp: str = field(default_factory=get_ISO_time) + init_timestamp: str = field(default_factory=get_ISO_time) + end_timestamp: Optional[str] = None agent_id: Optional[UUID] = field(default_factory=check_call_stack_for_agent_id) id: UUID = field(default_factory=uuid4) - # TODO: has_been_recorded: bool = False @dataclass From 661b8aa1ea6c9e4a86d1debe3eb0d1a88897cafe Mon Sep 17 00:00:00 2001 From: Howard Gil Date: Mon, 6 May 2024 15:03:18 -0700 Subject: [PATCH 6/6] Making code more explicit --- agentops/client.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/agentops/client.py b/agentops/client.py index d6512441..6df00bf7 100644 --- a/agentops/client.py +++ b/agentops/client.py @@ -141,18 +141,18 @@ def record(self, event: Event | ErrorEvent): logger.warning("🖇 AgentOps: Cannot record event - no current session") return - # Need to update end_timestamp for ErrorEvent so creating this event_local pointer - event_local = event.trigger_event if isinstance(event, ErrorEvent) else event - if event_local: # ErrorEvent may not have a trigger_event set - if event_local.init_timestamp == event_local.end_timestamp: - event_local.end_timestamp = get_ISO_time() - - if isinstance(event, ErrorEvent): - # Extract trigger_event info from ErrorEvent and log trigger_event - event.trigger_event_id = event_local.id - event.trigger_event_type = event_local.event_type - self._worker.add_event(event_local.__dict__) - event.trigger_event = None # removes trigger_event from serialization + if isinstance(event, Event): + if not event.end_timestamp or event.init_timestamp == event.end_timestamp: + event.end_timestamp = get_ISO_time() + elif isinstance(event, ErrorEvent): + if event.trigger_event: + if not event.trigger_event.end_timestamp or event.trigger_event.init_timestamp == event.trigger_event.end_timestamp: + event.trigger_event.end_timestamp = get_ISO_time() + + event.trigger_event_id = event.trigger_event.id + event.trigger_event_type = event.trigger_event.event_type + self._worker.add_event(event.trigger_event.__dict__) + event.trigger_event = None # removes trigger_event from serialization self._worker.add_event(event.__dict__)