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.
Files changed (58) hide show
  1. agentenv/__init__.py +26 -0
  2. agentenv/__main__.py +6 -0
  3. agentenv/_version.py +3 -0
  4. agentenv/api/__init__.py +23 -0
  5. agentenv/api/ai_gateway.py +322 -0
  6. agentenv/api/analytics.py +350 -0
  7. agentenv/api/app.py +127 -0
  8. agentenv/api/auth.py +155 -0
  9. agentenv/api/billing.py +92 -0
  10. agentenv/api/browser.py +212 -0
  11. agentenv/api/client.py +190 -0
  12. agentenv/api/cluster.py +70 -0
  13. agentenv/api/file.py +209 -0
  14. agentenv/api/image.py +100 -0
  15. agentenv/api/models.py +1250 -0
  16. agentenv/api/notebook.py +640 -0
  17. agentenv/api/sandbox.py +329 -0
  18. agentenv/api/site.py +178 -0
  19. agentenv/api/snapshot.py +163 -0
  20. agentenv/api/workflow.py +265 -0
  21. agentenv/api/workspace.py +195 -0
  22. agentenv/cli/__init__.py +1 -0
  23. agentenv/cli/ai.py +760 -0
  24. agentenv/cli/analytics.py +305 -0
  25. agentenv/cli/app.py +512 -0
  26. agentenv/cli/app_cmd.py +349 -0
  27. agentenv/cli/auth.py +344 -0
  28. agentenv/cli/billing.py +148 -0
  29. agentenv/cli/browser.py +433 -0
  30. agentenv/cli/cluster.py +247 -0
  31. agentenv/cli/config_cmd.py +333 -0
  32. agentenv/cli/file.py +264 -0
  33. agentenv/cli/image.py +500 -0
  34. agentenv/cli/notebook.py +1959 -0
  35. agentenv/cli/sandbox.py +944 -0
  36. agentenv/cli/site.py +315 -0
  37. agentenv/cli/snapshot.py +212 -0
  38. agentenv/cli/workflow.py +1004 -0
  39. agentenv/cli/workspace.py +383 -0
  40. agentenv/config/__init__.py +1 -0
  41. agentenv/config/defaults.py +132 -0
  42. agentenv/config/settings.py +199 -0
  43. agentenv/config/storage.py +197 -0
  44. agentenv/oauth/__init__.py +1 -0
  45. agentenv/oauth/flow.py +229 -0
  46. agentenv/sdk/__init__.py +1324 -0
  47. agentenv/sdk/ai.py +476 -0
  48. agentenv/sdk/cluster.py +487 -0
  49. agentenv/sdk/function.py +359 -0
  50. agentenv/sdk/image.py +1344 -0
  51. agentenv/spec.py +42 -0
  52. agentenv/ui/__init__.py +1 -0
  53. agentenv/ui/progress.py +269 -0
  54. agentenv/ui/tables.py +1133 -0
  55. agv-0.1.0.dist-info/METADATA +402 -0
  56. agv-0.1.0.dist-info/RECORD +58 -0
  57. agv-0.1.0.dist-info/WHEEL +4 -0
  58. 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
@@ -0,0 +1,6 @@
1
+ """Entry point for `python -m agentenv`."""
2
+
3
+ from .cli.app import main_cli
4
+
5
+ if __name__ == "__main__":
6
+ main_cli()
agentenv/_version.py ADDED
@@ -0,0 +1,3 @@
1
+ """Single source of truth for the package version."""
2
+
3
+ __version__ = "0.1.0"
@@ -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())