agentr 0.1.2__py3-none-any.whl → 0.1.4__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.
agentr/utils/openapi.py CHANGED
@@ -1,185 +1,185 @@
1
- import json
2
- import yaml
3
- from pathlib import Path
4
-
5
- def load_schema(path: Path):
6
- if path.suffix == '.yaml':
7
- type = 'yaml'
8
- else:
9
- type = 'json'
10
- with open(path, 'r') as f:
11
- if type == 'yaml':
12
- return yaml.safe_load(f)
13
- else:
14
- return json.load(f)
15
-
16
- def generate_api_client(schema):
17
- """
18
- Generate a Python API client class from an OpenAPI schema.
19
-
20
- Args:
21
- schema (dict): The OpenAPI schema as a dictionary.
22
-
23
- Returns:
24
- str: A string containing the Python code for the API client class.
25
- """
26
- methods = []
27
-
28
- # Iterate over paths and their operations
29
- for path, path_info in schema.get('paths', {}).items():
30
- for method in path_info:
31
- if method in ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']:
32
- operation = path_info[method]
33
- method_code = generate_method_code(path, method, operation)
34
- methods.append(method_code)
35
-
36
- # Construct the class code
37
- class_code = (
38
- "import requests\n\n"
39
- "class APIClient:\n"
40
- " def __init__(self, base_url):\n"
41
- " self.base_url = base_url\n\n" +
42
- '\n\n'.join(methods)
43
- )
44
- return class_code
45
-
46
- def generate_method_code(path, method, operation):
47
- """
48
- Generate the code for a single API method.
49
-
50
- Args:
51
- path (str): The API path (e.g., '/users/{user_id}').
52
- method (str): The HTTP method (e.g., 'get').
53
- operation (dict): The operation details from the schema.
54
-
55
- Returns:
56
- str: The Python code for the method.
57
- """
58
- # Determine function name
59
- if 'operationId' in operation:
60
- func_name = operation['operationId']
61
- else:
62
- # Generate name from path and method
63
- path_parts = path.strip('/').split('/')
64
- name_parts = [method]
65
- for part in path_parts:
66
- if part.startswith('{') and part.endswith('}'):
67
- name_parts.append('by_' + part[1:-1])
68
- else:
69
- name_parts.append(part)
70
- func_name = '_'.join(name_parts).replace('-', '_').lower()
71
-
72
- # Get parameters and request body
73
- parameters = operation.get('parameters', [])
74
- has_body = 'requestBody' in operation
75
- body_required = has_body and operation['requestBody'].get('required', False)
76
-
77
- # Build function arguments
78
- args = []
79
- for param in parameters:
80
- if param.get('required', False):
81
- args.append(param['name'])
82
- else:
83
- args.append(f"{param['name']}=None")
84
- if has_body:
85
- args.append('body' if body_required else 'body=None')
86
- signature = f"def {func_name}(self, {', '.join(args)}):"
87
-
88
- # Build method body
89
- body_lines = []
90
-
91
- # Path parameters
92
- path_params = [p for p in parameters if p['in'] == 'path']
93
- path_params_dict = ', '.join([f"'{p['name']}': {p['name']}" for p in path_params])
94
- body_lines.append(f" path_params = {{{path_params_dict}}}")
95
-
96
- # Query parameters
97
- query_params = [p for p in parameters if p['in'] == 'query']
98
- query_params_items = ', '.join([f"('{p['name']}', {p['name']})" for p in query_params])
99
- body_lines.append(
100
- f" query_params = {{k: v for k, v in [{query_params_items}] if v is not None}}"
101
- )
102
-
103
- # Format URL
104
- body_lines.append(f" url = f\"{{self.base_url}}{path}\".format_map(path_params)")
105
-
106
- # Make HTTP request
107
- method_func = method.lower()
108
- if has_body:
109
- body_lines.append(" if body is not None:")
110
- body_lines.append(f" response = requests.{method_func}(url, params=query_params, json=body)")
111
- body_lines.append(" else:")
112
- body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
113
- else:
114
- body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
115
-
116
- # Handle response
117
- body_lines.append(" response.raise_for_status()")
118
- body_lines.append(" return response.json()")
119
-
120
- return signature + '\n' + '\n'.join(body_lines)
121
-
122
- # Example usage
123
- if __name__ == "__main__":
124
- # Sample OpenAPI schema
125
- schema = {
126
- "paths": {
127
- "/users": {
128
- "get": {
129
- "summary": "Get a list of users",
130
- "parameters": [
131
- {
132
- "name": "limit",
133
- "in": "query",
134
- "required": False,
135
- "schema": {"type": "integer"}
136
- }
137
- ],
138
- "responses": {
139
- "200": {
140
- "description": "A list of users",
141
- "content": {"application/json": {"schema": {"type": "array"}}}
142
- }
143
- }
144
- },
145
- "post": {
146
- "summary": "Create a user",
147
- "requestBody": {
148
- "required": True,
149
- "content": {
150
- "application/json": {
151
- "schema": {
152
- "type": "object",
153
- "properties": {"name": {"type": "string"}}
154
- }
155
- }
156
- }
157
- },
158
- "responses": {
159
- "201": {"description": "User created"}
160
- }
161
- }
162
- },
163
- "/users/{user_id}": {
164
- "get": {
165
- "summary": "Get a user by ID",
166
- "parameters": [
167
- {
168
- "name": "user_id",
169
- "in": "path",
170
- "required": True,
171
- "schema": {"type": "string"}
172
- }
173
- ],
174
- "responses": {
175
- "200": {"description": "User details"}
176
- }
177
- }
178
- }
179
- }
180
- }
181
-
182
-
183
- schema = load_schema('openapi.yaml')
184
- code = generate_api_client(schema)
1
+ import json
2
+ import yaml
3
+ from pathlib import Path
4
+
5
+ def load_schema(path: Path):
6
+ if path.suffix == '.yaml':
7
+ type = 'yaml'
8
+ else:
9
+ type = 'json'
10
+ with open(path, 'r') as f:
11
+ if type == 'yaml':
12
+ return yaml.safe_load(f)
13
+ else:
14
+ return json.load(f)
15
+
16
+ def generate_api_client(schema):
17
+ """
18
+ Generate a Python API client class from an OpenAPI schema.
19
+
20
+ Args:
21
+ schema (dict): The OpenAPI schema as a dictionary.
22
+
23
+ Returns:
24
+ str: A string containing the Python code for the API client class.
25
+ """
26
+ methods = []
27
+
28
+ # Iterate over paths and their operations
29
+ for path, path_info in schema.get('paths', {}).items():
30
+ for method in path_info:
31
+ if method in ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']:
32
+ operation = path_info[method]
33
+ method_code = generate_method_code(path, method, operation)
34
+ methods.append(method_code)
35
+
36
+ # Construct the class code
37
+ class_code = (
38
+ "import requests\n\n"
39
+ "class APIClient:\n"
40
+ " def __init__(self, base_url):\n"
41
+ " self.base_url = base_url\n\n" +
42
+ '\n\n'.join(methods)
43
+ )
44
+ return class_code
45
+
46
+ def generate_method_code(path, method, operation):
47
+ """
48
+ Generate the code for a single API method.
49
+
50
+ Args:
51
+ path (str): The API path (e.g., '/users/{user_id}').
52
+ method (str): The HTTP method (e.g., 'get').
53
+ operation (dict): The operation details from the schema.
54
+
55
+ Returns:
56
+ str: The Python code for the method.
57
+ """
58
+ # Determine function name
59
+ if 'operationId' in operation:
60
+ func_name = operation['operationId']
61
+ else:
62
+ # Generate name from path and method
63
+ path_parts = path.strip('/').split('/')
64
+ name_parts = [method]
65
+ for part in path_parts:
66
+ if part.startswith('{') and part.endswith('}'):
67
+ name_parts.append('by_' + part[1:-1])
68
+ else:
69
+ name_parts.append(part)
70
+ func_name = '_'.join(name_parts).replace('-', '_').lower()
71
+
72
+ # Get parameters and request body
73
+ parameters = operation.get('parameters', [])
74
+ has_body = 'requestBody' in operation
75
+ body_required = has_body and operation['requestBody'].get('required', False)
76
+
77
+ # Build function arguments
78
+ args = []
79
+ for param in parameters:
80
+ if param.get('required', False):
81
+ args.append(param['name'])
82
+ else:
83
+ args.append(f"{param['name']}=None")
84
+ if has_body:
85
+ args.append('body' if body_required else 'body=None')
86
+ signature = f"def {func_name}(self, {', '.join(args)}):"
87
+
88
+ # Build method body
89
+ body_lines = []
90
+
91
+ # Path parameters
92
+ path_params = [p for p in parameters if p['in'] == 'path']
93
+ path_params_dict = ', '.join([f"'{p['name']}': {p['name']}" for p in path_params])
94
+ body_lines.append(f" path_params = {{{path_params_dict}}}")
95
+
96
+ # Query parameters
97
+ query_params = [p for p in parameters if p['in'] == 'query']
98
+ query_params_items = ', '.join([f"('{p['name']}', {p['name']})" for p in query_params])
99
+ body_lines.append(
100
+ f" query_params = {{k: v for k, v in [{query_params_items}] if v is not None}}"
101
+ )
102
+
103
+ # Format URL
104
+ body_lines.append(f" url = f\"{{self.base_url}}{path}\".format_map(path_params)")
105
+
106
+ # Make HTTP request
107
+ method_func = method.lower()
108
+ if has_body:
109
+ body_lines.append(" if body is not None:")
110
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params, json=body)")
111
+ body_lines.append(" else:")
112
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
113
+ else:
114
+ body_lines.append(f" response = requests.{method_func}(url, params=query_params)")
115
+
116
+ # Handle response
117
+ body_lines.append(" response.raise_for_status()")
118
+ body_lines.append(" return response.json()")
119
+
120
+ return signature + '\n' + '\n'.join(body_lines)
121
+
122
+ # Example usage
123
+ if __name__ == "__main__":
124
+ # Sample OpenAPI schema
125
+ schema = {
126
+ "paths": {
127
+ "/users": {
128
+ "get": {
129
+ "summary": "Get a list of users",
130
+ "parameters": [
131
+ {
132
+ "name": "limit",
133
+ "in": "query",
134
+ "required": False,
135
+ "schema": {"type": "integer"}
136
+ }
137
+ ],
138
+ "responses": {
139
+ "200": {
140
+ "description": "A list of users",
141
+ "content": {"application/json": {"schema": {"type": "array"}}}
142
+ }
143
+ }
144
+ },
145
+ "post": {
146
+ "summary": "Create a user",
147
+ "requestBody": {
148
+ "required": True,
149
+ "content": {
150
+ "application/json": {
151
+ "schema": {
152
+ "type": "object",
153
+ "properties": {"name": {"type": "string"}}
154
+ }
155
+ }
156
+ }
157
+ },
158
+ "responses": {
159
+ "201": {"description": "User created"}
160
+ }
161
+ }
162
+ },
163
+ "/users/{user_id}": {
164
+ "get": {
165
+ "summary": "Get a user by ID",
166
+ "parameters": [
167
+ {
168
+ "name": "user_id",
169
+ "in": "path",
170
+ "required": True,
171
+ "schema": {"type": "string"}
172
+ }
173
+ ],
174
+ "responses": {
175
+ "200": {"description": "User details"}
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+
183
+ schema = load_schema('openapi.yaml')
184
+ code = generate_api_client(schema)
185
185
  print(code)
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentr
3
+ Version: 0.1.4
4
+ Summary: Add your description here
5
+ Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: loguru>=0.7.3
8
+ Requires-Dist: mcp>=1.5.0
9
+ Requires-Dist: pyyaml>=6.0.2
10
+ Requires-Dist: typer>=0.15.2
11
+ Description-Content-Type: text/markdown
12
+
13
+ # AgentR
14
+
15
+ AgentR is a Python framework for building powerful agent applications with integrated third-party services. It provides a clean abstraction for incorporating various API services as "applications" into your agent workflow.
16
+
17
+ ## 🌟 Features
18
+
19
+ - **Simplified API Integration**: Connect to services like GitHub, Google Calendar, Gmail, Reddit, Tavily, and more with minimal code
20
+ - **Authentication Handling**: Built-in support for API keys and OAuth-based authentication flows
21
+ - **Extensible Architecture**: Easily build and add new app integrations with minimal boilerplate
22
+ - **MCP (Model Context Protocol) Integration**: Seamlessly works with MCP server architecture
23
+ - **Credential Management**: Flexible storage options for API credentials with memory and environment-based implementations
24
+
25
+ ## 🔧 Installation
26
+
27
+ Install AgentR using pip:
28
+
29
+ ```bash
30
+ pip install agentr
31
+ ```
32
+
33
+ ## 🚀 Quick Start
34
+
35
+ ### 1. Get an API Key
36
+ Before using AgentR with services that require authorization (like GitHub, Gmail, etc.), you'll need an AgentR API key:
37
+
38
+ Visit https://agentr.dev to create an account
39
+ Generate an API key from your dashboard
40
+ Set it as an environment variable or include it directly in your code:
41
+
42
+ ```bash
43
+ export AGENTR_API_KEY="your_api_key_here"
44
+ ```
45
+
46
+ ### 2. Create a basic server
47
+
48
+ ```bash
49
+ from agentr.server import TestServer
50
+
51
+ # Define your applications list
52
+ apps_list = [
53
+ {
54
+ "name": "tavily",
55
+ "integration": {
56
+ "name": "tavily_api_key",
57
+ "type": "api_key",
58
+ "store": {
59
+ "type": "environment",
60
+ }
61
+ },
62
+ },
63
+ {
64
+ "name": "zenquotes",
65
+ "integration": None
66
+ },
67
+ {
68
+ "name": "github",
69
+ "integration": {
70
+ "name": "github",
71
+ "type": "agentr",
72
+ }
73
+ }
74
+ ]
75
+
76
+ # Create a server with these applications
77
+ server = TestServer(name="My Agent Server", description="A server for my agent apps", apps_list=apps_list)
78
+
79
+ # Run the server
80
+ if __name__ == "__main__":
81
+ server.run()
82
+ ```
83
+
84
+ ## 🧩 Available Applications
85
+ AgentR comes with several pre-built applications:
86
+
87
+ | Application | Description | Authentication Type |
88
+ |-------------|-------------|---------------------|
89
+ | GitHub | Star repositories and more | OAuth (AgentR) |
90
+ | Google Calendar | Retrieve calendar events | OAuth (AgentR) |
91
+ | Gmail | Send emails | OAuth (AgentR) |
92
+ | Reddit | Access Reddit data | OAuth (AgentR) |
93
+ | Resend | Send emails via Resend API | API Key |
94
+ | Tavily | Web search capabilities | API Key |
95
+ | ZenQuotes | Get inspirational quotes | None |
96
+
97
+ > **Note**: More applications are coming soon! Stay tuned for updates to our application catalog.
98
+
99
+ ## 🔐 Integration Types
100
+ AgentR supports two primary integration types:
101
+
102
+ ### 1. API Key Integration
103
+ For services that authenticate via API keys:
104
+ ```python
105
+ {
106
+ "name": "service_name",
107
+ "integration": {
108
+ "name": "service_api_key",
109
+ "type": "api_key",
110
+ "store": {
111
+ "type": "environment", # or "memory"
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### 2. OAuth Integration (via AgentR)
118
+ For services requiring OAuth flow:
119
+ ```python
120
+ {
121
+ "name": "service_name",
122
+ "integration": {
123
+ "name": "service_name",
124
+ "type": "agentr"
125
+ }
126
+ }
127
+ ```
128
+ When using OAuth integrations, users will be directed to authenticate with the service provider through a secure flow managed by AgentR.
129
+
130
+ ## 🤖 CLI Usage
131
+ AgentR includes a command-line interface for common operations:
132
+
133
+ ```bash
134
+ # Get version information
135
+ agentr version
136
+
137
+ # Generate API client from OpenAPI schema
138
+ agentr generate --schema path/to/openapi.yaml
139
+
140
+ # Run the test server
141
+ agentr run
142
+
143
+ # Install AgentR for specific applications
144
+ agentr install claude
145
+ ```
146
+
147
+ ## 📋 Requirements
148
+
149
+ - Python 3.11+
150
+ - Dependencies (automatically installed):
151
+ - loguru >= 0.7.3
152
+ - mcp >= 1.5.0
153
+ - pyyaml >= 6.0.2
154
+ - typer >= 0.15.2
155
+
156
+
@@ -0,0 +1,22 @@
1
+ agentr/__init__.py,sha256=oESTO4raGTykM5npHqhuwinRY-zxPtdmeOzXV-se_Bo,31
2
+ agentr/application.py,sha256=jDcYk8DArOJuE-HEn6_aCUtMn_ckrFpJuoAv4qzyr6c,1607
3
+ agentr/cli.py,sha256=UndJFUcJ7MCZzlhQB3W70j1oi1a-aYb1pZyKODNtdX8,2872
4
+ agentr/exceptions.py,sha256=7VusZ_ltcYK3pRcew_Kc8rSllQoxi2RvmxdntJgufqM,275
5
+ agentr/integration.py,sha256=Btd7VwKb1T94s9ZKApMDAEFv7tlK4oxHfBvIYRAmUe8,3657
6
+ agentr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ agentr/server.py,sha256=WB98K-BrSt77pp_wGTUnJa7Sjeyj_hFbbaB3hS9qnRA,4325
8
+ agentr/store.py,sha256=IlCGsYjFIzVLsBnse5cuzS4egOn7osPr3zSUt3FwPvA,1655
9
+ agentr/test.py,sha256=ijzm58aoCSJDAN-ObK2HludNMr2bbvPMURC7ah8wcu4,920
10
+ agentr/applications/github/app.py,sha256=7ZOPDq95IaYza7IhNkB4zkeZmGDRxffhtRju6asUwLg,2005
11
+ agentr/applications/google_calendar/app.py,sha256=9PFV_p0KbyuJslcaFnhDmqR6p3G7BR-3Ij5KIaPomTc,2914
12
+ agentr/applications/google_mail/app.py,sha256=Pf_u0HE1Im7J9xe77RbknfaOmnspHRrKY40CpL270zU,2401
13
+ agentr/applications/reddit/app.py,sha256=NLBPS0sAqUt5EVHeqcnAn4s6XD-KoapJjlLhSnsUgaY,871
14
+ agentr/applications/resend/app.py,sha256=FWomwUKrrOHMptXO0P1wbe40JDyBvq_CC7Hrk0qcyWE,1471
15
+ agentr/applications/tavily/app.py,sha256=WgnEqD0bROiDpliGEUSTww4vH5drRsHTBBGf8WRZacU,1862
16
+ agentr/applications/zenquotes/app.py,sha256=WRK96H8cTWXRV-Z42QnOa1qfqzs6xmYTpxj1MJooYZM,627
17
+ agentr/utils/bridge.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ agentr/utils/openapi.py,sha256=S9MyxrxAs87-WTYgzfKVWhroxIB98_nBG1Ksac0x_pU,6463
19
+ agentr-0.1.4.dist-info/METADATA,sha256=hMmkU1mQZbV2otCFm-Kirx7XS_Y4ca08NWRME5xm9y0,4173
20
+ agentr-0.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ agentr-0.1.4.dist-info/entry_points.txt,sha256=13fGFeVhgF6_8T-VFiIkNxYO7gDQaUwwTcUNWdvaLQg,42
22
+ agentr-0.1.4.dist-info/RECORD,,
agentr/mcp.py DELETED
@@ -1,9 +0,0 @@
1
- from agentr.server import TestServer
2
- from agentr.store import MemoryStore
3
-
4
- store = MemoryStore()
5
-
6
- mcp = TestServer(name="Test Server", description="Test Server", store=store)
7
-
8
- if __name__ == "__main__":
9
- mcp.run()
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: agentr
3
- Version: 0.1.2
4
- Summary: Add your description here
5
- Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
- Requires-Python: >=3.11
7
- Requires-Dist: mcp>=1.5.0
8
- Requires-Dist: pyyaml>=6.0.2
9
- Requires-Dist: typer>=0.15.2
@@ -1,13 +0,0 @@
1
- agentr/__init__.py,sha256=LOWhgQayrQV7f5ro4rlBJ_6WevhbWIbjAOHnqP7b_-4,30
2
- agentr/application.py,sha256=rQ2vomCfZKigdXQLjwCvlTC9_UcnKyux_x9evmQqnjA,1220
3
- agentr/cli.py,sha256=F16qdCnfgg9UJt7D7VBjZ2-nKvwb7dJ3zezbopNH2YQ,877
4
- agentr/mcp.py,sha256=kGraScdBgDkCvrzbyg07TTUiIVMXIOF_um7v4g4-4Cs,216
5
- agentr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- agentr/server.py,sha256=fweppEwF7L9cRow1zDPHtLYQE-qUdTlICeYUbxHGb2w,990
7
- agentr/store.py,sha256=u18GL9nDQgkkGm8HFIMz6BiHmy04EDi3vugotbH87ss,689
8
- agentr/applications/zenquotes/app.py,sha256=4LjYeWdERI8ZMzkajOsDgy9IRTA9plUKem-rW4M03sA,607
9
- agentr/utils/openapi.py,sha256=yjiPYs-_JsYQ7T3aPh7oimHUCf8pMblIR8IPCaAeNCg,6279
10
- agentr-0.1.2.dist-info/METADATA,sha256=n6pFbzT-1SjybZX5H81kEjRcpOpfo-HvOkxUMY48PbU,244
11
- agentr-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
- agentr-0.1.2.dist-info/entry_points.txt,sha256=13fGFeVhgF6_8T-VFiIkNxYO7gDQaUwwTcUNWdvaLQg,42
13
- agentr-0.1.2.dist-info/RECORD,,
File without changes