agentr 0.1.6__py3-none-any.whl → 0.1.8__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/__init__.py +1 -1
- agentr/application.py +93 -56
- agentr/applications/__init__.py +27 -0
- agentr/applications/github/app.py +319 -56
- agentr/applications/google_calendar/app.py +489 -74
- agentr/applications/google_mail/app.py +565 -68
- agentr/applications/reddit/app.py +309 -29
- agentr/applications/resend/app.py +43 -43
- agentr/applications/tavily/app.py +57 -57
- agentr/applications/zenquotes/app.py +20 -20
- agentr/cli.py +76 -75
- agentr/config.py +15 -0
- agentr/exceptions.py +6 -5
- agentr/integration.py +161 -98
- agentr/integrations/README.md +25 -0
- agentr/integrations/__init__.py +5 -0
- agentr/integrations/agentr.py +87 -0
- agentr/integrations/api_key.py +16 -0
- agentr/integrations/base.py +60 -0
- agentr/server.py +128 -105
- agentr/store.py +70 -70
- agentr/test.py +14 -37
- agentr/utils/openapi.py +273 -184
- {agentr-0.1.6.dist-info → agentr-0.1.8.dist-info}/METADATA +4 -1
- agentr-0.1.8.dist-info/RECORD +30 -0
- {agentr-0.1.6.dist-info → agentr-0.1.8.dist-info}/licenses/LICENSE +21 -21
- agentr-0.1.6.dist-info/RECORD +0 -23
- {agentr-0.1.6.dist-info → agentr-0.1.8.dist-info}/WHEEL +0 -0
- {agentr-0.1.6.dist-info → agentr-0.1.8.dist-info}/entry_points.txt +0 -0
agentr/cli.py
CHANGED
@@ -1,75 +1,76 @@
|
|
1
|
-
import typer
|
2
|
-
from pathlib import Path
|
3
|
-
import sys
|
4
|
-
|
5
|
-
app = typer.Typer()
|
6
|
-
|
7
|
-
@app.command()
|
8
|
-
def version():
|
9
|
-
"""Show the version of the CLI"""
|
10
|
-
print("agentr version 0.1.0")
|
11
|
-
|
12
|
-
@app.command()
|
13
|
-
def generate(schema_path: Path = typer.Option(..., "--schema", "-s")):
|
14
|
-
"""Generate API client from OpenAPI schema"""
|
15
|
-
if not schema_path.exists():
|
16
|
-
typer.echo(f"Error: Schema file {schema_path} does not exist", err=True)
|
17
|
-
raise typer.Exit(1)
|
18
|
-
from .utils.openapi import generate_api_client, load_schema
|
19
|
-
|
20
|
-
try:
|
21
|
-
schema = load_schema(schema_path)
|
22
|
-
except Exception as e:
|
23
|
-
typer.echo(f"Error loading schema: {e}", err=True)
|
24
|
-
raise typer.Exit(1)
|
25
|
-
code = generate_api_client(schema)
|
26
|
-
print(code)
|
27
|
-
|
28
|
-
@app.command()
|
29
|
-
def run():
|
30
|
-
"""Run the MCP server"""
|
31
|
-
from agentr.
|
32
|
-
mcp
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
typer.echo("
|
42
|
-
typer.echo("
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
"
|
64
|
-
"
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
1
|
+
import typer
|
2
|
+
from pathlib import Path
|
3
|
+
import sys
|
4
|
+
|
5
|
+
app = typer.Typer()
|
6
|
+
|
7
|
+
@app.command()
|
8
|
+
def version():
|
9
|
+
"""Show the version of the CLI"""
|
10
|
+
print("agentr version 0.1.0")
|
11
|
+
|
12
|
+
@app.command()
|
13
|
+
def generate(schema_path: Path = typer.Option(..., "--schema", "-s")):
|
14
|
+
"""Generate API client from OpenAPI schema"""
|
15
|
+
if not schema_path.exists():
|
16
|
+
typer.echo(f"Error: Schema file {schema_path} does not exist", err=True)
|
17
|
+
raise typer.Exit(1)
|
18
|
+
from .utils.openapi import generate_api_client, load_schema
|
19
|
+
|
20
|
+
try:
|
21
|
+
schema = load_schema(schema_path)
|
22
|
+
except Exception as e:
|
23
|
+
typer.echo(f"Error loading schema: {e}", err=True)
|
24
|
+
raise typer.Exit(1)
|
25
|
+
code = generate_api_client(schema)
|
26
|
+
print(code)
|
27
|
+
|
28
|
+
@app.command()
|
29
|
+
def run():
|
30
|
+
"""Run the MCP server"""
|
31
|
+
from agentr.server import AgentRServer
|
32
|
+
mcp = AgentRServer(name="AgentR Server", description="AgentR Server")
|
33
|
+
mcp.run()
|
34
|
+
|
35
|
+
@app.command()
|
36
|
+
def install(app_name: str):
|
37
|
+
"""Install an app"""
|
38
|
+
import json
|
39
|
+
|
40
|
+
# Print instructions before asking for API key
|
41
|
+
typer.echo("╭─ Instruction ─────────────────────────────────────────────────────────────────╮")
|
42
|
+
typer.echo("│ API key is required. Visit https://agentr.dev to create an API key. │")
|
43
|
+
typer.echo("╰───────────────────────────────────────────────────────────────────────────────╯")
|
44
|
+
# Prompt for API key
|
45
|
+
api_key = typer.prompt("Enter your AgentR API key", hide_input=True)
|
46
|
+
|
47
|
+
if app_name == "claude":
|
48
|
+
typer.echo(f"Installing mcp server for: {app_name}")
|
49
|
+
|
50
|
+
# Determine platform-specific config path
|
51
|
+
if sys.platform == "darwin": # macOS
|
52
|
+
config_path = Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
|
53
|
+
elif sys.platform == "win32": # Windows
|
54
|
+
config_path = Path.home() / "AppData/Roaming/Claude/claude_desktop_config.json"
|
55
|
+
else:
|
56
|
+
typer.echo("Unsupported platform. Only macOS and Windows are currently supported.", err=True)
|
57
|
+
raise typer.Exit(1)
|
58
|
+
|
59
|
+
|
60
|
+
with open(config_path, 'r') as f:
|
61
|
+
config = json.load(f)
|
62
|
+
config['mcpServers']['agentr'] = {
|
63
|
+
"command": "uvx",
|
64
|
+
"args": ["agentr@latest", "run"],
|
65
|
+
"env": {
|
66
|
+
"AGENTR_API_KEY": api_key
|
67
|
+
}
|
68
|
+
}
|
69
|
+
with open(config_path, 'w') as f:
|
70
|
+
json.dump(config, f, indent=4)
|
71
|
+
typer.echo("App installed successfully")
|
72
|
+
else:
|
73
|
+
typer.echo(f"App {app_name} not supported")
|
74
|
+
|
75
|
+
if __name__ == "__main__":
|
76
|
+
app()
|
agentr/config.py
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
from typing import Literal
|
3
|
+
|
4
|
+
class StoreConfig(BaseModel):
|
5
|
+
type: Literal["memory", "environment"]
|
6
|
+
|
7
|
+
class IntegrationConfig(BaseModel):
|
8
|
+
name: str
|
9
|
+
type: Literal["api_key", "agentr"]
|
10
|
+
credentials: dict | None = None
|
11
|
+
store: StoreConfig | None = None
|
12
|
+
|
13
|
+
class AppConfig(BaseModel):
|
14
|
+
name: str
|
15
|
+
integration: IntegrationConfig | None = None
|
agentr/exceptions.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
class NotAuthorizedError(Exception):
|
2
|
-
"""Raised when a user is not authorized to access a resource or perform an action."""
|
3
|
-
def __init__(self, message="Not authorized to perform this action"):
|
4
|
-
self.message = message
|
5
|
-
super().__init__(self.message)
|
1
|
+
class NotAuthorizedError(Exception):
|
2
|
+
"""Raised when a user is not authorized to access a resource or perform an action."""
|
3
|
+
def __init__(self, message="Not authorized to perform this action"):
|
4
|
+
self.message = message
|
5
|
+
super().__init__(self.message)
|
6
|
+
|
agentr/integration.py
CHANGED
@@ -1,98 +1,161 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import os
|
3
|
-
|
4
|
-
|
5
|
-
from
|
6
|
-
from agentr.store import Store
|
7
|
-
import httpx
|
8
|
-
|
9
|
-
"""
|
10
|
-
Integration defines how a Application needs to authorize.
|
11
|
-
It is responsible for authenticating application with the service provider.
|
12
|
-
Supported integrations:
|
13
|
-
- AgentR Integration
|
14
|
-
- API Key Integration
|
15
|
-
"""
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
def
|
71
|
-
|
72
|
-
return
|
73
|
-
|
74
|
-
def
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import os
|
3
|
+
|
4
|
+
from loguru import logger
|
5
|
+
from agentr.exceptions import NotAuthorizedError
|
6
|
+
from agentr.store import Store
|
7
|
+
import httpx
|
8
|
+
|
9
|
+
"""
|
10
|
+
Integration defines how a Application needs to authorize.
|
11
|
+
It is responsible for authenticating application with the service provider.
|
12
|
+
Supported integrations:
|
13
|
+
- AgentR Integration
|
14
|
+
- API Key Integration
|
15
|
+
"""
|
16
|
+
|
17
|
+
|
18
|
+
class Integration(ABC):
|
19
|
+
"""Abstract base class for handling application integrations and authentication.
|
20
|
+
|
21
|
+
This class defines the interface for different types of integrations that handle
|
22
|
+
authentication and authorization with external services.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
name: The name identifier for this integration
|
26
|
+
store: Optional Store instance for persisting credentials and other data
|
27
|
+
|
28
|
+
Attributes:
|
29
|
+
name: The name identifier for this integration
|
30
|
+
store: Store instance for persisting credentials and other data
|
31
|
+
"""
|
32
|
+
def __init__(self, name: str, store: Store = None):
|
33
|
+
self.name = name
|
34
|
+
self.store = store
|
35
|
+
|
36
|
+
@abstractmethod
|
37
|
+
def authorize(self):
|
38
|
+
"""Authorize the integration.
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
str: Authorization URL.
|
42
|
+
"""
|
43
|
+
pass
|
44
|
+
|
45
|
+
@abstractmethod
|
46
|
+
def get_credentials(self):
|
47
|
+
"""Get credentials for the integration.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
dict: Credentials for the integration.
|
51
|
+
|
52
|
+
Raises:
|
53
|
+
NotAuthorizedError: If credentials are not found.
|
54
|
+
"""
|
55
|
+
pass
|
56
|
+
|
57
|
+
@abstractmethod
|
58
|
+
def set_credentials(self, credentials: dict):
|
59
|
+
"""Set credentials for the integration.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
credentials: Credentials for the integration.
|
63
|
+
"""
|
64
|
+
pass
|
65
|
+
|
66
|
+
class ApiKeyIntegration(Integration):
|
67
|
+
def __init__(self, name: str, store: Store = None, **kwargs):
|
68
|
+
super().__init__(name, store, **kwargs)
|
69
|
+
|
70
|
+
def get_credentials(self):
|
71
|
+
credentials = self.store.get(self.name)
|
72
|
+
return credentials
|
73
|
+
|
74
|
+
def set_credentials(self, credentials: dict):
|
75
|
+
self.store.set(self.name, credentials)
|
76
|
+
|
77
|
+
def authorize(self):
|
78
|
+
return {"text": "Please configure the environment variable {self.name}_API_KEY"}
|
79
|
+
|
80
|
+
|
81
|
+
class AgentRIntegration(Integration):
|
82
|
+
"""Integration class for AgentR API authentication and authorization.
|
83
|
+
|
84
|
+
This class handles API key authentication and OAuth authorization flow for AgentR services.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
name (str): Name of the integration
|
88
|
+
api_key (str, optional): AgentR API key. If not provided, will look for AGENTR_API_KEY env var
|
89
|
+
**kwargs: Additional keyword arguments passed to parent Integration class
|
90
|
+
|
91
|
+
Raises:
|
92
|
+
ValueError: If no API key is provided or found in environment variables
|
93
|
+
"""
|
94
|
+
def __init__(self, name: str, api_key: str = None, **kwargs):
|
95
|
+
super().__init__(name, **kwargs)
|
96
|
+
self.api_key = api_key or os.getenv("AGENTR_API_KEY")
|
97
|
+
if not self.api_key:
|
98
|
+
logger.error("API key for AgentR is missing. Please visit https://agentr.dev to create an API key, then set it as AGENTR_API_KEY environment variable.")
|
99
|
+
raise ValueError("AgentR API key required - get one at https://agentr.dev")
|
100
|
+
self.base_url = os.getenv("AGENTR_BASE_URL", "https://api.agentr.dev")
|
101
|
+
|
102
|
+
def set_credentials(self, credentials: dict| None = None):
|
103
|
+
"""Set credentials for the integration.
|
104
|
+
|
105
|
+
This method is not implemented for AgentR integration. Instead it redirects to the authorize flow.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
credentials (dict | None, optional): Credentials dict (not used). Defaults to None.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
str: Authorization URL from authorize() method
|
112
|
+
"""
|
113
|
+
return self.authorize()
|
114
|
+
# raise NotImplementedError("AgentR Integration does not support setting credentials. Visit the authorize url to set credentials.")
|
115
|
+
|
116
|
+
def get_credentials(self):
|
117
|
+
"""Get credentials for the integration from the AgentR API.
|
118
|
+
|
119
|
+
Makes API request to retrieve stored credentials for this integration.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
dict: Credentials data from API response
|
123
|
+
|
124
|
+
Raises:
|
125
|
+
NotAuthorizedError: If credentials are not found (404 response)
|
126
|
+
HTTPError: For other API errors
|
127
|
+
"""
|
128
|
+
response = httpx.get(
|
129
|
+
f"{self.base_url}/api/{self.name}/credentials/",
|
130
|
+
headers={
|
131
|
+
"accept": "application/json",
|
132
|
+
"X-API-KEY": self.api_key
|
133
|
+
}
|
134
|
+
)
|
135
|
+
if response.status_code == 404:
|
136
|
+
action = self.authorize()
|
137
|
+
raise NotAuthorizedError(action)
|
138
|
+
response.raise_for_status()
|
139
|
+
data = response.json()
|
140
|
+
return data
|
141
|
+
|
142
|
+
def authorize(self):
|
143
|
+
"""Get authorization URL for the integration.
|
144
|
+
|
145
|
+
Makes API request to get OAuth authorization URL.
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
str: Message containing authorization URL
|
149
|
+
|
150
|
+
Raises:
|
151
|
+
HTTPError: If API request fails
|
152
|
+
"""
|
153
|
+
response = httpx.get(
|
154
|
+
f"{self.base_url}/api/{self.name}/authorize/",
|
155
|
+
headers={
|
156
|
+
"X-API-KEY": self.api_key
|
157
|
+
}
|
158
|
+
)
|
159
|
+
response.raise_for_status()
|
160
|
+
url = response.json()
|
161
|
+
return f"Please authorize the application by clicking the link {url}"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Integrations
|
2
|
+
|
3
|
+
This package provides integration classes for handling authentication and authorization with external services.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
An Integration defines how an application authenticates and authorizes with a service provider. The base `Integration` class provides an interface that all integrations must implement.
|
8
|
+
|
9
|
+
## Supported Integrations
|
10
|
+
|
11
|
+
### AgentR Integration
|
12
|
+
The `AgentRIntegration` class handles OAuth-based authentication flow with the AgentR API. It requires an API key which can be obtained from [agentr.dev](https://agentr.dev).
|
13
|
+
|
14
|
+
### API Key Integration
|
15
|
+
The `ApiKeyIntegration` class provides a simple API key based authentication mechanism. API keys are configured via environment variables.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Each integration implements three key methods:
|
20
|
+
|
21
|
+
- `authorize()` - Initiates the authorization flow
|
22
|
+
- `get_credentials()` - Retrieves stored credentials
|
23
|
+
- `set_credentials()` - Stores new credentials
|
24
|
+
|
25
|
+
See the individual integration classes for specific usage details.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from agentr.integrations.base import Integration
|
2
|
+
import os
|
3
|
+
import httpx
|
4
|
+
from loguru import logger
|
5
|
+
from agentr.exceptions import NotAuthorizedError
|
6
|
+
|
7
|
+
class AgentRIntegration(Integration):
|
8
|
+
"""Integration class for AgentR API authentication and authorization.
|
9
|
+
|
10
|
+
This class handles API key authentication and OAuth authorization flow for AgentR services.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
name (str): Name of the integration
|
14
|
+
api_key (str, optional): AgentR API key. If not provided, will look for AGENTR_API_KEY env var
|
15
|
+
**kwargs: Additional keyword arguments passed to parent Integration class
|
16
|
+
|
17
|
+
Raises:
|
18
|
+
ValueError: If no API key is provided or found in environment variables
|
19
|
+
"""
|
20
|
+
def __init__(self, name: str, api_key: str = None, **kwargs):
|
21
|
+
super().__init__(name, **kwargs)
|
22
|
+
self.api_key = api_key or os.getenv("AGENTR_API_KEY")
|
23
|
+
if not self.api_key:
|
24
|
+
logger.error("API key for AgentR is missing. Please visit https://agentr.dev to create an API key, then set it as AGENTR_API_KEY environment variable.")
|
25
|
+
raise ValueError("AgentR API key required - get one at https://agentr.dev")
|
26
|
+
self.base_url = os.getenv("AGENTR_BASE_URL", "https://api.agentr.dev")
|
27
|
+
|
28
|
+
def set_credentials(self, credentials: dict| None = None):
|
29
|
+
"""Set credentials for the integration.
|
30
|
+
|
31
|
+
This method is not implemented for AgentR integration. Instead it redirects to the authorize flow.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
credentials (dict | None, optional): Credentials dict (not used). Defaults to None.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
str: Authorization URL from authorize() method
|
38
|
+
"""
|
39
|
+
return self.authorize()
|
40
|
+
# raise NotImplementedError("AgentR Integration does not support setting credentials. Visit the authorize url to set credentials.")
|
41
|
+
|
42
|
+
def get_credentials(self):
|
43
|
+
"""Get credentials for the integration from the AgentR API.
|
44
|
+
|
45
|
+
Makes API request to retrieve stored credentials for this integration.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
dict: Credentials data from API response
|
49
|
+
|
50
|
+
Raises:
|
51
|
+
NotAuthorizedError: If credentials are not found (404 response)
|
52
|
+
HTTPError: For other API errors
|
53
|
+
"""
|
54
|
+
response = httpx.get(
|
55
|
+
f"{self.base_url}/api/{self.name}/credentials/",
|
56
|
+
headers={
|
57
|
+
"accept": "application/json",
|
58
|
+
"X-API-KEY": self.api_key
|
59
|
+
}
|
60
|
+
)
|
61
|
+
if response.status_code == 404:
|
62
|
+
action = self.authorize()
|
63
|
+
raise NotAuthorizedError(action)
|
64
|
+
response.raise_for_status()
|
65
|
+
data = response.json()
|
66
|
+
return data
|
67
|
+
|
68
|
+
def authorize(self):
|
69
|
+
"""Get authorization URL for the integration.
|
70
|
+
|
71
|
+
Makes API request to get OAuth authorization URL.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
str: Message containing authorization URL
|
75
|
+
|
76
|
+
Raises:
|
77
|
+
HTTPError: If API request fails
|
78
|
+
"""
|
79
|
+
response = httpx.get(
|
80
|
+
f"{self.base_url}/api/{self.name}/authorize/",
|
81
|
+
headers={
|
82
|
+
"X-API-KEY": self.api_key
|
83
|
+
}
|
84
|
+
)
|
85
|
+
response.raise_for_status()
|
86
|
+
url = response.json()
|
87
|
+
return f"Please authorize the application by clicking the link {url}"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from agentr.integrations.base import Integration
|
2
|
+
from agentr.store import Store
|
3
|
+
|
4
|
+
class ApiKeyIntegration(Integration):
|
5
|
+
def __init__(self, name: str, store: Store = None, **kwargs):
|
6
|
+
super().__init__(name, store, **kwargs)
|
7
|
+
|
8
|
+
def get_credentials(self):
|
9
|
+
credentials = self.store.get(self.name)
|
10
|
+
return credentials
|
11
|
+
|
12
|
+
def set_credentials(self, credentials: dict):
|
13
|
+
self.store.set(self.name, credentials)
|
14
|
+
|
15
|
+
def authorize(self):
|
16
|
+
return {"text": "Please configure the environment variable {self.name}_API_KEY"}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import os
|
3
|
+
|
4
|
+
from loguru import logger
|
5
|
+
from agentr.exceptions import NotAuthorizedError
|
6
|
+
from agentr.store import Store
|
7
|
+
import httpx
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
class Integration(ABC):
|
13
|
+
"""Abstract base class for handling application integrations and authentication.
|
14
|
+
|
15
|
+
This class defines the interface for different types of integrations that handle
|
16
|
+
authentication and authorization with external services.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
name: The name identifier for this integration
|
20
|
+
store: Optional Store instance for persisting credentials and other data
|
21
|
+
|
22
|
+
Attributes:
|
23
|
+
name: The name identifier for this integration
|
24
|
+
store: Store instance for persisting credentials and other data
|
25
|
+
"""
|
26
|
+
def __init__(self, name: str, store: Store = None):
|
27
|
+
self.name = name
|
28
|
+
self.store = store
|
29
|
+
|
30
|
+
@abstractmethod
|
31
|
+
def authorize(self):
|
32
|
+
"""Authorize the integration.
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
str: Authorization URL.
|
36
|
+
"""
|
37
|
+
pass
|
38
|
+
|
39
|
+
@abstractmethod
|
40
|
+
def get_credentials(self):
|
41
|
+
"""Get credentials for the integration.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
dict: Credentials for the integration.
|
45
|
+
|
46
|
+
Raises:
|
47
|
+
NotAuthorizedError: If credentials are not found.
|
48
|
+
"""
|
49
|
+
pass
|
50
|
+
|
51
|
+
@abstractmethod
|
52
|
+
def set_credentials(self, credentials: dict):
|
53
|
+
"""Set credentials for the integration.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
credentials: Credentials for the integration.
|
57
|
+
"""
|
58
|
+
pass
|
59
|
+
|
60
|
+
|