agentauthlayer 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- agentauthlayer-0.1.2/PKG-INFO +194 -0
- agentauthlayer-0.1.2/README.md +174 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/__init__.py +12 -0
- agentauthlayer-0.1.2/agent_auth/__main__.py +5 -0
- agentauthlayer-0.1.2/agent_auth/cli.py +142 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/client.py +10 -2
- agentauthlayer-0.1.2/agent_auth/credentials.py +31 -0
- agentauthlayer-0.1.2/agent_auth/registry.py +61 -0
- agentauthlayer-0.1.2/agentauthlayer.egg-info/PKG-INFO +194 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agentauthlayer.egg-info/SOURCES.txt +2 -0
- agentauthlayer-0.1.2/agentauthlayer.egg-info/entry_points.txt +2 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/pyproject.toml +5 -3
- agentauthlayer-0.1.0/PKG-INFO +0 -131
- agentauthlayer-0.1.0/README.md +0 -110
- agentauthlayer-0.1.0/agent_auth/__main__.py +0 -4
- agentauthlayer-0.1.0/agent_auth/cli.py +0 -28
- agentauthlayer-0.1.0/agent_auth/registry.py +0 -90
- agentauthlayer-0.1.0/agentauthlayer.egg-info/PKG-INFO +0 -131
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/agents.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/audit.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/auth.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/context.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/core.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/delegation.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/exceptions.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/models.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/policy.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/policy_service.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/principals.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/session.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/storage.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/tokens.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agent_auth/users.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agentauthlayer.egg-info/dependency_links.txt +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agentauthlayer.egg-info/requires.txt +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/agentauthlayer.egg-info/top_level.txt +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/setup.cfg +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_agent_auth_library.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_auth_flow.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_core_first_boundary.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_health.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_iam_policy.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_project_flow.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_sqlite_repos.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_storage.py +0 -0
- {agentauthlayer-0.1.0 → agentauthlayer-0.1.2}/tests/test_tool_registry.py +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentauthlayer
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Library-first authentication and authorization SDK for AI agents
|
|
5
|
+
Author: Vaibhav Ahluwalia
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://pypi.org/project/agentauthlayer/
|
|
8
|
+
Keywords: agents,auth,authorization,iam,security,sdk
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests>=2.31.0
|
|
19
|
+
Requires-Dist: python-jose>=3.3.0
|
|
20
|
+
|
|
21
|
+
# agentauthlayer
|
|
22
|
+
|
|
23
|
+
Python SDK for integrating agent runtimes with the Agent Auth control plane.
|
|
24
|
+
|
|
25
|
+
`agentauthlayer` helps you:
|
|
26
|
+
- authenticate once and reuse local credentials
|
|
27
|
+
- register agents from code
|
|
28
|
+
- sync tool and capability definitions
|
|
29
|
+
- evaluate permissions against the control plane
|
|
30
|
+
- apply permission checks inside runtime functions
|
|
31
|
+
|
|
32
|
+
This package is the reusable SDK layer. It is intended for developers integrating Python agents, tools, and workflows with an Agent Auth deployment.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install agentauthlayer
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quickstart
|
|
41
|
+
|
|
42
|
+
### 1. Log in once
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
agentauth login --base-url http://127.0.0.1:8002
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This stores local credentials so your code can connect without manually pasting a token every time.
|
|
49
|
+
|
|
50
|
+
Useful follow-up commands:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
agentauth whoami
|
|
54
|
+
agentauth logout
|
|
55
|
+
agentauth ui
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Define tools and agents in code
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from agent_auth import register_tool, register_agent, require_permission
|
|
62
|
+
|
|
63
|
+
@register_tool(action="math.compute", description="Run approved math jobs")
|
|
64
|
+
@require_permission("math.compute", resource="math/basic")
|
|
65
|
+
def add(a: int, b: int, agent_id: str | None = None, role: str | None = None, context: dict | None = None):
|
|
66
|
+
return a + b
|
|
67
|
+
|
|
68
|
+
register_agent(
|
|
69
|
+
agent_id="math-agent",
|
|
70
|
+
name="Math Agent",
|
|
71
|
+
owner="you@company.com",
|
|
72
|
+
role="research_agent",
|
|
73
|
+
project_id="ai-platform",
|
|
74
|
+
scopes=[],
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Sync everything with one command
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
agentauth sync --module your_module_name
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This imports the module, discovers registered tools and agents, syncs capability definitions, and creates agents through the control plane.
|
|
85
|
+
|
|
86
|
+
## SDK client usage
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from agent_auth import AuthAPIClient
|
|
90
|
+
|
|
91
|
+
client = AuthAPIClient()
|
|
92
|
+
|
|
93
|
+
agent = client.create_agent(
|
|
94
|
+
agent_id="research-bot-01",
|
|
95
|
+
name="Research Bot 01",
|
|
96
|
+
owner="vaibhav@company.com",
|
|
97
|
+
role="research_agent",
|
|
98
|
+
scopes=[],
|
|
99
|
+
project_id="ai-platform",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
print(agent)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Environment variables
|
|
106
|
+
|
|
107
|
+
If you prefer non-interactive configuration, the SDK also supports environment variables:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
export AGENT_AUTH_URL=http://127.0.0.1:8002
|
|
111
|
+
export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Resolution order used by `AuthAPIClient()`:
|
|
115
|
+
1. explicit constructor arguments
|
|
116
|
+
2. environment variables
|
|
117
|
+
3. stored local credentials from `agentauth login`
|
|
118
|
+
|
|
119
|
+
## Common tasks
|
|
120
|
+
|
|
121
|
+
### Sync tools manually
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
client.sync_tools([
|
|
125
|
+
{"action": "tool.search_web", "description": "Search the web"},
|
|
126
|
+
{"action": "docs.read", "description": "Read protected docs"},
|
|
127
|
+
])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Evaluate access
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
decision = client.evaluate(
|
|
134
|
+
principal_id="research-bot-01",
|
|
135
|
+
action="tool.search_web",
|
|
136
|
+
resource="web/*",
|
|
137
|
+
role="research_agent",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
print(decision)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Fetch or delete an agent
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
agent = client.get_agent("research-bot-01")
|
|
147
|
+
print(agent)
|
|
148
|
+
|
|
149
|
+
result = client.delete_agent("research-bot-01")
|
|
150
|
+
print(result)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
CLI equivalent:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
agentauth delete-agent research-bot-01
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Public package scope
|
|
160
|
+
|
|
161
|
+
This package provides:
|
|
162
|
+
- the Python SDK (`agent_auth`)
|
|
163
|
+
- CLI helpers for login, sync, and agent cleanup
|
|
164
|
+
- registry-based tool and agent sync
|
|
165
|
+
- permission evaluation helpers
|
|
166
|
+
|
|
167
|
+
It does not package the full control plane server or admin dashboard.
|
|
168
|
+
|
|
169
|
+
## Suitable use cases
|
|
170
|
+
|
|
171
|
+
- Python agent runtimes
|
|
172
|
+
- tool-based workflows
|
|
173
|
+
- service-to-control-plane integrations
|
|
174
|
+
- local development with stored credentials
|
|
175
|
+
- CI or automation using environment variables
|
|
176
|
+
|
|
177
|
+
## Requirements
|
|
178
|
+
|
|
179
|
+
- Python 3.10+
|
|
180
|
+
- access to a running Agent Auth control plane
|
|
181
|
+
|
|
182
|
+
## Notes
|
|
183
|
+
|
|
184
|
+
The import path remains:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from agent_auth import ...
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
while the published package name is:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
pip install agentauthlayer
|
|
194
|
+
```
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# agentauthlayer
|
|
2
|
+
|
|
3
|
+
Python SDK for integrating agent runtimes with the Agent Auth control plane.
|
|
4
|
+
|
|
5
|
+
`agentauthlayer` helps you:
|
|
6
|
+
- authenticate once and reuse local credentials
|
|
7
|
+
- register agents from code
|
|
8
|
+
- sync tool and capability definitions
|
|
9
|
+
- evaluate permissions against the control plane
|
|
10
|
+
- apply permission checks inside runtime functions
|
|
11
|
+
|
|
12
|
+
This package is the reusable SDK layer. It is intended for developers integrating Python agents, tools, and workflows with an Agent Auth deployment.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install agentauthlayer
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
### 1. Log in once
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
agentauth login --base-url http://127.0.0.1:8002
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This stores local credentials so your code can connect without manually pasting a token every time.
|
|
29
|
+
|
|
30
|
+
Useful follow-up commands:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
agentauth whoami
|
|
34
|
+
agentauth logout
|
|
35
|
+
agentauth ui
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Define tools and agents in code
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from agent_auth import register_tool, register_agent, require_permission
|
|
42
|
+
|
|
43
|
+
@register_tool(action="math.compute", description="Run approved math jobs")
|
|
44
|
+
@require_permission("math.compute", resource="math/basic")
|
|
45
|
+
def add(a: int, b: int, agent_id: str | None = None, role: str | None = None, context: dict | None = None):
|
|
46
|
+
return a + b
|
|
47
|
+
|
|
48
|
+
register_agent(
|
|
49
|
+
agent_id="math-agent",
|
|
50
|
+
name="Math Agent",
|
|
51
|
+
owner="you@company.com",
|
|
52
|
+
role="research_agent",
|
|
53
|
+
project_id="ai-platform",
|
|
54
|
+
scopes=[],
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Sync everything with one command
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
agentauth sync --module your_module_name
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This imports the module, discovers registered tools and agents, syncs capability definitions, and creates agents through the control plane.
|
|
65
|
+
|
|
66
|
+
## SDK client usage
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from agent_auth import AuthAPIClient
|
|
70
|
+
|
|
71
|
+
client = AuthAPIClient()
|
|
72
|
+
|
|
73
|
+
agent = client.create_agent(
|
|
74
|
+
agent_id="research-bot-01",
|
|
75
|
+
name="Research Bot 01",
|
|
76
|
+
owner="vaibhav@company.com",
|
|
77
|
+
role="research_agent",
|
|
78
|
+
scopes=[],
|
|
79
|
+
project_id="ai-platform",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
print(agent)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Environment variables
|
|
86
|
+
|
|
87
|
+
If you prefer non-interactive configuration, the SDK also supports environment variables:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
export AGENT_AUTH_URL=http://127.0.0.1:8002
|
|
91
|
+
export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Resolution order used by `AuthAPIClient()`:
|
|
95
|
+
1. explicit constructor arguments
|
|
96
|
+
2. environment variables
|
|
97
|
+
3. stored local credentials from `agentauth login`
|
|
98
|
+
|
|
99
|
+
## Common tasks
|
|
100
|
+
|
|
101
|
+
### Sync tools manually
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
client.sync_tools([
|
|
105
|
+
{"action": "tool.search_web", "description": "Search the web"},
|
|
106
|
+
{"action": "docs.read", "description": "Read protected docs"},
|
|
107
|
+
])
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Evaluate access
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
decision = client.evaluate(
|
|
114
|
+
principal_id="research-bot-01",
|
|
115
|
+
action="tool.search_web",
|
|
116
|
+
resource="web/*",
|
|
117
|
+
role="research_agent",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
print(decision)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Fetch or delete an agent
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
agent = client.get_agent("research-bot-01")
|
|
127
|
+
print(agent)
|
|
128
|
+
|
|
129
|
+
result = client.delete_agent("research-bot-01")
|
|
130
|
+
print(result)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
CLI equivalent:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
agentauth delete-agent research-bot-01
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Public package scope
|
|
140
|
+
|
|
141
|
+
This package provides:
|
|
142
|
+
- the Python SDK (`agent_auth`)
|
|
143
|
+
- CLI helpers for login, sync, and agent cleanup
|
|
144
|
+
- registry-based tool and agent sync
|
|
145
|
+
- permission evaluation helpers
|
|
146
|
+
|
|
147
|
+
It does not package the full control plane server or admin dashboard.
|
|
148
|
+
|
|
149
|
+
## Suitable use cases
|
|
150
|
+
|
|
151
|
+
- Python agent runtimes
|
|
152
|
+
- tool-based workflows
|
|
153
|
+
- service-to-control-plane integrations
|
|
154
|
+
- local development with stored credentials
|
|
155
|
+
- CI or automation using environment variables
|
|
156
|
+
|
|
157
|
+
## Requirements
|
|
158
|
+
|
|
159
|
+
- Python 3.10+
|
|
160
|
+
- access to a running Agent Auth control plane
|
|
161
|
+
|
|
162
|
+
## Notes
|
|
163
|
+
|
|
164
|
+
The import path remains:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from agent_auth import ...
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
while the published package name is:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
pip install agentauthlayer
|
|
174
|
+
```
|
|
@@ -15,6 +15,13 @@ from agent_auth.exceptions import (
|
|
|
15
15
|
from agent_auth.models import Agent, TokenClaims, TokenRecord, User, UserClaims
|
|
16
16
|
from agent_auth.policy import PolicyDecision, PolicyEvaluator, PolicyRequest, PolicyStatement, RoleDefinition, require_permission
|
|
17
17
|
from agent_auth.principals import AgentPrincipal, Principal, SystemPrincipal, UserPrincipal, user_scopes_for_role
|
|
18
|
+
from agent_auth.registry import (
|
|
19
|
+
clear_registries,
|
|
20
|
+
list_registered_agents,
|
|
21
|
+
list_registered_tools,
|
|
22
|
+
register_agent,
|
|
23
|
+
register_tool,
|
|
24
|
+
)
|
|
18
25
|
|
|
19
26
|
__all__ = [
|
|
20
27
|
"Agent",
|
|
@@ -40,9 +47,14 @@ __all__ = [
|
|
|
40
47
|
"User",
|
|
41
48
|
"UserClaims",
|
|
42
49
|
"UserPrincipal",
|
|
50
|
+
"clear_registries",
|
|
51
|
+
"list_registered_agents",
|
|
52
|
+
"list_registered_tools",
|
|
43
53
|
"principal_fields",
|
|
44
54
|
"principal_from_agent",
|
|
45
55
|
"principal_from_user",
|
|
56
|
+
"register_agent",
|
|
57
|
+
"register_tool",
|
|
46
58
|
"require_permission",
|
|
47
59
|
"user_scopes_for_role",
|
|
48
60
|
]
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import getpass
|
|
5
|
+
import importlib
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
import webbrowser
|
|
9
|
+
|
|
10
|
+
import requests
|
|
11
|
+
|
|
12
|
+
from agent_auth.client import AuthAPIClient
|
|
13
|
+
from agent_auth.credentials import clear_credentials, load_credentials, save_credentials
|
|
14
|
+
from agent_auth.registry import clear_registries, list_registered_agents, list_registered_tools
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def login_command(args) -> int:
|
|
18
|
+
email = args.email or input('Email: ').strip()
|
|
19
|
+
password = args.password or getpass.getpass('Password: ')
|
|
20
|
+
base_url = (args.base_url or 'http://127.0.0.1:8002').rstrip('/')
|
|
21
|
+
|
|
22
|
+
response = requests.post(
|
|
23
|
+
f"{base_url}/users/login",
|
|
24
|
+
json={"email": email, "password": password},
|
|
25
|
+
timeout=30,
|
|
26
|
+
)
|
|
27
|
+
if not response.ok:
|
|
28
|
+
print(response.text, file=sys.stderr)
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
payload = response.json()
|
|
32
|
+
save_credentials({
|
|
33
|
+
'base_url': base_url,
|
|
34
|
+
'token': payload['access_token'],
|
|
35
|
+
'email': payload['user']['email'],
|
|
36
|
+
})
|
|
37
|
+
print(f"Logged in to {base_url} as {payload['user']['email']}")
|
|
38
|
+
return 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def whoami_command(args) -> int:
|
|
42
|
+
creds = load_credentials()
|
|
43
|
+
if not creds:
|
|
44
|
+
print('Not logged in.')
|
|
45
|
+
return 1
|
|
46
|
+
client = AuthAPIClient()
|
|
47
|
+
me = client.me()
|
|
48
|
+
print(json.dumps(me, indent=2))
|
|
49
|
+
return 0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def logout_command(args) -> int:
|
|
53
|
+
clear_credentials()
|
|
54
|
+
print('Logged out.')
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def sync_command(args) -> int:
|
|
59
|
+
clear_registries()
|
|
60
|
+
importlib.import_module(args.module)
|
|
61
|
+
|
|
62
|
+
client = AuthAPIClient()
|
|
63
|
+
tools = list_registered_tools()
|
|
64
|
+
agents = list_registered_agents()
|
|
65
|
+
|
|
66
|
+
if tools:
|
|
67
|
+
client.sync_tools([
|
|
68
|
+
{'action': tool.action, 'description': tool.description}
|
|
69
|
+
for tool in tools
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
created_agents = []
|
|
73
|
+
for agent in agents:
|
|
74
|
+
created_agents.append(client.create_agent(
|
|
75
|
+
agent_id=agent.agent_id,
|
|
76
|
+
name=agent.name,
|
|
77
|
+
owner=agent.owner,
|
|
78
|
+
role=agent.role,
|
|
79
|
+
scopes=agent.scopes,
|
|
80
|
+
project_id=agent.project_id,
|
|
81
|
+
))
|
|
82
|
+
|
|
83
|
+
print(json.dumps({
|
|
84
|
+
'module': args.module,
|
|
85
|
+
'synced_tools': [tool.action for tool in tools],
|
|
86
|
+
'synced_agents': [agent['agent_id'] for agent in created_agents],
|
|
87
|
+
}, indent=2))
|
|
88
|
+
return 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def delete_agent_command(args) -> int:
|
|
92
|
+
client = AuthAPIClient()
|
|
93
|
+
result = client.delete_agent(args.agent_id)
|
|
94
|
+
print(json.dumps(result, indent=2))
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def ui_command(args) -> int:
|
|
99
|
+
creds = load_credentials() or {}
|
|
100
|
+
base_url = (args.base_url or creds.get('base_url') or 'http://127.0.0.1:8002').rstrip('/')
|
|
101
|
+
webbrowser.open(base_url)
|
|
102
|
+
print(f'Opened UI: {base_url}')
|
|
103
|
+
return 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main():
|
|
107
|
+
parser = argparse.ArgumentParser(prog='agentauth', description='Agent Auth SDK CLI')
|
|
108
|
+
subparsers = parser.add_subparsers(dest='command')
|
|
109
|
+
|
|
110
|
+
login_parser = subparsers.add_parser('login', help='Log in and store local credentials')
|
|
111
|
+
login_parser.add_argument('--base-url', default='http://127.0.0.1:8002')
|
|
112
|
+
login_parser.add_argument('--email')
|
|
113
|
+
login_parser.add_argument('--password')
|
|
114
|
+
login_parser.set_defaults(func=login_command)
|
|
115
|
+
|
|
116
|
+
whoami_parser = subparsers.add_parser('whoami', help='Show the currently stored user context')
|
|
117
|
+
whoami_parser.set_defaults(func=whoami_command)
|
|
118
|
+
|
|
119
|
+
logout_parser = subparsers.add_parser('logout', help='Clear stored local credentials')
|
|
120
|
+
logout_parser.set_defaults(func=logout_command)
|
|
121
|
+
|
|
122
|
+
sync_parser = subparsers.add_parser('sync', help='Import a module and sync its registered tools and agents')
|
|
123
|
+
sync_parser.add_argument('--module', required=True)
|
|
124
|
+
sync_parser.set_defaults(func=sync_command)
|
|
125
|
+
|
|
126
|
+
delete_agent_parser = subparsers.add_parser('delete-agent', help='Delete an agent by ID')
|
|
127
|
+
delete_agent_parser.add_argument('agent_id')
|
|
128
|
+
delete_agent_parser.set_defaults(func=delete_agent_command)
|
|
129
|
+
|
|
130
|
+
ui_parser = subparsers.add_parser('ui', help='Open the configured control plane UI in a browser')
|
|
131
|
+
ui_parser.add_argument('--base-url')
|
|
132
|
+
ui_parser.set_defaults(func=ui_command)
|
|
133
|
+
|
|
134
|
+
args = parser.parse_args()
|
|
135
|
+
if not hasattr(args, 'func'):
|
|
136
|
+
parser.print_help()
|
|
137
|
+
return 1
|
|
138
|
+
return args.func(args)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == '__main__':
|
|
142
|
+
raise SystemExit(main())
|
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
|
6
6
|
import requests
|
|
7
7
|
|
|
8
8
|
from agent_auth.context import AuthContext
|
|
9
|
+
from agent_auth.credentials import load_credentials
|
|
9
10
|
from agent_auth.exceptions import (
|
|
10
11
|
AgentNotFoundError,
|
|
11
12
|
AuthServiceError,
|
|
@@ -19,8 +20,9 @@ class AuthAPIClient:
|
|
|
19
20
|
"""Thin SDK client for talking to the Agent Auth control plane."""
|
|
20
21
|
|
|
21
22
|
def __init__(self, base_url: str | None = None, token: str | None = None, timeout: int = 30) -> None:
|
|
22
|
-
|
|
23
|
-
self.
|
|
23
|
+
stored = load_credentials() or {}
|
|
24
|
+
self.base_url = (base_url or os.getenv("AGENT_AUTH_URL") or stored.get("base_url") or "http://127.0.0.1:8002").rstrip("/")
|
|
25
|
+
self.token = token or os.getenv("AGENT_AUTH_TOKEN") or stored.get("token")
|
|
24
26
|
self.timeout = timeout
|
|
25
27
|
|
|
26
28
|
def _headers(self) -> dict[str, str]:
|
|
@@ -62,6 +64,9 @@ class AuthAPIClient:
|
|
|
62
64
|
def health(self) -> dict[str, Any]:
|
|
63
65
|
return self._request("GET", "/health")
|
|
64
66
|
|
|
67
|
+
def me(self) -> dict[str, Any]:
|
|
68
|
+
return self._request("GET", "/users/me")
|
|
69
|
+
|
|
65
70
|
def create_agent(self, agent_id: str, name: str, owner: str, role: str, scopes: list[str], project_id: str | None = None) -> dict[str, Any]:
|
|
66
71
|
payload = {
|
|
67
72
|
"agent_id": agent_id,
|
|
@@ -74,6 +79,9 @@ class AuthAPIClient:
|
|
|
74
79
|
payload["project_id"] = project_id
|
|
75
80
|
return self._request("POST", "/agents", json=payload)
|
|
76
81
|
|
|
82
|
+
def delete_agent(self, agent_id: str) -> dict[str, Any]:
|
|
83
|
+
return self._request("DELETE", f"/agents/{agent_id}")
|
|
84
|
+
|
|
77
85
|
def get_agent(self, agent_id: str) -> dict[str, Any]:
|
|
78
86
|
return self._request("GET", f"/agents/{agent_id}")
|
|
79
87
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
CONFIG_DIR = Path.home() / '.agentauth'
|
|
8
|
+
CREDENTIALS_FILE = CONFIG_DIR / 'credentials.json'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def credentials_path() -> Path:
|
|
12
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
13
|
+
return CREDENTIALS_FILE
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_credentials() -> dict[str, Any] | None:
|
|
17
|
+
path = credentials_path()
|
|
18
|
+
if not path.exists():
|
|
19
|
+
return None
|
|
20
|
+
return json.loads(path.read_text())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def save_credentials(data: dict[str, Any]) -> None:
|
|
24
|
+
path = credentials_path()
|
|
25
|
+
path.write_text(json.dumps(data, indent=2))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def clear_credentials() -> None:
|
|
29
|
+
path = credentials_path()
|
|
30
|
+
if path.exists():
|
|
31
|
+
path.unlink()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Callable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class RegisteredTool:
|
|
9
|
+
action: str
|
|
10
|
+
description: str
|
|
11
|
+
func_name: str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(slots=True)
|
|
15
|
+
class RegisteredAgent:
|
|
16
|
+
agent_id: str
|
|
17
|
+
name: str
|
|
18
|
+
owner: str
|
|
19
|
+
role: str
|
|
20
|
+
project_id: str | None
|
|
21
|
+
scopes: list[str]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_TOOL_REGISTRY: list[RegisteredTool] = []
|
|
25
|
+
_AGENT_REGISTRY: list[RegisteredAgent] = []
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register_tool(action: str, description: str):
|
|
29
|
+
def decorator(func: Callable[..., Any]):
|
|
30
|
+
setattr(func, "_agentauth_tool_action", action)
|
|
31
|
+
setattr(func, "_agentauth_tool_description", description)
|
|
32
|
+
_TOOL_REGISTRY.append(RegisteredTool(action=action, description=description, func_name=func.__name__))
|
|
33
|
+
return func
|
|
34
|
+
|
|
35
|
+
return decorator
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def register_agent(*, agent_id: str, name: str, owner: str, role: str, project_id: str | None = None, scopes: list[str] | None = None):
|
|
39
|
+
agent = RegisteredAgent(
|
|
40
|
+
agent_id=agent_id,
|
|
41
|
+
name=name,
|
|
42
|
+
owner=owner,
|
|
43
|
+
role=role,
|
|
44
|
+
project_id=project_id,
|
|
45
|
+
scopes=scopes or [],
|
|
46
|
+
)
|
|
47
|
+
_AGENT_REGISTRY.append(agent)
|
|
48
|
+
return agent
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def list_registered_tools() -> list[RegisteredTool]:
|
|
52
|
+
return list(_TOOL_REGISTRY)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def list_registered_agents() -> list[RegisteredAgent]:
|
|
56
|
+
return list(_AGENT_REGISTRY)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def clear_registries() -> None:
|
|
60
|
+
_TOOL_REGISTRY.clear()
|
|
61
|
+
_AGENT_REGISTRY.clear()
|