agv 0.1.0__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.
- agentenv/__init__.py +26 -0
- agentenv/__main__.py +6 -0
- agentenv/_version.py +3 -0
- agentenv/api/__init__.py +23 -0
- agentenv/api/ai_gateway.py +322 -0
- agentenv/api/analytics.py +350 -0
- agentenv/api/app.py +127 -0
- agentenv/api/auth.py +155 -0
- agentenv/api/billing.py +92 -0
- agentenv/api/browser.py +212 -0
- agentenv/api/client.py +190 -0
- agentenv/api/cluster.py +70 -0
- agentenv/api/file.py +209 -0
- agentenv/api/image.py +100 -0
- agentenv/api/models.py +1250 -0
- agentenv/api/notebook.py +640 -0
- agentenv/api/sandbox.py +329 -0
- agentenv/api/site.py +178 -0
- agentenv/api/snapshot.py +163 -0
- agentenv/api/workflow.py +265 -0
- agentenv/api/workspace.py +195 -0
- agentenv/cli/__init__.py +1 -0
- agentenv/cli/ai.py +760 -0
- agentenv/cli/analytics.py +305 -0
- agentenv/cli/app.py +512 -0
- agentenv/cli/app_cmd.py +349 -0
- agentenv/cli/auth.py +344 -0
- agentenv/cli/billing.py +148 -0
- agentenv/cli/browser.py +433 -0
- agentenv/cli/cluster.py +247 -0
- agentenv/cli/config_cmd.py +333 -0
- agentenv/cli/file.py +264 -0
- agentenv/cli/image.py +500 -0
- agentenv/cli/notebook.py +1959 -0
- agentenv/cli/sandbox.py +944 -0
- agentenv/cli/site.py +315 -0
- agentenv/cli/snapshot.py +212 -0
- agentenv/cli/workflow.py +1004 -0
- agentenv/cli/workspace.py +383 -0
- agentenv/config/__init__.py +1 -0
- agentenv/config/defaults.py +132 -0
- agentenv/config/settings.py +199 -0
- agentenv/config/storage.py +197 -0
- agentenv/oauth/__init__.py +1 -0
- agentenv/oauth/flow.py +229 -0
- agentenv/sdk/__init__.py +1324 -0
- agentenv/sdk/ai.py +476 -0
- agentenv/sdk/cluster.py +487 -0
- agentenv/sdk/function.py +359 -0
- agentenv/sdk/image.py +1344 -0
- agentenv/spec.py +42 -0
- agentenv/ui/__init__.py +1 -0
- agentenv/ui/progress.py +269 -0
- agentenv/ui/tables.py +1133 -0
- agv-0.1.0.dist-info/METADATA +402 -0
- agv-0.1.0.dist-info/RECORD +58 -0
- agv-0.1.0.dist-info/WHEEL +4 -0
- agv-0.1.0.dist-info/entry_points.txt +4 -0
agentenv/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""AgentEnv Cloud CLI - Manage containers, sandboxes, and more."""
|
|
2
|
+
|
|
3
|
+
from ._version import __version__
|
|
4
|
+
|
|
5
|
+
# SDK exports
|
|
6
|
+
from .sdk import Client, connect, SandboxResource
|
|
7
|
+
from .sdk.ai import AIClient
|
|
8
|
+
from .sdk.cluster import ray_init, spark_init, remote
|
|
9
|
+
from .sdk.function import function, RemoteFunctionError
|
|
10
|
+
from .sdk.image import ImageBuilder, image, py
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Client",
|
|
14
|
+
"connect",
|
|
15
|
+
"SandboxResource",
|
|
16
|
+
"AIClient",
|
|
17
|
+
"ImageBuilder",
|
|
18
|
+
"image",
|
|
19
|
+
"py",
|
|
20
|
+
"function",
|
|
21
|
+
"RemoteFunctionError",
|
|
22
|
+
"ray_init",
|
|
23
|
+
"spark_init",
|
|
24
|
+
"remote",
|
|
25
|
+
"__version__",
|
|
26
|
+
]
|
agentenv/__main__.py
ADDED
agentenv/_version.py
ADDED
agentenv/api/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""API client for AgentEnv Cloud."""
|
|
2
|
+
|
|
3
|
+
from .analytics import AnalyticsAPI
|
|
4
|
+
from .models import (
|
|
5
|
+
AnalyticsInstallation,
|
|
6
|
+
AnalyticsFunnel,
|
|
7
|
+
AnalyticsFunnelStep,
|
|
8
|
+
AnalyticsUserProfile,
|
|
9
|
+
AnalyticsEvent,
|
|
10
|
+
CreateAnalyticsInstallationRequest,
|
|
11
|
+
CreateAnalyticsFunnelRequest,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"AnalyticsAPI",
|
|
16
|
+
"AnalyticsInstallation",
|
|
17
|
+
"AnalyticsFunnel",
|
|
18
|
+
"AnalyticsFunnelStep",
|
|
19
|
+
"AnalyticsUserProfile",
|
|
20
|
+
"AnalyticsEvent",
|
|
21
|
+
"CreateAnalyticsInstallationRequest",
|
|
22
|
+
"CreateAnalyticsFunnelRequest",
|
|
23
|
+
]
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""AI Gateway API client."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Iterator
|
|
4
|
+
|
|
5
|
+
from .client import Client
|
|
6
|
+
from .models import (
|
|
7
|
+
GatewayUpstream,
|
|
8
|
+
GatewayPool,
|
|
9
|
+
GatewayApiKey,
|
|
10
|
+
CreateGatewayApiKeyRequest,
|
|
11
|
+
GatewayUsageReport,
|
|
12
|
+
ChatCompletionRequest,
|
|
13
|
+
ChatCompletionResponse,
|
|
14
|
+
ChatCompletionChunk,
|
|
15
|
+
EmbeddingRequest,
|
|
16
|
+
EmbeddingResponse,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AIGatewayAPI:
|
|
21
|
+
"""API client for AI Gateway resources."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, client: Client, gateway_key: str | None = None):
|
|
24
|
+
"""Initialize AI Gateway API client.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
client: HTTP client instance (for management APIs with JWT)
|
|
28
|
+
gateway_key: Gateway API key (for proxy APIs)
|
|
29
|
+
"""
|
|
30
|
+
self.client = client
|
|
31
|
+
self.gateway_key = gateway_key
|
|
32
|
+
self.chat = ChatCompletionsAPI(client, gateway_key)
|
|
33
|
+
self.embeddings = EmbeddingsAPI(client, gateway_key)
|
|
34
|
+
|
|
35
|
+
# -------------------------------------------------------------------------
|
|
36
|
+
# Upstreams
|
|
37
|
+
# -------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
def list_upstreams(self) -> list[GatewayUpstream]:
|
|
40
|
+
"""List all upstream providers.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List of upstream configurations
|
|
44
|
+
"""
|
|
45
|
+
response = self.client.get("/ai-gateway/upstreams")
|
|
46
|
+
data = response.json()
|
|
47
|
+
|
|
48
|
+
if isinstance(data, list):
|
|
49
|
+
return [GatewayUpstream(**item) for item in data]
|
|
50
|
+
return []
|
|
51
|
+
|
|
52
|
+
def create_upstream(
|
|
53
|
+
self,
|
|
54
|
+
name: str,
|
|
55
|
+
provider: str,
|
|
56
|
+
api_key: str,
|
|
57
|
+
base_url: str | None = None,
|
|
58
|
+
rate_limit_rpm: int | None = None,
|
|
59
|
+
rate_limit_tpm: int | None = None,
|
|
60
|
+
priority: int = 0,
|
|
61
|
+
weight: int = 1,
|
|
62
|
+
) -> GatewayUpstream:
|
|
63
|
+
"""Create a new upstream provider."""
|
|
64
|
+
data: dict[str, Any] = {
|
|
65
|
+
"name": name,
|
|
66
|
+
"provider": provider,
|
|
67
|
+
"apiKey": api_key,
|
|
68
|
+
"priority": priority,
|
|
69
|
+
"weight": weight,
|
|
70
|
+
}
|
|
71
|
+
if base_url:
|
|
72
|
+
data["baseUrl"] = base_url
|
|
73
|
+
if rate_limit_rpm:
|
|
74
|
+
data["rateLimitRpm"] = rate_limit_rpm
|
|
75
|
+
if rate_limit_tpm:
|
|
76
|
+
data["rateLimitTpm"] = rate_limit_tpm
|
|
77
|
+
|
|
78
|
+
response = self.client.post("/ai-gateway/upstreams", json=data)
|
|
79
|
+
return GatewayUpstream(**response.json())
|
|
80
|
+
|
|
81
|
+
def get_upstream(self, upstream_id: str) -> GatewayUpstream:
|
|
82
|
+
"""Get upstream details."""
|
|
83
|
+
response = self.client.get(f"/ai-gateway/upstreams/{upstream_id}")
|
|
84
|
+
return GatewayUpstream(**response.json())
|
|
85
|
+
|
|
86
|
+
def delete_upstream(self, upstream_id: str) -> None:
|
|
87
|
+
"""Delete an upstream provider."""
|
|
88
|
+
self.client.delete(f"/ai-gateway/upstreams/{upstream_id}")
|
|
89
|
+
|
|
90
|
+
def test_upstream(self, upstream_id: str) -> dict[str, Any]:
|
|
91
|
+
"""Test upstream connectivity."""
|
|
92
|
+
response = self.client.post(f"/ai-gateway/upstreams/{upstream_id}/test")
|
|
93
|
+
return response.json()
|
|
94
|
+
|
|
95
|
+
# -------------------------------------------------------------------------
|
|
96
|
+
# Pools
|
|
97
|
+
# -------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def list_pools(self) -> list[GatewayPool]:
|
|
100
|
+
"""List all pools."""
|
|
101
|
+
response = self.client.get("/ai-gateway/pools")
|
|
102
|
+
data = response.json()
|
|
103
|
+
|
|
104
|
+
if isinstance(data, list):
|
|
105
|
+
return [GatewayPool(**item) for item in data]
|
|
106
|
+
return []
|
|
107
|
+
|
|
108
|
+
def create_pool(
|
|
109
|
+
self,
|
|
110
|
+
name: str,
|
|
111
|
+
strategy: str = "round-robin",
|
|
112
|
+
model_mappings: dict[str, str] | None = None,
|
|
113
|
+
) -> GatewayPool:
|
|
114
|
+
"""Create a new pool."""
|
|
115
|
+
data: dict[str, Any] = {
|
|
116
|
+
"name": name,
|
|
117
|
+
"strategy": strategy,
|
|
118
|
+
}
|
|
119
|
+
if model_mappings:
|
|
120
|
+
data["modelMappings"] = model_mappings
|
|
121
|
+
|
|
122
|
+
response = self.client.post("/ai-gateway/pools", json=data)
|
|
123
|
+
return GatewayPool(**response.json())
|
|
124
|
+
|
|
125
|
+
def delete_pool(self, pool_id: str) -> None:
|
|
126
|
+
"""Delete a pool."""
|
|
127
|
+
self.client.delete(f"/ai-gateway/pools/{pool_id}")
|
|
128
|
+
|
|
129
|
+
def add_pool_member(
|
|
130
|
+
self,
|
|
131
|
+
pool_id: str,
|
|
132
|
+
upstream_id: str,
|
|
133
|
+
priority: int = 0,
|
|
134
|
+
weight: int = 1,
|
|
135
|
+
) -> GatewayPool:
|
|
136
|
+
"""Add member to pool."""
|
|
137
|
+
data = {
|
|
138
|
+
"upstreamId": upstream_id,
|
|
139
|
+
"priority": priority,
|
|
140
|
+
"weight": weight,
|
|
141
|
+
}
|
|
142
|
+
response = self.client.post(f"/ai-gateway/pools/{pool_id}/members", json=data)
|
|
143
|
+
return GatewayPool(**response.json())
|
|
144
|
+
|
|
145
|
+
# -------------------------------------------------------------------------
|
|
146
|
+
# API Keys
|
|
147
|
+
# -------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
def list_keys(self) -> list[GatewayApiKey]:
|
|
150
|
+
"""List all API keys."""
|
|
151
|
+
response = self.client.get("/ai-gateway/keys")
|
|
152
|
+
data = response.json()
|
|
153
|
+
|
|
154
|
+
if isinstance(data, list):
|
|
155
|
+
return [GatewayApiKey(**item) for item in data]
|
|
156
|
+
return []
|
|
157
|
+
|
|
158
|
+
def create_key(self, request: CreateGatewayApiKeyRequest) -> GatewayApiKey:
|
|
159
|
+
"""Create a new API key."""
|
|
160
|
+
response = self.client.post(
|
|
161
|
+
"/ai-gateway/keys",
|
|
162
|
+
json=request.model_dump(exclude_none=True, by_alias=True),
|
|
163
|
+
)
|
|
164
|
+
return GatewayApiKey(**response.json())
|
|
165
|
+
|
|
166
|
+
def revoke_key(self, key_id: str) -> None:
|
|
167
|
+
"""Revoke an API key."""
|
|
168
|
+
self.client.delete(f"/ai-gateway/keys/{key_id}")
|
|
169
|
+
|
|
170
|
+
# -------------------------------------------------------------------------
|
|
171
|
+
# Discovery
|
|
172
|
+
# -------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
def list_providers(self) -> dict[str, Any]:
|
|
175
|
+
"""List supported gateway providers."""
|
|
176
|
+
response = self.client.get("/ai-gateway/providers")
|
|
177
|
+
return response.json()
|
|
178
|
+
|
|
179
|
+
def list_platform_models(self) -> dict[str, Any]:
|
|
180
|
+
"""List platform models grouped by provider."""
|
|
181
|
+
response = self.client.get("/ai-gateway/platform-models")
|
|
182
|
+
return response.json()
|
|
183
|
+
|
|
184
|
+
# -------------------------------------------------------------------------
|
|
185
|
+
# Usage
|
|
186
|
+
# -------------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
def get_usage(
|
|
189
|
+
self,
|
|
190
|
+
start_date: str | None = None,
|
|
191
|
+
end_date: str | None = None,
|
|
192
|
+
upstream_id: str | None = None,
|
|
193
|
+
) -> GatewayUsageReport:
|
|
194
|
+
"""Get usage report."""
|
|
195
|
+
params: dict[str, Any] = {}
|
|
196
|
+
if start_date:
|
|
197
|
+
params["startDate"] = start_date
|
|
198
|
+
if end_date:
|
|
199
|
+
params["endDate"] = end_date
|
|
200
|
+
if upstream_id:
|
|
201
|
+
params["upstreamId"] = upstream_id
|
|
202
|
+
|
|
203
|
+
response = self.client.get("/ai-gateway/usage", params=params)
|
|
204
|
+
return GatewayUsageReport(**response.json())
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class ChatCompletionsAPI:
|
|
208
|
+
"""Chat completions API (OpenAI-compatible endpoint)."""
|
|
209
|
+
|
|
210
|
+
def __init__(self, client: Client, gateway_key: str | None = None):
|
|
211
|
+
self.client = client
|
|
212
|
+
self.gateway_key = gateway_key
|
|
213
|
+
|
|
214
|
+
def _auth_headers(self) -> dict[str, str]:
|
|
215
|
+
"""Get authentication headers for proxy API."""
|
|
216
|
+
if self.gateway_key:
|
|
217
|
+
return {"x-gateway-key": self.gateway_key}
|
|
218
|
+
return {}
|
|
219
|
+
|
|
220
|
+
def create(
|
|
221
|
+
self,
|
|
222
|
+
request: ChatCompletionRequest | dict[str, Any],
|
|
223
|
+
) -> ChatCompletionResponse | Iterator[ChatCompletionChunk]:
|
|
224
|
+
"""Create chat completion."""
|
|
225
|
+
if isinstance(request, ChatCompletionRequest):
|
|
226
|
+
data = request.model_dump(exclude_none=True, by_alias=True)
|
|
227
|
+
else:
|
|
228
|
+
data = request
|
|
229
|
+
|
|
230
|
+
headers = self._auth_headers()
|
|
231
|
+
|
|
232
|
+
if data.get("stream"):
|
|
233
|
+
return self._stream_create(data, headers)
|
|
234
|
+
|
|
235
|
+
response = self.client.post(
|
|
236
|
+
"/ai-gateway/openai/v1/chat/completions",
|
|
237
|
+
json=data,
|
|
238
|
+
headers=headers,
|
|
239
|
+
)
|
|
240
|
+
return ChatCompletionResponse(**response.json())
|
|
241
|
+
|
|
242
|
+
def _stream_create(
|
|
243
|
+
self,
|
|
244
|
+
data: dict[str, Any],
|
|
245
|
+
headers: dict[str, str],
|
|
246
|
+
) -> Iterator[ChatCompletionChunk]:
|
|
247
|
+
"""Create streaming chat completion."""
|
|
248
|
+
# Use stream_request from StreamingClient if available
|
|
249
|
+
if hasattr(self.client, "stream_request"):
|
|
250
|
+
response = self.client.stream_request(
|
|
251
|
+
"POST",
|
|
252
|
+
"/ai-gateway/openai/v1/chat/completions",
|
|
253
|
+
json=data,
|
|
254
|
+
headers=headers,
|
|
255
|
+
)
|
|
256
|
+
else:
|
|
257
|
+
# Fallback to regular client with streaming
|
|
258
|
+
import httpx
|
|
259
|
+
|
|
260
|
+
with httpx.Client() as http_client:
|
|
261
|
+
url = f"{self.client.base_url}/ai-gateway/openai/v1/chat/completions"
|
|
262
|
+
headers = {**headers, "Content-Type": "application/json"}
|
|
263
|
+
|
|
264
|
+
with http_client.stream("POST", url, json=data, headers=headers) as response:
|
|
265
|
+
for line in response.iter_lines():
|
|
266
|
+
if line.startswith("data: "):
|
|
267
|
+
data_str = line[6:]
|
|
268
|
+
if data_str == "[DONE]":
|
|
269
|
+
break
|
|
270
|
+
try:
|
|
271
|
+
chunk = ChatCompletionChunk.model_validate_json(data_str)
|
|
272
|
+
yield chunk
|
|
273
|
+
except Exception: # noqa: S110 - Skip invalid chunks
|
|
274
|
+
continue
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
# Handle response from stream_request
|
|
278
|
+
for line in response.iter_lines():
|
|
279
|
+
if isinstance(line, bytes):
|
|
280
|
+
line = line.decode("utf-8")
|
|
281
|
+
if line.startswith("data: "):
|
|
282
|
+
data_str = line[6:]
|
|
283
|
+
if data_str == "[DONE]":
|
|
284
|
+
break
|
|
285
|
+
try:
|
|
286
|
+
chunk = ChatCompletionChunk.model_validate_json(data_str)
|
|
287
|
+
yield chunk
|
|
288
|
+
except Exception: # noqa: S110 - Skip invalid chunks
|
|
289
|
+
continue
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class EmbeddingsAPI:
|
|
293
|
+
"""Embeddings API (OpenAI-compatible endpoint)."""
|
|
294
|
+
|
|
295
|
+
def __init__(self, client: Client, gateway_key: str | None = None):
|
|
296
|
+
self.client = client
|
|
297
|
+
self.gateway_key = gateway_key
|
|
298
|
+
|
|
299
|
+
def _auth_headers(self) -> dict[str, str]:
|
|
300
|
+
"""Get authentication headers for proxy API."""
|
|
301
|
+
if self.gateway_key:
|
|
302
|
+
return {"x-gateway-key": self.gateway_key}
|
|
303
|
+
return {}
|
|
304
|
+
|
|
305
|
+
def create(
|
|
306
|
+
self,
|
|
307
|
+
request: EmbeddingRequest | dict[str, Any],
|
|
308
|
+
) -> EmbeddingResponse:
|
|
309
|
+
"""Create embeddings."""
|
|
310
|
+
if isinstance(request, EmbeddingRequest):
|
|
311
|
+
data = request.model_dump(exclude_none=True, by_alias=True)
|
|
312
|
+
else:
|
|
313
|
+
data = request
|
|
314
|
+
|
|
315
|
+
headers = self._auth_headers()
|
|
316
|
+
|
|
317
|
+
response = self.client.post(
|
|
318
|
+
"/ai-gateway/openai/v1/embeddings",
|
|
319
|
+
json=data,
|
|
320
|
+
headers=headers,
|
|
321
|
+
)
|
|
322
|
+
return EmbeddingResponse(**response.json())
|