agenttier 0.1.1__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.
- agenttier-0.1.1/.gitignore +78 -0
- agenttier-0.1.1/PKG-INFO +137 -0
- agenttier-0.1.1/README.md +102 -0
- agenttier-0.1.1/examples/basic_usage.py +39 -0
- agenttier-0.1.1/pyproject.toml +68 -0
- agenttier-0.1.1/src/agenttier/__init__.py +83 -0
- agenttier-0.1.1/src/agenttier/_http.py +74 -0
- agenttier-0.1.1/src/agenttier/_version.py +11 -0
- agenttier-0.1.1/src/agenttier/async_client.py +141 -0
- agenttier-0.1.1/src/agenttier/async_sandbox.py +110 -0
- agenttier-0.1.1/src/agenttier/auth.py +105 -0
- agenttier-0.1.1/src/agenttier/client.py +175 -0
- agenttier-0.1.1/src/agenttier/exceptions.py +61 -0
- agenttier-0.1.1/src/agenttier/models.py +136 -0
- agenttier-0.1.1/src/agenttier/py.typed +0 -0
- agenttier-0.1.1/src/agenttier/sandbox.py +150 -0
- agenttier-0.1.1/tests/__init__.py +0 -0
- agenttier-0.1.1/tests/test_async_client.py +92 -0
- agenttier-0.1.1/tests/test_auth.py +81 -0
- agenttier-0.1.1/tests/test_client.py +290 -0
- agenttier-0.1.1/tests/test_imports.py +41 -0
- agenttier-0.1.1/tests/test_models.py +69 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Go
|
|
2
|
+
bin/
|
|
3
|
+
_output/
|
|
4
|
+
vendor/
|
|
5
|
+
*.exe
|
|
6
|
+
*.exe~
|
|
7
|
+
*.dll
|
|
8
|
+
*.so
|
|
9
|
+
*.dylib
|
|
10
|
+
*.test
|
|
11
|
+
*.out
|
|
12
|
+
coverage.out
|
|
13
|
+
coverage.html
|
|
14
|
+
|
|
15
|
+
# Compiled binaries
|
|
16
|
+
/controller
|
|
17
|
+
/router
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
*~
|
|
25
|
+
.DS_Store
|
|
26
|
+
|
|
27
|
+
# Kiro (internal development tooling)
|
|
28
|
+
.kiro/
|
|
29
|
+
|
|
30
|
+
# Local working todo (not shipped)
|
|
31
|
+
/todo.md
|
|
32
|
+
|
|
33
|
+
# Node.js (web-ui)
|
|
34
|
+
web-ui/node_modules/
|
|
35
|
+
web-ui/dist/
|
|
36
|
+
web-ui/.env.local
|
|
37
|
+
web-ui/.env.*.local
|
|
38
|
+
|
|
39
|
+
# Python (SDK)
|
|
40
|
+
python-sdk/**/__pycache__/
|
|
41
|
+
python-sdk/*.egg-info/
|
|
42
|
+
python-sdk/dist/
|
|
43
|
+
python-sdk/build/
|
|
44
|
+
python-sdk/.venv/
|
|
45
|
+
python-sdk/.env
|
|
46
|
+
python-sdk/.pytest_cache/
|
|
47
|
+
python-sdk/.mypy_cache/
|
|
48
|
+
python-sdk/.ruff_cache/
|
|
49
|
+
|
|
50
|
+
# Environment
|
|
51
|
+
.env
|
|
52
|
+
.env.local
|
|
53
|
+
*.log
|
|
54
|
+
|
|
55
|
+
# Kubernetes
|
|
56
|
+
kubeconfig
|
|
57
|
+
*.kubeconfig
|
|
58
|
+
|
|
59
|
+
# Terraform
|
|
60
|
+
terraform/**/.terraform/
|
|
61
|
+
terraform/**/*.tfstate
|
|
62
|
+
terraform/**/*.tfstate.backup
|
|
63
|
+
terraform/**/*.tfvars
|
|
64
|
+
!terraform/**/*.tfvars.example
|
|
65
|
+
terraform/**/tfplan
|
|
66
|
+
|
|
67
|
+
# Helm
|
|
68
|
+
helm/agenttier/charts/
|
|
69
|
+
|
|
70
|
+
# Build artifacts
|
|
71
|
+
dist/
|
|
72
|
+
tmp/
|
|
73
|
+
|
|
74
|
+
# Test
|
|
75
|
+
testbin/
|
|
76
|
+
|
|
77
|
+
# OS files
|
|
78
|
+
Thumbs.db
|
agenttier-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agenttier
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python SDK for AgentTier — manage isolated AI agent sandboxes on Kubernetes
|
|
5
|
+
Project-URL: Homepage, https://github.com/agenttier/agenttier
|
|
6
|
+
Project-URL: Documentation, https://agenttier.github.io/agenttier/sdk/
|
|
7
|
+
Project-URL: Repository, https://github.com/agenttier/agenttier
|
|
8
|
+
Project-URL: Issues, https://github.com/agenttier/agenttier/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/agenttier/agenttier/blob/main/CHANGELOG.md
|
|
10
|
+
Author: AgentTier Authors
|
|
11
|
+
License-Expression: Apache-2.0
|
|
12
|
+
Keywords: agents,ai-agents,developer-tools,kubernetes,sandbox
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Classifier: Topic :: System :: Clustering
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: httpx<1.0,>=0.27.0
|
|
27
|
+
Requires-Dist: pydantic<3.0,>=2.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# AgentTier Python SDK
|
|
37
|
+
|
|
38
|
+
Programmatic client for [AgentTier](https://github.com/agenttier/agenttier) —
|
|
39
|
+
manage isolated, persistent Kubernetes sandboxes for AI agents from Python.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
pip install agenttier
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Synchronous quick start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from agenttier import AgentTierClient
|
|
49
|
+
|
|
50
|
+
with AgentTierClient(api_url="https://agenttier.company.com") as client:
|
|
51
|
+
sandbox = client.create_sandbox(template="general-coding", name="demo")
|
|
52
|
+
sandbox.wait_until_running()
|
|
53
|
+
|
|
54
|
+
result = sandbox.exec("echo 'hello from AgentTier'")
|
|
55
|
+
print(result.stdout, "exit", result.exit_code)
|
|
56
|
+
|
|
57
|
+
port = sandbox.forward_port(8080)
|
|
58
|
+
print("Forwarded:", port.preview_url or port.internal_url)
|
|
59
|
+
|
|
60
|
+
sandbox.terminate()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Async
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import asyncio
|
|
67
|
+
from agenttier import AsyncAgentTierClient
|
|
68
|
+
|
|
69
|
+
async def main():
|
|
70
|
+
async with AsyncAgentTierClient(api_url="https://agenttier.company.com") as client:
|
|
71
|
+
sandbox = await client.create_sandbox(template="general-coding", name="demo")
|
|
72
|
+
await sandbox.wait_until_running()
|
|
73
|
+
result = await sandbox.exec("uname -a")
|
|
74
|
+
print(result.stdout)
|
|
75
|
+
await sandbox.terminate()
|
|
76
|
+
|
|
77
|
+
asyncio.run(main())
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Authentication
|
|
81
|
+
|
|
82
|
+
The SDK auto-detects credentials in this order:
|
|
83
|
+
|
|
84
|
+
1. `AGENTTIER_API_KEY` — sent as `X-API-Key`.
|
|
85
|
+
2. `AGENTTIER_TOKEN` — sent as `Authorization: Bearer <token>` (OIDC JWT).
|
|
86
|
+
3. In-cluster ServiceAccount token at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
|
|
87
|
+
4. Unauthenticated (accepted only in the Router's dev mode).
|
|
88
|
+
|
|
89
|
+
Or pass an explicit provider:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from agenttier import AgentTierClient, APIKeyAuth, BearerTokenAuth
|
|
93
|
+
|
|
94
|
+
client = AgentTierClient(
|
|
95
|
+
api_url="https://agenttier.company.com",
|
|
96
|
+
auth=APIKeyAuth("sk_live_..."),
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Error handling
|
|
101
|
+
|
|
102
|
+
Every error inherits from `AgentTierError` so you can catch them all at once.
|
|
103
|
+
The common subclasses you'll want to handle individually:
|
|
104
|
+
|
|
105
|
+
| Exception | When |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `AuthenticationError` | 401 — token / API key missing or invalid |
|
|
108
|
+
| `AuthorizationError` | 403 — authenticated but not permitted |
|
|
109
|
+
| `PolicyViolationError` | 403 with governance body; exposes `.violations` |
|
|
110
|
+
| `NotFoundError` | 404 — resource doesn't exist |
|
|
111
|
+
| `ConflictError` | 409 — operation invalid for current state |
|
|
112
|
+
| `SandboxTimeoutError` | `wait_until_running` timed out |
|
|
113
|
+
| `SandboxErrorState` | sandbox entered the `Error` phase while waiting |
|
|
114
|
+
| `APIError` | anything else; carries `.status_code` and `.body` |
|
|
115
|
+
|
|
116
|
+
## Supported API surface (v0.1.1)
|
|
117
|
+
|
|
118
|
+
Only endpoints that the Router server implements in v0.1.0 are exposed:
|
|
119
|
+
|
|
120
|
+
- **Sandboxes** — `create_sandbox`, `list_sandboxes`, `get_sandbox`, `stop`,
|
|
121
|
+
`resume`, `terminate`, `exec`, `wait_until_running`, `status`.
|
|
122
|
+
- **Port forwarding** — `forward_port`, `list_ports`, `remove_port`.
|
|
123
|
+
- **Templates** — `list_templates`, `get_template`.
|
|
124
|
+
- **Identity** — `current_user`.
|
|
125
|
+
|
|
126
|
+
Endpoints that are not yet implemented on the server (file transfer, sharing,
|
|
127
|
+
cloning, WebSocket terminal from Python) are **not exposed** by the SDK and
|
|
128
|
+
will be added in a future release once the server ships them.
|
|
129
|
+
|
|
130
|
+
## Supported Python versions
|
|
131
|
+
|
|
132
|
+
3.10, 3.11, 3.12, 3.13. Runtime dependencies: `httpx` and `pydantic`.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
Apache-2.0. Source at
|
|
137
|
+
[github.com/agenttier/agenttier/tree/main/python-sdk](https://github.com/agenttier/agenttier/tree/main/python-sdk).
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# AgentTier Python SDK
|
|
2
|
+
|
|
3
|
+
Programmatic client for [AgentTier](https://github.com/agenttier/agenttier) —
|
|
4
|
+
manage isolated, persistent Kubernetes sandboxes for AI agents from Python.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
pip install agenttier
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Synchronous quick start
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from agenttier import AgentTierClient
|
|
14
|
+
|
|
15
|
+
with AgentTierClient(api_url="https://agenttier.company.com") as client:
|
|
16
|
+
sandbox = client.create_sandbox(template="general-coding", name="demo")
|
|
17
|
+
sandbox.wait_until_running()
|
|
18
|
+
|
|
19
|
+
result = sandbox.exec("echo 'hello from AgentTier'")
|
|
20
|
+
print(result.stdout, "exit", result.exit_code)
|
|
21
|
+
|
|
22
|
+
port = sandbox.forward_port(8080)
|
|
23
|
+
print("Forwarded:", port.preview_url or port.internal_url)
|
|
24
|
+
|
|
25
|
+
sandbox.terminate()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Async
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import asyncio
|
|
32
|
+
from agenttier import AsyncAgentTierClient
|
|
33
|
+
|
|
34
|
+
async def main():
|
|
35
|
+
async with AsyncAgentTierClient(api_url="https://agenttier.company.com") as client:
|
|
36
|
+
sandbox = await client.create_sandbox(template="general-coding", name="demo")
|
|
37
|
+
await sandbox.wait_until_running()
|
|
38
|
+
result = await sandbox.exec("uname -a")
|
|
39
|
+
print(result.stdout)
|
|
40
|
+
await sandbox.terminate()
|
|
41
|
+
|
|
42
|
+
asyncio.run(main())
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Authentication
|
|
46
|
+
|
|
47
|
+
The SDK auto-detects credentials in this order:
|
|
48
|
+
|
|
49
|
+
1. `AGENTTIER_API_KEY` — sent as `X-API-Key`.
|
|
50
|
+
2. `AGENTTIER_TOKEN` — sent as `Authorization: Bearer <token>` (OIDC JWT).
|
|
51
|
+
3. In-cluster ServiceAccount token at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
|
|
52
|
+
4. Unauthenticated (accepted only in the Router's dev mode).
|
|
53
|
+
|
|
54
|
+
Or pass an explicit provider:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from agenttier import AgentTierClient, APIKeyAuth, BearerTokenAuth
|
|
58
|
+
|
|
59
|
+
client = AgentTierClient(
|
|
60
|
+
api_url="https://agenttier.company.com",
|
|
61
|
+
auth=APIKeyAuth("sk_live_..."),
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Error handling
|
|
66
|
+
|
|
67
|
+
Every error inherits from `AgentTierError` so you can catch them all at once.
|
|
68
|
+
The common subclasses you'll want to handle individually:
|
|
69
|
+
|
|
70
|
+
| Exception | When |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `AuthenticationError` | 401 — token / API key missing or invalid |
|
|
73
|
+
| `AuthorizationError` | 403 — authenticated but not permitted |
|
|
74
|
+
| `PolicyViolationError` | 403 with governance body; exposes `.violations` |
|
|
75
|
+
| `NotFoundError` | 404 — resource doesn't exist |
|
|
76
|
+
| `ConflictError` | 409 — operation invalid for current state |
|
|
77
|
+
| `SandboxTimeoutError` | `wait_until_running` timed out |
|
|
78
|
+
| `SandboxErrorState` | sandbox entered the `Error` phase while waiting |
|
|
79
|
+
| `APIError` | anything else; carries `.status_code` and `.body` |
|
|
80
|
+
|
|
81
|
+
## Supported API surface (v0.1.1)
|
|
82
|
+
|
|
83
|
+
Only endpoints that the Router server implements in v0.1.0 are exposed:
|
|
84
|
+
|
|
85
|
+
- **Sandboxes** — `create_sandbox`, `list_sandboxes`, `get_sandbox`, `stop`,
|
|
86
|
+
`resume`, `terminate`, `exec`, `wait_until_running`, `status`.
|
|
87
|
+
- **Port forwarding** — `forward_port`, `list_ports`, `remove_port`.
|
|
88
|
+
- **Templates** — `list_templates`, `get_template`.
|
|
89
|
+
- **Identity** — `current_user`.
|
|
90
|
+
|
|
91
|
+
Endpoints that are not yet implemented on the server (file transfer, sharing,
|
|
92
|
+
cloning, WebSocket terminal from Python) are **not exposed** by the SDK and
|
|
93
|
+
will be added in a future release once the server ships them.
|
|
94
|
+
|
|
95
|
+
## Supported Python versions
|
|
96
|
+
|
|
97
|
+
3.10, 3.11, 3.12, 3.13. Runtime dependencies: `httpx` and `pydantic`.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
Apache-2.0. Source at
|
|
102
|
+
[github.com/agenttier/agenttier/tree/main/python-sdk](https://github.com/agenttier/agenttier/tree/main/python-sdk).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright 2024 AgentTier Authors.
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Basic usage example for the AgentTier Python SDK.
|
|
6
|
+
|
|
7
|
+
Before running: set ``AGENTTIER_API_KEY`` or ``AGENTTIER_TOKEN`` (or run the
|
|
8
|
+
Router in dev mode locally) and update ``API_URL`` below.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from agenttier import AgentTierClient
|
|
14
|
+
|
|
15
|
+
API_URL = "http://localhost:8080" # or https://agenttier.company.com in production
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> None:
|
|
19
|
+
with AgentTierClient(api_url=API_URL) as client:
|
|
20
|
+
print("Authenticated as:", client.current_user())
|
|
21
|
+
|
|
22
|
+
print("Available templates:")
|
|
23
|
+
for template in client.list_templates():
|
|
24
|
+
print(f" - {template.name}: {template.description or '(no description)'}")
|
|
25
|
+
|
|
26
|
+
sandbox = client.create_sandbox(template="general-coding", name="sdk-demo")
|
|
27
|
+
print(f"Created sandbox {sandbox.id}; waiting for Running…")
|
|
28
|
+
sandbox.wait_until_running()
|
|
29
|
+
|
|
30
|
+
result = sandbox.exec("echo 'Hello from AgentTier!'")
|
|
31
|
+
print(f"stdout: {result.stdout.strip()}")
|
|
32
|
+
print(f"exit: {result.exit_code}")
|
|
33
|
+
|
|
34
|
+
sandbox.terminate()
|
|
35
|
+
print("Terminated.")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
main()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agenttier"
|
|
7
|
+
# Source of truth is src/agenttier/_version.py — keep both in sync on release.
|
|
8
|
+
version = "0.1.1"
|
|
9
|
+
description = "Python SDK for AgentTier — manage isolated AI agent sandboxes on Kubernetes"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "AgentTier Authors" },
|
|
15
|
+
]
|
|
16
|
+
keywords = ["kubernetes", "sandbox", "ai-agents", "developer-tools", "agents"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: Apache Software License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Software Development :: Libraries",
|
|
28
|
+
"Topic :: System :: Clustering",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"httpx>=0.27.0,<1.0",
|
|
33
|
+
"pydantic>=2.0.0,<3.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8.0",
|
|
39
|
+
"pytest-asyncio>=0.23",
|
|
40
|
+
"pytest-httpx>=0.30",
|
|
41
|
+
"ruff>=0.5",
|
|
42
|
+
"mypy>=1.10",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/agenttier/agenttier"
|
|
47
|
+
Documentation = "https://agenttier.github.io/agenttier/sdk/"
|
|
48
|
+
Repository = "https://github.com/agenttier/agenttier"
|
|
49
|
+
Issues = "https://github.com/agenttier/agenttier/issues"
|
|
50
|
+
Changelog = "https://github.com/agenttier/agenttier/blob/main/CHANGELOG.md"
|
|
51
|
+
|
|
52
|
+
[tool.hatch.build.targets.wheel]
|
|
53
|
+
packages = ["src/agenttier"]
|
|
54
|
+
|
|
55
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
56
|
+
"src/agenttier/py.typed" = "agenttier/py.typed"
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
target-version = "py310"
|
|
60
|
+
line-length = 100
|
|
61
|
+
|
|
62
|
+
[tool.mypy]
|
|
63
|
+
python_version = "3.10"
|
|
64
|
+
strict = true
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
testpaths = ["tests"]
|
|
68
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Copyright 2024 AgentTier Authors.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""AgentTier Python SDK.
|
|
5
|
+
|
|
6
|
+
Manage isolated AI agent sandboxes on Kubernetes from Python.
|
|
7
|
+
|
|
8
|
+
Typical usage::
|
|
9
|
+
|
|
10
|
+
from agenttier import AgentTierClient
|
|
11
|
+
|
|
12
|
+
with AgentTierClient(api_url="https://agenttier.company.com") as client:
|
|
13
|
+
sandbox = client.create_sandbox(template="general-coding", name="demo")
|
|
14
|
+
sandbox.wait_until_running()
|
|
15
|
+
print(sandbox.exec("uname -a").stdout)
|
|
16
|
+
sandbox.terminate()
|
|
17
|
+
|
|
18
|
+
See :mod:`agenttier.async_client` for the ``async/await`` variant.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from agenttier._version import __version__
|
|
22
|
+
from agenttier.async_client import AsyncAgentTierClient
|
|
23
|
+
from agenttier.async_sandbox import AsyncSandbox
|
|
24
|
+
from agenttier.auth import APIKeyAuth, AuthProvider, BearerTokenAuth, KubeconfigAuth
|
|
25
|
+
from agenttier.client import AgentTierClient
|
|
26
|
+
from agenttier.exceptions import (
|
|
27
|
+
AgentTierError,
|
|
28
|
+
APIError,
|
|
29
|
+
AuthenticationError,
|
|
30
|
+
AuthorizationError,
|
|
31
|
+
ConflictError,
|
|
32
|
+
NotFoundError,
|
|
33
|
+
PolicyViolationError,
|
|
34
|
+
SandboxErrorState,
|
|
35
|
+
SandboxTimeoutError,
|
|
36
|
+
)
|
|
37
|
+
from agenttier.models import (
|
|
38
|
+
AuditEvent,
|
|
39
|
+
CommandResult,
|
|
40
|
+
CreatedBy,
|
|
41
|
+
CurrentUser,
|
|
42
|
+
ForwardedPort,
|
|
43
|
+
SandboxPhase,
|
|
44
|
+
SandboxSummary,
|
|
45
|
+
Template,
|
|
46
|
+
UsageAnalytics,
|
|
47
|
+
)
|
|
48
|
+
from agenttier.sandbox import Sandbox
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"__version__",
|
|
52
|
+
# Clients
|
|
53
|
+
"AgentTierClient",
|
|
54
|
+
"AsyncAgentTierClient",
|
|
55
|
+
# Handles
|
|
56
|
+
"Sandbox",
|
|
57
|
+
"AsyncSandbox",
|
|
58
|
+
# Auth
|
|
59
|
+
"AuthProvider",
|
|
60
|
+
"APIKeyAuth",
|
|
61
|
+
"BearerTokenAuth",
|
|
62
|
+
"KubeconfigAuth",
|
|
63
|
+
# Models
|
|
64
|
+
"AuditEvent",
|
|
65
|
+
"CommandResult",
|
|
66
|
+
"CreatedBy",
|
|
67
|
+
"CurrentUser",
|
|
68
|
+
"ForwardedPort",
|
|
69
|
+
"SandboxPhase",
|
|
70
|
+
"SandboxSummary",
|
|
71
|
+
"Template",
|
|
72
|
+
"UsageAnalytics",
|
|
73
|
+
# Exceptions
|
|
74
|
+
"AgentTierError",
|
|
75
|
+
"APIError",
|
|
76
|
+
"AuthenticationError",
|
|
77
|
+
"AuthorizationError",
|
|
78
|
+
"ConflictError",
|
|
79
|
+
"NotFoundError",
|
|
80
|
+
"PolicyViolationError",
|
|
81
|
+
"SandboxErrorState",
|
|
82
|
+
"SandboxTimeoutError",
|
|
83
|
+
]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Copyright 2024 AgentTier Authors.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Internal HTTP utilities.
|
|
5
|
+
|
|
6
|
+
Kept private (underscore prefix) so we can change the shape freely without a
|
|
7
|
+
compat guarantee. The public clients are the only consumers.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
|
|
16
|
+
from agenttier.exceptions import (
|
|
17
|
+
APIError,
|
|
18
|
+
AuthenticationError,
|
|
19
|
+
AuthorizationError,
|
|
20
|
+
ConflictError,
|
|
21
|
+
NotFoundError,
|
|
22
|
+
PolicyViolationError,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _decode_body(response: httpx.Response) -> Any:
|
|
27
|
+
"""Return a JSON body, a text body, or None, whichever succeeds."""
|
|
28
|
+
if not response.content:
|
|
29
|
+
return None
|
|
30
|
+
try:
|
|
31
|
+
return response.json()
|
|
32
|
+
except ValueError:
|
|
33
|
+
return response.text or None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def raise_for_status(response: httpx.Response) -> None:
|
|
37
|
+
"""Translate non-2xx responses into typed SDK exceptions.
|
|
38
|
+
|
|
39
|
+
The Router returns structured JSON error bodies (``{"error": ..., ...}``)
|
|
40
|
+
so we can offer crisp exception types without parsing error strings.
|
|
41
|
+
"""
|
|
42
|
+
if response.is_success:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
body = _decode_body(response)
|
|
46
|
+
status = response.status_code
|
|
47
|
+
message = _extract_message(body, response.reason_phrase)
|
|
48
|
+
|
|
49
|
+
if status == 401:
|
|
50
|
+
raise AuthenticationError(message)
|
|
51
|
+
if status == 403:
|
|
52
|
+
if isinstance(body, dict) and body.get("error") == "policy_violation":
|
|
53
|
+
raise PolicyViolationError(message, list(body.get("violations", [])))
|
|
54
|
+
raise AuthorizationError(message)
|
|
55
|
+
if status == 404:
|
|
56
|
+
raise NotFoundError(message)
|
|
57
|
+
if status == 409:
|
|
58
|
+
raise ConflictError(message)
|
|
59
|
+
raise APIError(status, message, body)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _extract_message(body: Any, fallback: str) -> str:
|
|
63
|
+
if isinstance(body, dict):
|
|
64
|
+
for key in ("error", "message"):
|
|
65
|
+
v = body.get(key)
|
|
66
|
+
if isinstance(v, str) and v:
|
|
67
|
+
return v
|
|
68
|
+
if isinstance(body, str) and body:
|
|
69
|
+
return body
|
|
70
|
+
return fallback or "request failed"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def default_user_agent(version: str) -> str:
|
|
74
|
+
return f"agenttier-python-sdk/{version}"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright 2024 AgentTier Authors.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Single source of truth for the SDK version string.
|
|
5
|
+
|
|
6
|
+
Kept in a separate module so ``pyproject.toml`` and :mod:`agenttier` can both
|
|
7
|
+
import it without circular dependencies. Release tooling reads this file when
|
|
8
|
+
bumping versions; keep the identifier named ``__version__``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.1"
|