From 8ccf38e7a29b893a1b204e46d55754a511f7aa5e Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Thu, 5 Jun 2025 16:51:00 -0700 Subject: [PATCH 1/6] init() sets auto_start_session to false if in notebook and changed docs --- agentops/__init__.py | 7 +++++++ docs/v2/usage/sdk-reference.mdx | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/agentops/__init__.py b/agentops/__init__.py index 3b252759a..48690b1e2 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -105,6 +105,13 @@ def init( merged_tags = tags elif default_tags: merged_tags = default_tags + + # Check if in a Jupyter Notebook (manual start/end_trace()) + try: + __IPYTHON__ # type: ignore + auto_start_session = False + except NameError: + auto_start_session = True return _client.init( api_key=api_key, diff --git a/docs/v2/usage/sdk-reference.mdx b/docs/v2/usage/sdk-reference.mdx index de29cd30c..0326268c9 100644 --- a/docs/v2/usage/sdk-reference.mdx +++ b/docs/v2/usage/sdk-reference.mdx @@ -25,7 +25,7 @@ Initializes the AgentOps SDK and automatically starts tracking your application. - `default_tags` (List[str], optional): Default tags for the sessions that can be used for grouping or sorting later (e.g. ["GPT-4"]). - `tags` (List[str], optional): [Deprecated] Use `default_tags` instead. - `instrument_llm_calls` (bool, optional): Whether to instrument LLM calls automatically. Defaults to True. -- `auto_start_session` (bool, optional): Whether to start a session automatically when the client is created. Defaults to True. +- `auto_start_session` (bool, optional): Whether to start a session automatically when the client is created. Set to False if running in a Jupyter Notebook. Defaults to True. - `auto_init` (bool, optional): Whether to automatically initialize the client on import. Defaults to True. - `skip_auto_end_session` (bool, optional): Don't automatically end session based on your framework's decision-making. Defaults to False. - `env_data_opt_out` (bool, optional): Whether to opt out of collecting environment data. Defaults to False. From db9bc6b8f09a9113a3b407f9b6f46f2b32ff210c Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Fri, 6 Jun 2025 13:42:29 -0700 Subject: [PATCH 2/6] deal with non-notebook manual trace --- agentops/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentops/__init__.py b/agentops/__init__.py index 48690b1e2..488e45f80 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -111,7 +111,7 @@ def init( __IPYTHON__ # type: ignore auto_start_session = False except NameError: - auto_start_session = True + pass return _client.init( api_key=api_key, From f25565e0d6b94b90923609f223396c0601ed7a26 Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Fri, 6 Jun 2025 14:00:30 -0700 Subject: [PATCH 3/6] ruff, if you will --- agentops/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agentops/__init__.py b/agentops/__init__.py index 488e45f80..e54ab501c 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -105,10 +105,10 @@ def init( merged_tags = tags elif default_tags: merged_tags = default_tags - + # Check if in a Jupyter Notebook (manual start/end_trace()) try: - __IPYTHON__ # type: ignore + __IPYTHON__ # type: ignore auto_start_session = False except NameError: pass From 886eb96b5c2e5f62d50010881769cd181a35915d Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Fri, 6 Jun 2025 16:30:04 -0700 Subject: [PATCH 4/6] ruff redux --- agentops/__init__.py | 2 +- agentops/client/api/base.py | 3 +- agentops/client/client.py | 6 +- agentops/instrumentation/common/attributes.py | 3 +- agentops/instrumentation/google_adk/patch.py | 18 ++-- .../openai_agents/attributes/completion.py | 6 +- .../adk_human_approval_example.ipynb | 89 ++++++++++++------- .../customer_service_agent.ipynb | 2 +- tests/unit/sdk/instrumentation_tester.py | 3 +- 9 files changed, 75 insertions(+), 57 deletions(-) diff --git a/agentops/__init__.py b/agentops/__init__.py index 7de3a7737..9e48a2347 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -108,7 +108,7 @@ def init( # Check if in a Jupyter Notebook (manual start/end_trace()) try: - __IPYTHON__ # type: ignore + get_ipython().__class__.__name__ == "ZMQInteractiveShell" # type: ignore auto_start_session = False except NameError: pass diff --git a/agentops/client/api/base.py b/agentops/client/api/base.py index 44140956e..4891e743f 100644 --- a/agentops/client/api/base.py +++ b/agentops/client/api/base.py @@ -15,8 +15,7 @@ class TokenFetcher(Protocol): """Protocol for token fetching functions""" - def __call__(self, api_key: str) -> str: - ... + def __call__(self, api_key: str) -> str: ... class BaseApiClient: diff --git a/agentops/client/client.py b/agentops/client/client.py index 1979e6c6e..2b2706172 100644 --- a/agentops/client/client.py +++ b/agentops/client/client.py @@ -40,9 +40,9 @@ class Client: config: Config _initialized: bool _init_trace_context: Optional[TraceContext] = None # Stores the context of the auto-started trace - _legacy_session_for_init_trace: Optional[ - Session - ] = None # Stores the legacy Session wrapper for the auto-started trace + _legacy_session_for_init_trace: Optional[Session] = ( + None # Stores the legacy Session wrapper for the auto-started trace + ) __instance = None # Class variable for singleton pattern diff --git a/agentops/instrumentation/common/attributes.py b/agentops/instrumentation/common/attributes.py index f267d615e..da33fbd6c 100644 --- a/agentops/instrumentation/common/attributes.py +++ b/agentops/instrumentation/common/attributes.py @@ -98,8 +98,7 @@ class IndexedAttribute(Protocol): formatting of attribute keys based on the indices. """ - def format(self, *, i: int, j: Optional[int] = None) -> str: - ... + def format(self, *, i: int, j: Optional[int] = None) -> str: ... IndexedAttributeMap = Dict[IndexedAttribute, str] # target_attribute_key: source_attribute diff --git a/agentops/instrumentation/google_adk/patch.py b/agentops/instrumentation/google_adk/patch.py index 88d9aa2df..bb62c42f7 100644 --- a/agentops/instrumentation/google_adk/patch.py +++ b/agentops/instrumentation/google_adk/patch.py @@ -304,16 +304,16 @@ def _extract_llm_attributes(llm_request_dict: dict, llm_response: Any) -> dict: elif "function_call" in part: # This is a function call in the response func_call = part["function_call"] - attributes[ - MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=0, j=tool_call_index) - ] = func_call.get("name", "") - attributes[ - MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=0, j=tool_call_index) - ] = json.dumps(func_call.get("args", {})) + attributes[MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=0, j=tool_call_index)] = ( + func_call.get("name", "") + ) + attributes[MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=0, j=tool_call_index)] = ( + json.dumps(func_call.get("args", {})) + ) if "id" in func_call: - attributes[ - MessageAttributes.COMPLETION_TOOL_CALL_ID.format(i=0, j=tool_call_index) - ] = func_call["id"] + attributes[MessageAttributes.COMPLETION_TOOL_CALL_ID.format(i=0, j=tool_call_index)] = ( + func_call["id"] + ) tool_call_index += 1 if text_parts: diff --git a/agentops/instrumentation/openai_agents/attributes/completion.py b/agentops/instrumentation/openai_agents/attributes/completion.py index d035d6cff..10bd6bfdc 100644 --- a/agentops/instrumentation/openai_agents/attributes/completion.py +++ b/agentops/instrumentation/openai_agents/attributes/completion.py @@ -115,9 +115,9 @@ def get_raw_response_attributes(response: Dict[str, Any]) -> Dict[str, Any]: result[MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=j, j=k)] = function.get( "name", "" ) - result[ - MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=j, j=k) - ] = function.get("arguments", "") + result[MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=j, j=k)] = ( + function.get("arguments", "") + ) return result diff --git a/examples/google_adk_example/adk_human_approval_example.ipynb b/examples/google_adk_example/adk_human_approval_example.ipynb index a2d0cc23b..d288175ee 100644 --- a/examples/google_adk_example/adk_human_approval_example.ipynb +++ b/examples/google_adk_example/adk_human_approval_example.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "id": "7fb27b941602401d91542211134fc71a", "metadata": {}, "source": [ "# Google ADK Example: Human Approval Workflow with AgentOps" @@ -9,6 +10,7 @@ }, { "cell_type": "markdown", + "id": "acae54e37e7d407bbb7b55eff062a284", "metadata": {}, "source": [ "This notebook demonstrates a complete human approval workflow using the Google ADK (Agent Development Kit), integrated with AgentOps for observability.\n", @@ -23,6 +25,7 @@ }, { "cell_type": "markdown", + "id": "9a63283cbaf04dbcab1f6479b197f3a8", "metadata": {}, "source": [ "## 1. Setup and Dependencies" @@ -30,6 +33,7 @@ }, { "cell_type": "markdown", + "id": "8dd0d8092fe74a7c96281538738b07e2", "metadata": {}, "source": [ "First, let's install the necessary libraries if they are not already present and import them." @@ -38,6 +42,7 @@ { "cell_type": "code", "execution_count": null, + "id": "72eea5119410473aa328ad9291626812", "metadata": {}, "outputs": [], "source": [ @@ -47,6 +52,7 @@ { "cell_type": "code", "execution_count": 1, + "id": "8edb47106e1a46a883d545849b8ab81b", "metadata": {}, "outputs": [], "source": [ @@ -66,6 +72,7 @@ }, { "cell_type": "markdown", + "id": "10185d26023b46108eb7d9f57d49d2b3", "metadata": {}, "source": [ "## 2. Configuration and Initialization" @@ -73,6 +80,7 @@ }, { "cell_type": "markdown", + "id": "8763a12b2bbd4a93a75aff182afb95dc", "metadata": {}, "source": [ "Load environment variables (especially `AGENTOPS_API_KEY` and your Google API key for Gemini) and initialize AgentOps." @@ -81,6 +89,7 @@ { "cell_type": "code", "execution_count": null, + "id": "7623eae2785240b9bd12b16a66d81610", "metadata": {}, "outputs": [], "source": [ @@ -94,6 +103,7 @@ }, { "cell_type": "markdown", + "id": "7cdc8c89c7104fffa095e18ddfef8986", "metadata": {}, "source": [ "Define some constants for our application." @@ -102,6 +112,7 @@ { "cell_type": "code", "execution_count": null, + "id": "b118ea5561624da68c537baed56e602f", "metadata": {}, "outputs": [], "source": [ @@ -109,11 +120,12 @@ "USER_ID = \"test_user_notebook_123\"\n", "SESSION_ID = \"approval_session_notebook_456\"\n", "MODEL_NAME = \"gemini-1.5-flash\"\n", - "agentops.start_trace(trace_name=APP_NAME, tags=[\"google_adk\",\"notebook\"])" + "agentops.start_trace(trace_name=APP_NAME, tags=[\"google_adk\", \"notebook\"])" ] }, { "cell_type": "markdown", + "id": "938c804e27f84196a10c8828c723f798", "metadata": {}, "source": [ "## 3. Define Schemas" @@ -121,6 +133,7 @@ }, { "cell_type": "markdown", + "id": "504fb2a444614c0babb325280ed9130a", "metadata": {}, "source": [ "Pydantic models are used to define the structure of data for approval requests and decisions. This helps with validation and clarity." @@ -129,12 +142,15 @@ { "cell_type": "code", "execution_count": 4, + "id": "59bbdb311c014d738909a11f9e486628", "metadata": {}, "outputs": [], "source": [ "class ApprovalRequest(BaseModel):\n", " amount: float = Field(description=\"The amount requiring approval\")\n", " reason: str = Field(description=\"The reason for the request\")\n", + "\n", + "\n", "class ApprovalDecision(BaseModel):\n", " decision: str = Field(description=\"The approval decision: 'approved' or 'rejected'\")\n", " comments: str = Field(description=\"Additional comments from the approver\")" @@ -142,6 +158,7 @@ }, { "cell_type": "markdown", + "id": "b43b363d81ae4b689946ece5c682cd59", "metadata": {}, "source": [ "## 4. External Approval Tool (with Human Interaction)" @@ -149,6 +166,7 @@ }, { "cell_type": "markdown", + "id": "8a65eabff63a45729fe45fb5ade58bdc", "metadata": {}, "source": [ "This tool now directly prompts the user for an approval decision. In a real-world scenario, this might involve sending a notification to an approver and waiting for their response through a UI or API." @@ -157,11 +175,12 @@ { "cell_type": "code", "execution_count": 5, + "id": "c3933fab20d04ec698c2621248eb3be0", "metadata": {}, "outputs": [], "source": [ "async def external_approval_tool(amount: float, reason: str) -> str:\n", - " \"\"\" \n", + " \"\"\"\n", " Prompts for human approval and returns the decision as a JSON string.\n", " \"\"\"\n", " print(f\"🔔 HUMAN APPROVAL REQUIRED:\")\n", @@ -175,12 +194,8 @@ " comments = input(\" Enter comments (optional): \").strip()\n", " print(f\" Decision: {decision.upper()}\")\n", " print(f\" Comments: {comments if comments else 'N/A'}\")\n", - " return json.dumps({\n", - " \"decision\": decision,\n", - " \"comments\": comments,\n", - " \"amount\": amount,\n", - " \"reason\": reason\n", - " })\n", + " return json.dumps({\"decision\": decision, \"comments\": comments, \"amount\": amount, \"reason\": reason})\n", + "\n", "\n", "# Create the approval tool instance\n", "approval_tool = FunctionTool(func=external_approval_tool)" @@ -188,6 +203,7 @@ }, { "cell_type": "markdown", + "id": "4dd4641cc4064e0191573fe9c69df29b", "metadata": {}, "source": [ "## 5. Define Agents" @@ -195,6 +211,7 @@ }, { "cell_type": "markdown", + "id": "8309879909854d7188b41380fd92a7c3", "metadata": {}, "source": [ "We define three agents for our workflow:\n", @@ -206,6 +223,7 @@ { "cell_type": "code", "execution_count": 6, + "id": "3ed186c9a28b402fb0bc4494df01f08d", "metadata": {}, "outputs": [], "source": [ @@ -222,13 +240,13 @@ " 4. Respond with a summary of what will be submitted for approval\n", " If the user input is missing amount or reason, ask for clarification.\n", " \"\"\",\n", - " output_key=\"request_prepared\"\n", + " output_key=\"request_prepared\",\n", ")\n", "\n", "# Agent 2: Request human approval using the tool\n", "request_approval = LlmAgent(\n", " model=MODEL_NAME,\n", - " name=\"RequestHumanApprovalAgent\", \n", + " name=\"RequestHumanApprovalAgent\",\n", " description=\"Calls the external approval system with prepared request details\",\n", " instruction=\"\"\"You are a human approval request agent.\n", " Your task:\n", @@ -239,7 +257,7 @@ " Always use the exact values from the session state for the tool call.\n", " \"\"\",\n", " tools=[approval_tool],\n", - " output_key=\"approval_requested\"\n", + " output_key=\"approval_requested\",\n", ")\n", "\n", "# Agent 3: Process the approval decision\n", @@ -257,12 +275,13 @@ "\n", " Be professional and helpful in your response.\n", " \"\"\",\n", - " output_key=\"final_decision\"\n", + " output_key=\"final_decision\",\n", ")" ] }, { "cell_type": "markdown", + "id": "cb1e1581032b452c9409d6c6813c49d1", "metadata": {}, "source": [ "## 6. Create Sequential Workflow" @@ -270,6 +289,7 @@ }, { "cell_type": "markdown", + "id": "379cbbc1e968416e875cc15c1202d7eb", "metadata": {}, "source": [ "Combine the agents into a sequential workflow. The `SequentialAgent` ensures that the sub-agents are executed in the specified order." @@ -278,18 +298,20 @@ { "cell_type": "code", "execution_count": 7, + "id": "277c27b1587741f2af2001be3712ef0d", "metadata": {}, "outputs": [], "source": [ "approval_workflow = SequentialAgent(\n", " name=\"HumanApprovalWorkflowNotebook\",\n", " description=\"Complete workflow for processing approval requests with human oversight\",\n", - " sub_agents=[prepare_request, request_approval, process_decision]\n", + " sub_agents=[prepare_request, request_approval, process_decision],\n", ")" ] }, { "cell_type": "markdown", + "id": "db7b79bc585a40fcaf58bf750017e135", "metadata": {}, "source": [ "## 7. Session Management and Runner" @@ -297,6 +319,7 @@ }, { "cell_type": "markdown", + "id": "916684f9a58a4a2aa5f864670399430d", "metadata": {}, "source": [ "Set up an in-memory session service and the workflow runner." @@ -305,20 +328,18 @@ { "cell_type": "code", "execution_count": 8, + "id": "1671c31a24314836a5b85d7ef7fbf015", "metadata": {}, "outputs": [], "source": [ "session_service = InMemorySessionService()\n", "# Create runner\n", - "workflow_runner = Runner(\n", - " agent=approval_workflow,\n", - " app_name=APP_NAME,\n", - " session_service=session_service\n", - ")" + "workflow_runner = Runner(agent=approval_workflow, app_name=APP_NAME, session_service=session_service)" ] }, { "cell_type": "markdown", + "id": "33b0902fd34d4ace834912fa1002cf8e", "metadata": {}, "source": [ "## 8. Helper Function to Run Workflow" @@ -326,6 +347,7 @@ }, { "cell_type": "markdown", + "id": "f6fa52606d8c4a75a9b52967216f8f3f", "metadata": {}, "source": [ "This function encapsulates the logic to run the workflow for a given user request and session ID." @@ -334,20 +356,18 @@ { "cell_type": "code", "execution_count": 9, + "id": "f5a1fa73e5044315a093ec459c9be902", "metadata": {}, "outputs": [], "source": [ "async def run_approval_workflow_notebook(user_request: str, session_id: str):\n", " \"\"\"Run the complete approval workflow with a user request in the notebook environment\"\"\"\n", - " print(f\"{'='*60}\")\n", + " print(f\"{'=' * 60}\")\n", " print(f\" Starting Approval Workflow for Session: {session_id}\")\n", - " print(f\"{'='*60}\")\n", + " print(f\"{'=' * 60}\")\n", " print(f\"User Request: {user_request}\")\n", " # Create user message\n", - " user_content = types.Content(\n", - " role='user', \n", - " parts=[types.Part(text=user_request)]\n", - " )\n", + " user_content = types.Content(role=\"user\", parts=[types.Part(text=user_request)])\n", " step_count = 0\n", " final_response = \"No response received\"\n", " # Run the workflow\n", @@ -366,12 +386,12 @@ " final_response = response_text\n", " session = await session_service.get_session(\n", " app_name=APP_NAME,\n", - " user_id=USER_ID, \n", + " user_id=USER_ID,\n", " session_id=session_id,\n", " )\n", - " print(f\"{'='*60}\")\n", + " print(f\"{'=' * 60}\")\n", " print(f\"📊 Workflow Complete - Session State ({session_id}):\")\n", - " print(f\"{'='*60}\")\n", + " print(f\"{'=' * 60}\")\n", " for key, value in session.state.items():\n", " print(f\" {key}: {value}\")\n", " print(f\"🎯 Final Response: {final_response}\")\n", @@ -380,6 +400,7 @@ }, { "cell_type": "markdown", + "id": "cdf66aed5cc84ca1b48e60bad68798a8", "metadata": {}, "source": [ "## 9. Main Execution Logic" @@ -387,6 +408,7 @@ }, { "cell_type": "markdown", + "id": "28d3efd5258a48a79c179ea5c6759f01", "metadata": {}, "source": [ "This cell contains the main logic to run the workflow with a few test cases. Each test case will run in its own session." @@ -395,6 +417,7 @@ { "cell_type": "code", "execution_count": null, + "id": "3f9bc0b9dd2c44919cc8dcca39b469f8", "metadata": {}, "outputs": [], "source": [ @@ -402,18 +425,16 @@ " test_requests = [\n", " \"I need approval for $750 for team lunch and celebrations\",\n", " \"Please approve $3,000 for a conference ticket and travel expenses\",\n", - " \"I need $12,000 approved for critical software licenses renewal\"\n", + " \"I need $12,000 approved for critical software licenses renewal\",\n", " ]\n", " for i, request in enumerate(test_requests, 1):\n", - " current_session_id = f\"approval_session_notebook_{456 + i -1}\"\n", + " current_session_id = f\"approval_session_notebook_{456 + i - 1}\"\n", " # Create the session before running the workflow\n", - " await session_service.create_session(\n", - " app_name=APP_NAME,\n", - " user_id=USER_ID,\n", - " session_id=current_session_id\n", - " )\n", + " await session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=current_session_id)\n", " print(f\"Created session: {current_session_id}\")\n", " await run_approval_workflow_notebook(request, current_session_id)\n", + "\n", + "\n", "try:\n", " asyncio.run(main_notebook())\n", " agentops.end_trace(end_state=\"Success\")\n", diff --git a/examples/openai_agents_sdk/customer_service_agent.ipynb b/examples/openai_agents_sdk/customer_service_agent.ipynb index ed313b71c..563e7f3f2 100644 --- a/examples/openai_agents_sdk/customer_service_agent.ipynb +++ b/examples/openai_agents_sdk/customer_service_agent.ipynb @@ -44,7 +44,7 @@ "# API key is automatically read from the environment variable\n", "agentops.init(tags=[\"customer-service-agent\", \"agentops-example\"])\n", "\n", - "from agents import ( # noqa: E402\n", + "from agents import ( # noqa: E402\n", " Agent,\n", " HandoffOutputItem,\n", " ItemHelpers,\n", diff --git a/tests/unit/sdk/instrumentation_tester.py b/tests/unit/sdk/instrumentation_tester.py index 606a91bfb..4175270d6 100644 --- a/tests/unit/sdk/instrumentation_tester.py +++ b/tests/unit/sdk/instrumentation_tester.py @@ -45,8 +45,7 @@ def reset_trace_globals(): class HasAttributesViaProperty(Protocol): @property - def attributes(self) -> Attributes: - ... + def attributes(self) -> Attributes: ... class HasAttributesViaAttr(Protocol): From 8d936d4d39c648f1509ec6751bee828f08266e11 Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Fri, 6 Jun 2025 16:46:53 -0700 Subject: [PATCH 5/6] ruff redux 2 --- agentops/client/api/base.py | 3 ++- agentops/client/client.py | 6 +++--- agentops/instrumentation/__init__.py | 1 - agentops/instrumentation/common/attributes.py | 3 ++- agentops/instrumentation/google_adk/patch.py | 18 +++++++++--------- .../openai_agents/attributes/completion.py | 6 +++--- tests/unit/sdk/instrumentation_tester.py | 3 ++- 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/agentops/client/api/base.py b/agentops/client/api/base.py index 4891e743f..44140956e 100644 --- a/agentops/client/api/base.py +++ b/agentops/client/api/base.py @@ -15,7 +15,8 @@ class TokenFetcher(Protocol): """Protocol for token fetching functions""" - def __call__(self, api_key: str) -> str: ... + def __call__(self, api_key: str) -> str: + ... class BaseApiClient: diff --git a/agentops/client/client.py b/agentops/client/client.py index 2b2706172..1979e6c6e 100644 --- a/agentops/client/client.py +++ b/agentops/client/client.py @@ -40,9 +40,9 @@ class Client: config: Config _initialized: bool _init_trace_context: Optional[TraceContext] = None # Stores the context of the auto-started trace - _legacy_session_for_init_trace: Optional[Session] = ( - None # Stores the legacy Session wrapper for the auto-started trace - ) + _legacy_session_for_init_trace: Optional[ + Session + ] = None # Stores the legacy Session wrapper for the auto-started trace __instance = None # Class variable for singleton pattern diff --git a/agentops/instrumentation/__init__.py b/agentops/instrumentation/__init__.py index b48475af9..c1416956d 100644 --- a/agentops/instrumentation/__init__.py +++ b/agentops/instrumentation/__init__.py @@ -33,7 +33,6 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore from agentops.logging import logger -from agentops.sdk.core import tracer # Module-level state variables diff --git a/agentops/instrumentation/common/attributes.py b/agentops/instrumentation/common/attributes.py index da33fbd6c..f267d615e 100644 --- a/agentops/instrumentation/common/attributes.py +++ b/agentops/instrumentation/common/attributes.py @@ -98,7 +98,8 @@ class IndexedAttribute(Protocol): formatting of attribute keys based on the indices. """ - def format(self, *, i: int, j: Optional[int] = None) -> str: ... + def format(self, *, i: int, j: Optional[int] = None) -> str: + ... IndexedAttributeMap = Dict[IndexedAttribute, str] # target_attribute_key: source_attribute diff --git a/agentops/instrumentation/google_adk/patch.py b/agentops/instrumentation/google_adk/patch.py index bb62c42f7..88d9aa2df 100644 --- a/agentops/instrumentation/google_adk/patch.py +++ b/agentops/instrumentation/google_adk/patch.py @@ -304,16 +304,16 @@ def _extract_llm_attributes(llm_request_dict: dict, llm_response: Any) -> dict: elif "function_call" in part: # This is a function call in the response func_call = part["function_call"] - attributes[MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=0, j=tool_call_index)] = ( - func_call.get("name", "") - ) - attributes[MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=0, j=tool_call_index)] = ( - json.dumps(func_call.get("args", {})) - ) + attributes[ + MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=0, j=tool_call_index) + ] = func_call.get("name", "") + attributes[ + MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=0, j=tool_call_index) + ] = json.dumps(func_call.get("args", {})) if "id" in func_call: - attributes[MessageAttributes.COMPLETION_TOOL_CALL_ID.format(i=0, j=tool_call_index)] = ( - func_call["id"] - ) + attributes[ + MessageAttributes.COMPLETION_TOOL_CALL_ID.format(i=0, j=tool_call_index) + ] = func_call["id"] tool_call_index += 1 if text_parts: diff --git a/agentops/instrumentation/openai_agents/attributes/completion.py b/agentops/instrumentation/openai_agents/attributes/completion.py index 10bd6bfdc..d035d6cff 100644 --- a/agentops/instrumentation/openai_agents/attributes/completion.py +++ b/agentops/instrumentation/openai_agents/attributes/completion.py @@ -115,9 +115,9 @@ def get_raw_response_attributes(response: Dict[str, Any]) -> Dict[str, Any]: result[MessageAttributes.COMPLETION_TOOL_CALL_NAME.format(i=j, j=k)] = function.get( "name", "" ) - result[MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=j, j=k)] = ( - function.get("arguments", "") - ) + result[ + MessageAttributes.COMPLETION_TOOL_CALL_ARGUMENTS.format(i=j, j=k) + ] = function.get("arguments", "") return result diff --git a/tests/unit/sdk/instrumentation_tester.py b/tests/unit/sdk/instrumentation_tester.py index 4175270d6..606a91bfb 100644 --- a/tests/unit/sdk/instrumentation_tester.py +++ b/tests/unit/sdk/instrumentation_tester.py @@ -45,7 +45,8 @@ def reset_trace_globals(): class HasAttributesViaProperty(Protocol): @property - def attributes(self) -> Attributes: ... + def attributes(self) -> Attributes: + ... class HasAttributesViaAttr(Protocol): From 8b5cb752659314c9e0b6dff4973999492eaeedbf Mon Sep 17 00:00:00 2001 From: michi-okahata Date: Fri, 6 Jun 2025 16:53:57 -0700 Subject: [PATCH 6/6] fix ruff deletion --- agentops/instrumentation/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agentops/instrumentation/__init__.py b/agentops/instrumentation/__init__.py index 7f8daff40..81ea53fe9 100644 --- a/agentops/instrumentation/__init__.py +++ b/agentops/instrumentation/__init__.py @@ -33,7 +33,7 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore from agentops.logging import logger - +from agentops.sdk.core import tracer # Module-level state variables _active_instrumentors: list[BaseInstrumentor] = []