agent-dev-cli 0.0.1b251223__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_dev_cli-0.0.1b251223.dist-info/METADATA +143 -0
- agent_dev_cli-0.0.1b251223.dist-info/RECORD +20 -0
- agent_dev_cli-0.0.1b251223.dist-info/WHEEL +4 -0
- agent_dev_cli-0.0.1b251223.dist-info/entry_points.txt +3 -0
- agentdev/__init__.py +22 -0
- agentdev/__main__.py +5 -0
- agentdev/_bootstrap.py +70 -0
- agentdev/_hooks.py +275 -0
- agentdev/backend/__init__.py +10 -0
- agentdev/backend/_conversations.py +473 -0
- agentdev/backend/_utils.py +86 -0
- agentdev/backend/code_analyzer.py +41 -0
- agentdev/backend/errors.py +2 -0
- agentdev/backend/event_mapper.py +302 -0
- agentdev/backend/server.py +262 -0
- agentdev/backend/structs/__init__.py +10 -0
- agentdev/backend/structs/entity_response.py +30 -0
- agentdev/backend/structs/request.py +57 -0
- agentdev/cli.py +165 -0
- agentdev/localdebug.py +65 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-dev-cli
|
|
3
|
+
Version: 0.0.1b251223
|
|
4
|
+
Summary: AI Toolkit - CLI and SDK for agent debugging and workflow visualization
|
|
5
|
+
Keywords: ai,agent,toolkit,debugging,workflow,visualization
|
|
6
|
+
Requires-Python: >=3.10.0
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: pydantic>=2.12.4
|
|
20
|
+
Requires-Dist: azure-identity>=1.25.1
|
|
21
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
22
|
+
Requires-Dist: azure-ai-agents>=1.2.0b5
|
|
23
|
+
Requires-Dist: starlette>=0.49.3
|
|
24
|
+
Requires-Dist: openai>=1.109.1
|
|
25
|
+
Requires-Dist: agent-framework-azure-ai>=1.0.0b251211
|
|
26
|
+
Requires-Dist: azure-ai-agentserver-agentframework>=1.0.0b7
|
|
27
|
+
Requires-Dist: azure-ai-agentserver-core>=1.0.0b7
|
|
28
|
+
Requires-Dist: click>=8.1.0
|
|
29
|
+
Requires-Dist: azure-ai-projects>=2.0.0b2
|
|
30
|
+
Requires-Dist: pytest>=8.0.0 ; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.23.0 ; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=4.1.0 ; extra == "dev"
|
|
33
|
+
Requires-Dist: httpx>=0.27.0 ; extra == "dev"
|
|
34
|
+
Project-URL: Documentation, https://github.com/microsoft/vscode-ai-toolkit#readme
|
|
35
|
+
Project-URL: Homepage, https://github.com/microsoft/vscode-ai-toolkit
|
|
36
|
+
Project-URL: Issues, https://github.com/microsoft/vscode-ai-toolkit/issues
|
|
37
|
+
Project-URL: Repository, https://github.com/microsoft/vscode-ai-toolkit
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
|
|
40
|
+
# Agent Dev CLI
|
|
41
|
+
|
|
42
|
+
Agent Dev CLI - A Python package for agent debugging and workflow visualization with VS Code integration.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install -e .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Option 1: CLI Wrapper (Recommended)
|
|
53
|
+
|
|
54
|
+
The easiest way to use Agent Dev CLI - **no code changes required**:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Run your agent script with agentdev instrumentation
|
|
58
|
+
agentdev run my_agent.py
|
|
59
|
+
|
|
60
|
+
# Specify a custom port
|
|
61
|
+
agentdev run workflow.py --port 9000
|
|
62
|
+
|
|
63
|
+
# Enable verbose output
|
|
64
|
+
agentdev run my_agent.py --verbose
|
|
65
|
+
|
|
66
|
+
# Pass arguments to your script
|
|
67
|
+
agentdev run my_agent.py -- --model gpt-4 --temperature 0.7
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The CLI automatically:
|
|
71
|
+
- Intercepts `from_agent_framework()` calls
|
|
72
|
+
- Injects agentdev visualization endpoints
|
|
73
|
+
- Opens the workflow visualization in VS Code
|
|
74
|
+
|
|
75
|
+
### Option 2: Programmatic API
|
|
76
|
+
|
|
77
|
+
If you prefer explicit control, you can integrate agentdev directly:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from agentdev import setup_test_tool
|
|
81
|
+
from azure.ai.agentserver.agentframework import from_agent_framework
|
|
82
|
+
|
|
83
|
+
# Create your agent
|
|
84
|
+
agent = build_agent(chat_client)
|
|
85
|
+
|
|
86
|
+
# Create agent server
|
|
87
|
+
agent_server = from_agent_framework(agent)
|
|
88
|
+
|
|
89
|
+
# Setup workflow visualization
|
|
90
|
+
setup_test_tool(agent_server)
|
|
91
|
+
|
|
92
|
+
# Run the server
|
|
93
|
+
await agent_server.run_async()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## CLI Commands
|
|
97
|
+
|
|
98
|
+
### `agentdev run`
|
|
99
|
+
|
|
100
|
+
Run a Python agent script with agentdev instrumentation.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
agentdev run [OPTIONS] SCRIPT [ARGS]...
|
|
104
|
+
|
|
105
|
+
Options:
|
|
106
|
+
-p, --port INTEGER Agent server port (default: 8088)
|
|
107
|
+
-v, --verbose Enable verbose output
|
|
108
|
+
--help Show this message and exit
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `agentdev info`
|
|
112
|
+
|
|
113
|
+
Show agentdev configuration and status information.
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
agentdev info
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Features
|
|
120
|
+
|
|
121
|
+
- **Health Check Endpoint**: Adds a `/agentdev/health` endpoint to your agent server
|
|
122
|
+
- **Workflow Visualization**: Starts a visualization server on port 8090 for WorkflowAgent instances
|
|
123
|
+
- **Easy Integration**: Simple one-function setup
|
|
124
|
+
|
|
125
|
+
## Requirements
|
|
126
|
+
|
|
127
|
+
- Python 3.10+
|
|
128
|
+
- agent-framework
|
|
129
|
+
- starlette
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT License
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## Test
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
curl 'http://localhost:8088/agentdev/v1/responses' \
|
|
140
|
+
-H 'Content-Type: application/json' \
|
|
141
|
+
-d '{"model":"workflow_in-memory_content-review-workflow_5c703d16cb1e4756848ddcc685b16503","input":{"role":"user","text":"test"},"stream":true}'
|
|
142
|
+
```
|
|
143
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
agentdev/__init__.py,sha256=x8tqJT9_MfcIjgmP1dB8gztU3cXEjkUkxk6Q8bEgXjk,537
|
|
2
|
+
agentdev/__main__.py,sha256=lHwzD56r-Jd0A_VOGRmv2PcP2AZ56dWz61o3zCBGxzY,135
|
|
3
|
+
agentdev/_bootstrap.py,sha256=XQ2sKmTxJzS7S6AvvfUbegP6FZxJ93UO5clHpB_SUhQ,2193
|
|
4
|
+
agentdev/_hooks.py,sha256=TeZWMQQeiSWzOokceDrVrYkOl4DT8oR5isBlhJRAu5A,9859
|
|
5
|
+
agentdev/cli.py,sha256=dbDfnppPXUA1G2lpGh4U-Y-g-t1eFp0K9J97DzknQvk,4724
|
|
6
|
+
agentdev/localdebug.py,sha256=Pr_DMsYZrYS_ijnahCQ6QT6_KqEo7e1-7lQ2QHTucIE,1977
|
|
7
|
+
agentdev/backend/__init__.py,sha256=BFiYU9_0aAfygA0oTs0o70etmH65_gX9cN53ZcMwFIY,197
|
|
8
|
+
agentdev/backend/_conversations.py,sha256=ui62ml5pise0fF9ri7HITM_l4irMdmm2jJ7d_U1FL74,18518
|
|
9
|
+
agentdev/backend/_utils.py,sha256=9fx1bAZZR13wUX4d6OeOnCRDWglExpBA2yM1oIhozV4,3138
|
|
10
|
+
agentdev/backend/code_analyzer.py,sha256=NfKmoPSCVB39qFG_jzhY9Qf1iYiTNezpGVxJQyr4ZLE,1517
|
|
11
|
+
agentdev/backend/errors.py,sha256=95geZNBeAfxAWyJDCaGFXSFsCifUZ2V0PHmsPOYsmt4,53
|
|
12
|
+
agentdev/backend/event_mapper.py,sha256=0k0zAMoiBteQjK2TELQXhjYFD0dcZCcuDwM2cKuS7pA,11847
|
|
13
|
+
agentdev/backend/server.py,sha256=XWWHpVC8eKtqvU5esKOkaUlqHKFjbe2iif2eqbzHdXE,12262
|
|
14
|
+
agentdev/backend/structs/__init__.py,sha256=UKpDMo_sjEtvmHI8Rys6_s4dUYaE0lz3-jw0T_BWoQ8,212
|
|
15
|
+
agentdev/backend/structs/entity_response.py,sha256=0z5lliYeQmX3jgz4TGJNSt82vVxccsCHYop5hDxU1fc,1103
|
|
16
|
+
agentdev/backend/structs/request.py,sha256=KsAHkDGGLW53_sOBDxV21D3cv_TzVcGYYP-jfM_ebV8,2053
|
|
17
|
+
agent_dev_cli-0.0.1b251223.dist-info/entry_points.txt,sha256=Zeb1F0rPDO1dIQorHn7Q-hpOg09ZDE7elz4fowvO6BQ,46
|
|
18
|
+
agent_dev_cli-0.0.1b251223.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
19
|
+
agent_dev_cli-0.0.1b251223.dist-info/METADATA,sha256=ruzicRPC0YmVOb7i0bjM84wY5DHRXLROYZAe8zq1I0U,3991
|
|
20
|
+
agent_dev_cli-0.0.1b251223.dist-info/RECORD,,
|
agentdev/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentdev Package
|
|
3
|
+
|
|
4
|
+
Agent Dev CLI - A package for agent debugging and workflow visualization.
|
|
5
|
+
|
|
6
|
+
This package provides two ways to use agentdev:
|
|
7
|
+
|
|
8
|
+
1. CLI Wrapper (Recommended - No code changes required):
|
|
9
|
+
|
|
10
|
+
$ agentdev run my_agent.py
|
|
11
|
+
$ agentdev run workflow.py --port 9000
|
|
12
|
+
|
|
13
|
+
2. Programmatic API (Requires code modification):
|
|
14
|
+
|
|
15
|
+
from agentdev import setup_test_tool
|
|
16
|
+
setup_test_tool(agent_server)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .localdebug import setup_test_tool
|
|
20
|
+
|
|
21
|
+
__version__ = "0.0.1b251223"
|
|
22
|
+
__all__ = ["setup_test_tool"]
|
agentdev/__main__.py
ADDED
agentdev/_bootstrap.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentdev Bootstrap Module.
|
|
3
|
+
|
|
4
|
+
This module is executed via `python -m agentdev._bootstrap` to set up
|
|
5
|
+
import hooks before running the user's agent script.
|
|
6
|
+
|
|
7
|
+
The bootstrap process:
|
|
8
|
+
1. Install import hooks for auto-instrumentation
|
|
9
|
+
2. Modify sys.argv to match what the user script expects
|
|
10
|
+
3. Execute the user's script in __main__ context
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import runpy
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def bootstrap():
|
|
20
|
+
"""Bootstrap the user's script with agentdev instrumentation."""
|
|
21
|
+
|
|
22
|
+
# Check if we have a script to run
|
|
23
|
+
if len(sys.argv) < 2:
|
|
24
|
+
print("agentdev Bootstrap: No script specified", file=sys.stderr)
|
|
25
|
+
sys.exit(1)
|
|
26
|
+
|
|
27
|
+
script_path = sys.argv[1]
|
|
28
|
+
|
|
29
|
+
# Validate script exists
|
|
30
|
+
if not os.path.isfile(script_path):
|
|
31
|
+
print(f"agentdev Bootstrap: Script not found: {script_path}", file=sys.stderr)
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
35
|
+
|
|
36
|
+
if verbose:
|
|
37
|
+
print(f"agentdev Bootstrap: Installing import hooks...", file=sys.stderr)
|
|
38
|
+
|
|
39
|
+
# Install import hooks BEFORE running user code
|
|
40
|
+
from agentdev._hooks import install_hooks
|
|
41
|
+
install_hooks()
|
|
42
|
+
|
|
43
|
+
if verbose:
|
|
44
|
+
print(f"agentdev Bootstrap: Hooks installed, running {script_path}", file=sys.stderr)
|
|
45
|
+
|
|
46
|
+
# Adjust sys.argv to remove bootstrap reference
|
|
47
|
+
# User script sees: [script_path, arg1, arg2, ...]
|
|
48
|
+
sys.argv = sys.argv[1:]
|
|
49
|
+
|
|
50
|
+
# Add script's directory to sys.path for relative imports
|
|
51
|
+
script_dir = str(Path(script_path).parent.absolute())
|
|
52
|
+
if script_dir not in sys.path:
|
|
53
|
+
sys.path.insert(0, script_dir)
|
|
54
|
+
|
|
55
|
+
# Run the user's script as __main__
|
|
56
|
+
try:
|
|
57
|
+
# Use runpy for proper __main__ execution
|
|
58
|
+
runpy.run_path(script_path, run_name='__main__')
|
|
59
|
+
except SystemExit:
|
|
60
|
+
# Re-raise SystemExit to preserve exit codes
|
|
61
|
+
raise
|
|
62
|
+
except KeyboardInterrupt:
|
|
63
|
+
if verbose:
|
|
64
|
+
print("\nagentdev Bootstrap: Interrupted by user", file=sys.stderr)
|
|
65
|
+
sys.exit(130)
|
|
66
|
+
# Let other exceptions propagate so debuggers can break on them
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == '__main__':
|
|
70
|
+
bootstrap()
|
agentdev/_hooks.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentdev Import Hooks.
|
|
3
|
+
|
|
4
|
+
This module provides import hooks that automatically instrument
|
|
5
|
+
the agent framework to inject agentdev visualization and debugging
|
|
6
|
+
capabilities without requiring user code modifications.
|
|
7
|
+
|
|
8
|
+
The hook intercepts:
|
|
9
|
+
- `azure.ai.agentserver.agentframework.from_agent_framework()`
|
|
10
|
+
to automatically call `setup_test_tool()` on the created server.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import os
|
|
15
|
+
import builtins
|
|
16
|
+
import functools
|
|
17
|
+
from typing import Any, Callable, Optional
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Global flag to track if hooks are installed
|
|
21
|
+
_hooks_installed = False
|
|
22
|
+
|
|
23
|
+
# Store original functions for potential restoration
|
|
24
|
+
_original_from_agent_framework: Optional[Callable] = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _create_patched_from_agent_framework(original_func: Callable) -> Callable:
|
|
28
|
+
"""Create a patched version of from_agent_framework that auto-injects agentdev.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
original_func: The original from_agent_framework function
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Patched function that calls setup_test_tool automatically
|
|
35
|
+
"""
|
|
36
|
+
@functools.wraps(original_func)
|
|
37
|
+
def patched_from_agent_framework(agent: Any, **kwargs) -> Any:
|
|
38
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
39
|
+
|
|
40
|
+
if verbose:
|
|
41
|
+
print(f"agentdev Hook: Intercepted from_agent_framework() call", file=sys.stderr)
|
|
42
|
+
|
|
43
|
+
# Call original function to create the server
|
|
44
|
+
server = original_func(agent, **kwargs)
|
|
45
|
+
|
|
46
|
+
if verbose:
|
|
47
|
+
print(f"agentdev Hook: Agent server created, injecting agentdev...", file=sys.stderr)
|
|
48
|
+
|
|
49
|
+
# Auto-inject agentdev visualization
|
|
50
|
+
try:
|
|
51
|
+
from agentdev.localdebug import setup_test_tool
|
|
52
|
+
setup_test_tool(server)
|
|
53
|
+
|
|
54
|
+
if verbose:
|
|
55
|
+
print(f"agentdev Hook: Successfully injected agentdev instrumentation", file=sys.stderr)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"agentdev Hook: Warning - Failed to inject agentdev: {e}", file=sys.stderr)
|
|
58
|
+
# Don't fail the user's code, just warn
|
|
59
|
+
|
|
60
|
+
return server
|
|
61
|
+
|
|
62
|
+
return patched_from_agent_framework
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _patch_agentserver_module(module: Any, silent_retry: bool = False) -> bool:
|
|
66
|
+
"""Patch the agentserver.agentframework module with agentdev instrumentation.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
module: The azure.ai.agentserver.agentframework module
|
|
70
|
+
silent_retry: If True, don't log retry messages
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
True if patching was successful, False if should retry later
|
|
74
|
+
"""
|
|
75
|
+
global _original_from_agent_framework
|
|
76
|
+
|
|
77
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
78
|
+
|
|
79
|
+
if hasattr(module, 'from_agent_framework'):
|
|
80
|
+
# Store original for potential restoration
|
|
81
|
+
_original_from_agent_framework = module.from_agent_framework
|
|
82
|
+
|
|
83
|
+
# Replace with patched version
|
|
84
|
+
module.from_agent_framework = _create_patched_from_agent_framework(
|
|
85
|
+
_original_from_agent_framework
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if verbose:
|
|
89
|
+
print(f"agentdev Hook: Patched from_agent_framework()", file=sys.stderr)
|
|
90
|
+
return True
|
|
91
|
+
else:
|
|
92
|
+
# Only log once on first retry attempt
|
|
93
|
+
if verbose and not silent_retry:
|
|
94
|
+
print(f"agentdev Hook: Waiting for from_agent_framework to be available...", file=sys.stderr)
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class AgentDevMetaPathFinder:
|
|
99
|
+
"""Meta path finder that intercepts agent framework imports.
|
|
100
|
+
|
|
101
|
+
This finder watches for imports of azure.ai.agentserver.agentframework
|
|
102
|
+
and patches the module after it's loaded.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
TARGET_MODULE = "azure.ai.agentserver.agentframework"
|
|
106
|
+
|
|
107
|
+
def __init__(self):
|
|
108
|
+
self._patched = False
|
|
109
|
+
self._verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
110
|
+
|
|
111
|
+
def find_module(self, fullname: str, path: Any = None) -> Optional["AgentDevMetaPathFinder"]:
|
|
112
|
+
"""Called for each import - we use this to detect our target module.
|
|
113
|
+
|
|
114
|
+
Note: We return None to let normal import proceed, then patch afterward.
|
|
115
|
+
"""
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def find_spec(self, fullname: str, path: Any, target: Any = None) -> None:
|
|
119
|
+
"""Called for each import in Python 3.4+.
|
|
120
|
+
|
|
121
|
+
We don't provide a spec - we just use this as a notification hook.
|
|
122
|
+
"""
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class AgentDevImportHook:
|
|
127
|
+
"""Import hook that patches modules after they're imported.
|
|
128
|
+
|
|
129
|
+
This uses sys.meta_path to intercept imports and patch the
|
|
130
|
+
agentserver module when it's loaded.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
TARGET_MODULE = "azure.ai.agentserver.agentframework"
|
|
134
|
+
|
|
135
|
+
def __init__(self):
|
|
136
|
+
self._patched = False
|
|
137
|
+
self._first_attempt = True
|
|
138
|
+
self._verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
139
|
+
|
|
140
|
+
def find_module(self, fullname: str, path: Any = None):
|
|
141
|
+
"""Legacy finder method for Python 3.3 compatibility."""
|
|
142
|
+
# Check if target module was just imported
|
|
143
|
+
self._check_and_patch()
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def find_spec(self, fullname: str, path: Any, target: Any = None):
|
|
147
|
+
"""Finder method for Python 3.4+."""
|
|
148
|
+
# Check if target module was just imported
|
|
149
|
+
self._check_and_patch()
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
def _check_and_patch(self) -> None:
|
|
153
|
+
"""Check if target module is loaded and patch if necessary."""
|
|
154
|
+
if self._patched:
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
if self.TARGET_MODULE in sys.modules:
|
|
158
|
+
module = sys.modules[self.TARGET_MODULE]
|
|
159
|
+
# Only show "waiting" message on first attempt
|
|
160
|
+
silent = not self._first_attempt
|
|
161
|
+
self._first_attempt = False
|
|
162
|
+
if _patch_agentserver_module(module, silent_retry=silent):
|
|
163
|
+
self._patched = True
|
|
164
|
+
|
|
165
|
+
def _install_post_import_hook() -> None:
|
|
166
|
+
"""Install a hook that patches the module after import.
|
|
167
|
+
|
|
168
|
+
Since we can't easily intercept the module during import,
|
|
169
|
+
we use a different approach: patch sys.modules monitoring.
|
|
170
|
+
"""
|
|
171
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
172
|
+
|
|
173
|
+
# First, check if the module is already imported
|
|
174
|
+
target = "azure.ai.agentserver.agentframework"
|
|
175
|
+
target_parts = target.split(".")
|
|
176
|
+
|
|
177
|
+
if target in sys.modules:
|
|
178
|
+
if verbose:
|
|
179
|
+
print(f"agentdev Hook: Target module already loaded, patching now", file=sys.stderr)
|
|
180
|
+
_patch_agentserver_module(sys.modules[target])
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Install meta path hook to catch future imports
|
|
184
|
+
hook = AgentDevImportHook()
|
|
185
|
+
sys.meta_path.insert(0, hook)
|
|
186
|
+
|
|
187
|
+
if verbose:
|
|
188
|
+
print(f"agentdev Hook: Installed meta path finder", file=sys.stderr)
|
|
189
|
+
|
|
190
|
+
# Monkey-patch __import__ for more reliable interception
|
|
191
|
+
# Use the builtins module (standard way) instead of __builtins__ (implementation detail)
|
|
192
|
+
original_import = builtins.__import__
|
|
193
|
+
|
|
194
|
+
def patched_import(name, globals=None, locals=None, fromlist=(), level=0):
|
|
195
|
+
result = original_import(name, globals, locals, fromlist, level)
|
|
196
|
+
|
|
197
|
+
# Only check when importing something related to our target
|
|
198
|
+
# This reduces noise from unrelated imports
|
|
199
|
+
if hook._patched:
|
|
200
|
+
return result
|
|
201
|
+
|
|
202
|
+
# Check if this import is our target or a parent/child of it
|
|
203
|
+
if name == target or name.startswith("azure.ai.agentserver") or target.startswith(name + "."):
|
|
204
|
+
if target in sys.modules:
|
|
205
|
+
module = sys.modules[target]
|
|
206
|
+
# Use hook's first_attempt tracking for silent retry
|
|
207
|
+
silent = not hook._first_attempt
|
|
208
|
+
hook._first_attempt = False
|
|
209
|
+
if _patch_agentserver_module(module, silent_retry=silent):
|
|
210
|
+
hook._patched = True
|
|
211
|
+
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
builtins.__import__ = patched_import
|
|
215
|
+
|
|
216
|
+
if verbose:
|
|
217
|
+
print(f"agentdev Hook: Installed __import__ hook", file=sys.stderr)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def install_hooks() -> None:
|
|
221
|
+
"""Install agentdev import hooks for auto-instrumentation.
|
|
222
|
+
|
|
223
|
+
This function should be called before any user code runs.
|
|
224
|
+
It sets up hooks to automatically patch the agent framework
|
|
225
|
+
when it's imported.
|
|
226
|
+
"""
|
|
227
|
+
global _hooks_installed
|
|
228
|
+
|
|
229
|
+
if _hooks_installed:
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
233
|
+
|
|
234
|
+
if verbose:
|
|
235
|
+
print("agentdev Hook: Installing import hooks...", file=sys.stderr)
|
|
236
|
+
|
|
237
|
+
_install_post_import_hook()
|
|
238
|
+
_hooks_installed = True
|
|
239
|
+
|
|
240
|
+
if verbose:
|
|
241
|
+
print("agentdev Hook: Import hooks installed successfully", file=sys.stderr)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def uninstall_hooks() -> None:
|
|
245
|
+
"""Uninstall agentdev import hooks and restore original functions.
|
|
246
|
+
|
|
247
|
+
This can be used for testing or if the user wants to disable
|
|
248
|
+
agentdev instrumentation at runtime.
|
|
249
|
+
"""
|
|
250
|
+
global _hooks_installed, _original_from_agent_framework
|
|
251
|
+
|
|
252
|
+
if not _hooks_installed:
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
verbose = os.environ.get('AGENTDEV_VERBOSE') == '1'
|
|
256
|
+
|
|
257
|
+
# Restore original from_agent_framework if we patched it
|
|
258
|
+
target = "azure.ai.agentserver.agentframework"
|
|
259
|
+
if target in sys.modules and _original_from_agent_framework:
|
|
260
|
+
sys.modules[target].from_agent_framework = _original_from_agent_framework
|
|
261
|
+
|
|
262
|
+
if verbose:
|
|
263
|
+
print("agentdev Hook: Restored original from_agent_framework()", file=sys.stderr)
|
|
264
|
+
|
|
265
|
+
# Remove our meta path finders
|
|
266
|
+
sys.meta_path = [
|
|
267
|
+
finder for finder in sys.meta_path
|
|
268
|
+
if not isinstance(finder, AgentDevImportHook)
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
_hooks_installed = False
|
|
272
|
+
_original_from_agent_framework = None
|
|
273
|
+
|
|
274
|
+
if verbose:
|
|
275
|
+
print("agentdev Hook: Hooks uninstalled", file=sys.stderr)
|