agenta 0.2.12__tar.gz → 0.3.0__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.

Potentially problematic release.


This version of agenta might be problematic. Click here for more details.

Files changed (40) hide show
  1. {agenta-0.2.12 → agenta-0.3.0}/PKG-INFO +1 -1
  2. {agenta-0.2.12 → agenta-0.3.0}/agenta/__init__.py +1 -0
  3. {agenta-0.2.12 → agenta-0.3.0}/agenta/cli/helper.py +8 -5
  4. {agenta-0.2.12 → agenta-0.3.0}/agenta/cli/main.py +8 -2
  5. {agenta-0.2.12 → agenta-0.3.0}/agenta/cli/variant_commands.py +49 -39
  6. {agenta-0.2.12 → agenta-0.3.0}/agenta/client/api_models.py +6 -0
  7. agenta-0.3.0/agenta/client/client.py +253 -0
  8. {agenta-0.2.12 → agenta-0.3.0}/pyproject.toml +1 -1
  9. agenta-0.2.12/agenta/client/client.py +0 -177
  10. {agenta-0.2.12 → agenta-0.3.0}/README.md +0 -0
  11. {agenta-0.2.12 → agenta-0.3.0}/agenta/client/Readme.md +0 -0
  12. {agenta-0.2.12 → agenta-0.3.0}/agenta/client/__init__.py +0 -0
  13. {agenta-0.2.12 → agenta-0.3.0}/agenta/config.py +0 -0
  14. {agenta-0.2.12 → agenta-0.3.0}/agenta/config.toml +0 -0
  15. {agenta-0.2.12 → agenta-0.3.0}/agenta/docker/docker-assets/Dockerfile.template +0 -0
  16. {agenta-0.2.12 → agenta-0.3.0}/agenta/docker/docker-assets/README.md +0 -0
  17. {agenta-0.2.12 → agenta-0.3.0}/agenta/docker/docker-assets/entrypoint.sh +0 -0
  18. {agenta-0.2.12 → agenta-0.3.0}/agenta/docker/docker-assets/main.py +0 -0
  19. {agenta-0.2.12 → agenta-0.3.0}/agenta/docker/docker_utils.py +0 -0
  20. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/__init__.py +0 -0
  21. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/agenta.py +0 -0
  22. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/context.py +0 -0
  23. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/init.py +0 -0
  24. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/router.py +0 -0
  25. {agenta-0.2.12 → agenta-0.3.0}/agenta/sdk/types.py +0 -0
  26. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/compose_email/README.md +0 -0
  27. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/compose_email/app.py +0 -0
  28. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/compose_email/env.example +0 -0
  29. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/compose_email/requirements.txt +0 -0
  30. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/compose_email/template.toml +0 -0
  31. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/extract_data_to_json/README.md +0 -0
  32. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/extract_data_to_json/app.py +0 -0
  33. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/extract_data_to_json/env.example +0 -0
  34. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/extract_data_to_json/requirements.txt +0 -0
  35. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/extract_data_to_json/template.toml +0 -0
  36. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/simple_prompt/README.md +0 -0
  37. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/simple_prompt/app.py +0 -0
  38. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/simple_prompt/env.example +0 -0
  39. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/simple_prompt/requirements.txt +0 -0
  40. {agenta-0.2.12 → agenta-0.3.0}/agenta/templates/simple_prompt/template.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: agenta
3
- Version: 0.2.12
3
+ Version: 0.3.0
4
4
  Summary: SDK for Agenta an open-source LLMOps platform.
5
5
  Home-page: https://agenta.ai
6
6
  Keywords: LLMOps,LLM,evaluation,prompt engineering
@@ -1,4 +1,5 @@
1
1
  from . import sdk
2
+ from . import config
2
3
  from .sdk import post, ingest, app
3
4
  from .sdk.types import (
4
5
  TextParam,
@@ -7,19 +7,20 @@ from agenta.client.api_models import AppVariant
7
7
 
8
8
 
9
9
  def update_variants_from_backend(
10
- app_name: str, config: MutableMapping[str, Any], host: str
10
+ app_id: str, config: MutableMapping[str, Any], host: str
11
11
  ) -> MutableMapping[str, Any]:
12
12
  """Reads the list of variants from the backend and updates the config accordingly
13
13
 
14
14
  Arguments:
15
- app_name -- the app name
15
+ app_id -- the app id
16
16
  config -- the config loaded using toml.load
17
17
 
18
18
  Returns:
19
19
  a new config object later to be saved using toml.dump(config, config_file.open('w'))
20
20
  """
21
- variants: List[AppVariant] = client.list_variants(app_name, host)
21
+ variants: List[AppVariant] = client.list_variants(app_id, host)
22
22
  config["variants"] = [variant.variant_name for variant in variants]
23
+ config["variant_ids"] = [variant.variant_id for variant in variants]
23
24
  return config
24
25
 
25
26
 
@@ -31,10 +32,12 @@ def update_config_from_backend(config_file: Path, host: str):
31
32
  """
32
33
  assert config_file.exists(), "Config file does not exist!"
33
34
  config = toml.load(config_file)
34
- app_name = config["app-name"]
35
+ app_id = config["app_id"]
35
36
  if "variants" not in config:
36
37
  config["variants"] = []
37
- config = update_variants_from_backend(app_name, config, host)
38
+ if "variant_ids" not in config:
39
+ config["variant_ids"] = []
40
+ config = update_variants_from_backend(app_id, config, host)
38
41
  toml.dump(config, config_file.open("w"))
39
42
 
40
43
 
@@ -7,6 +7,8 @@ from pathlib import Path
7
7
  import click
8
8
  import questionary
9
9
  import toml
10
+
11
+ from agenta.client import client
10
12
  from agenta.cli import variant_commands
11
13
 
12
14
 
@@ -29,7 +31,7 @@ def check_latest_version() -> Union[str, None]:
29
31
  import requests
30
32
 
31
33
  try:
32
- response = requests.get("https://pypi.org/pypi/agenta/json")
34
+ response = requests.get("https://pypi.org/pypi/agenta/json", timeout=360)
33
35
  response.raise_for_status()
34
36
  latest_version = response.json()["info"]["version"]
35
37
  return latest_version
@@ -103,7 +105,11 @@ def init(app_name: str):
103
105
  else "http://" + backend_host
104
106
  )
105
107
 
106
- config = {"app-name": app_name, "backend_host": backend_host}
108
+ # Get app_id after creating new app in the backend server
109
+ app_id = client.create_new_app(app_name, backend_host)
110
+
111
+ # Set app toml configuration
112
+ config = {"app_name": app_name, "app_id": app_id, "backend_host": backend_host}
107
113
  with open("config.toml", "w") as config_file:
108
114
  toml.dump(config, config_file)
109
115
 
@@ -39,8 +39,11 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
39
39
  app_path = Path(app_folder)
40
40
  config_file = app_path / "config.toml"
41
41
  config = toml.load(config_file)
42
- app_name = config["app-name"]
43
- variant_name = file_name.removesuffix(".py")
42
+ app_name = config["app_name"]
43
+ app_id = config["app_id"]
44
+ base_name = file_name.removesuffix(".py")
45
+ config_name = "default"
46
+ variant_name = f"{base_name}.{config_name}"
44
47
  # check files in folder
45
48
  app_file = app_path / file_name
46
49
  if not app_file.exists():
@@ -71,7 +74,7 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
71
74
  sys.exit(0)
72
75
 
73
76
  # Validate variant name
74
- if not re.match("^[a-zA-Z0-9_]+$", variant_name):
77
+ if not re.match("^[a-zA-Z0-9_]+$", base_name):
75
78
  click.echo(
76
79
  click.style(
77
80
  "Invalid input. Please use only alphanumeric characters without spaces.",
@@ -82,6 +85,7 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
82
85
 
83
86
  # update the config file with the variant names from the backend
84
87
  overwrite = False
88
+
85
89
  if variant_name in config["variants"]:
86
90
  overwrite = questionary.confirm(
87
91
  "This variant already exists. Do you want to overwrite it?"
@@ -90,22 +94,22 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
90
94
  click.echo("Operation cancelled.")
91
95
  sys.exit(0)
92
96
 
93
- if not overwrite:
94
- config["variants"].append(variant_name)
95
97
  try:
96
98
  click.echo(
97
99
  click.style(
98
- f"Preparing variant {variant_name} into a tar file...", fg="yellow"
100
+ f"Preparing variant {base_name} into a tar file...",
101
+ fg="yellow",
99
102
  )
100
103
  )
101
104
  tar_path = build_tar_docker_container(folder=app_path, file_name=file_name)
102
105
 
103
106
  click.echo(
104
107
  click.style(
105
- f"Building variant {variant_name} into a docker image...", fg="yellow"
108
+ f"Building variant {base_name} into a docker image...",
109
+ fg="yellow",
106
110
  )
107
111
  )
108
- image: Image = client.send_docker_tar(app_name, variant_name, tar_path, host)
112
+ image: Image = client.send_docker_tar(app_id, base_name, tar_path, host)
109
113
  # docker_image: DockerImage = build_and_upload_docker_image(
110
114
  # folder=app_path, app_name=app_name, variant_name=variant_name)
111
115
  except Exception as ex:
@@ -115,15 +119,18 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
115
119
  if overwrite:
116
120
  click.echo(
117
121
  click.style(
118
- f"Updating variant {variant_name} to server...", fg="yellow"
122
+ f"Updating {base_name} to server...",
123
+ fg="yellow",
119
124
  )
120
125
  )
121
- client.update_variant_image(app_name, variant_name, image, host)
126
+ variant_id = config["variant_ids"][config["variants"].index(variant_name)]
127
+ client.update_variant_image(variant_id, image, host)
122
128
  else:
123
- click.echo(
124
- click.style(f"Adding variant {variant_name} to server...", fg="yellow")
125
- )
126
- client.add_variant_to_server(app_name, variant_name, image, host)
129
+ click.echo(click.style(f"Adding {variant_name} to server...", fg="yellow"))
130
+ response = client.add_variant_to_server(app_id, base_name, image, host)
131
+ variant_id = response["variant_id"]
132
+ config["variants"].append(variant_name)
133
+ config["variant_ids"].append(variant_id)
127
134
  except Exception as ex:
128
135
  if overwrite:
129
136
  click.echo(click.style(f"Error while updating variant: {ex}", fg="red"))
@@ -151,10 +158,10 @@ def add_variant(app_folder: str, file_name: str, host: str) -> str:
151
158
  # TODO: Improve this stupid design
152
159
  return None
153
160
  else:
154
- return variant_name
161
+ return variant_id
155
162
 
156
163
 
157
- def start_variant(variant_name: str, app_folder: str, host: str):
164
+ def start_variant(variant_id: str, app_folder: str, host: str):
158
165
  """
159
166
  Starts a container for an existing variant
160
167
  Args:
@@ -164,17 +171,18 @@ def start_variant(variant_name: str, app_folder: str, host: str):
164
171
  app_folder = Path(app_folder)
165
172
  config_file = app_folder / "config.toml"
166
173
  config = toml.load(config_file)
167
- app_name = config["app-name"]
174
+ app_name = config["app_name"]
175
+ app_id = config["app_id"]
168
176
 
169
177
  if len(config["variants"]) == 0:
170
178
  click.echo("No variants found. Please add a variant first.")
171
179
  return
172
180
 
173
- if variant_name:
174
- if variant_name not in config["variants"]:
181
+ if variant_id:
182
+ if variant_id not in config["variant_ids"]:
175
183
  click.echo(
176
184
  click.style(
177
- f"Variant {variant_name} not found in backend. Maybe you removed it in the webUI?",
185
+ f"Variant {variant_id} not found in backend. Maybe you removed it in the webUI?",
178
186
  fg="red",
179
187
  )
180
188
  )
@@ -183,30 +191,30 @@ def start_variant(variant_name: str, app_folder: str, host: str):
183
191
  variant_name = questionary.select(
184
192
  "Please choose a variant", choices=config["variants"]
185
193
  ).ask()
194
+ variant_id = config["variant_ids"][config["variants"].index(variant_name)]
186
195
 
187
- endpoint = client.start_variant(app_name, variant_name, host=host)
196
+ endpoint = client.start_variant(variant_id=variant_id, host=host)
188
197
  click.echo("\n" + click.style("Congratulations! 🎉", bold=True, fg="green"))
189
198
  click.echo(
190
- click.style(f"Your app has been deployed locally as an API. 🚀", fg="cyan")
191
- + click.style(f" You can access it here: ", fg="white")
199
+ click.style("Your app has been deployed locally as an API. 🚀", fg="cyan")
200
+ + click.style(" You can access it here: ", fg="white")
192
201
  + click.style(f"{endpoint}/", bold=True, fg="yellow")
193
202
  )
194
203
 
195
204
  click.echo(
196
- click.style(f"\nRead the API documentation. 📚", fg="cyan")
197
- + click.style(f" It's available at: ", fg="white")
205
+ click.style("\nRead the API documentation. 📚", fg="cyan")
206
+ + click.style(" It's available at: ", fg="white")
198
207
  + click.style(f"{endpoint}/docs", bold=True, fg="yellow")
199
208
  )
200
209
 
201
210
  webui_host = "http://localhost:3000" if host == "localhost" else host
202
211
  click.echo(
203
212
  click.style(
204
- "\nStart experimenting with your app in the playground. 🎮", fg="cyan"
213
+ "\nStart experimenting with your app in the playground. 🎮",
214
+ fg="cyan",
205
215
  )
206
216
  + click.style(" Go to: ", fg="white")
207
- + click.style(
208
- f"{webui_host}/apps/{app_name}/playground", bold=True, fg="yellow"
209
- )
217
+ + click.style(f"{webui_host}/apps/{app_id}/playground", bold=True, fg="yellow")
210
218
  + "\n"
211
219
  )
212
220
 
@@ -220,7 +228,7 @@ def remove_variant(variant_name: str, app_folder: str, host: str):
220
228
  """
221
229
  config_file = Path(app_folder) / "config.toml"
222
230
  config = toml.load(config_file)
223
- app_name = config["app-name"]
231
+ app_name = config["app_name"]
224
232
 
225
233
  if variant_name:
226
234
  if variant_name not in config["variants"]:
@@ -235,8 +243,9 @@ def remove_variant(variant_name: str, app_folder: str, host: str):
235
243
  variant_name = questionary.select(
236
244
  "Please choose a variant", choices=config["variants"]
237
245
  ).ask()
246
+ variant_id = config["variant_ids"][config["variants"].index(variant_name)]
238
247
  try:
239
- client.remove_variant(app_name, variant_name, host)
248
+ client.remove_variant(variant_id, host)
240
249
  except Exception as ex:
241
250
  click.echo(
242
251
  click.style(
@@ -263,8 +272,9 @@ def list_variants(app_folder: str, host: str):
263
272
  """
264
273
  config_file = Path(app_folder) / "config.toml"
265
274
  config = toml.load(config_file)
266
- app_name = config["app-name"]
267
- variants: List[AppVariant] = client.list_variants(app_name, host)
275
+ app_id = config["app_id"]
276
+ app_name = config["app_name"]
277
+ variants: List[AppVariant] = client.list_variants(app_id, host)
268
278
  if variants:
269
279
  for variant in variants:
270
280
  helper.display_app_variant(variant)
@@ -313,7 +323,9 @@ def remove_variant_cli(variant_name: str, app_folder: str):
313
323
  """Remove an existing variant."""
314
324
  config_check(app_folder)
315
325
  remove_variant(
316
- variant_name=variant_name, app_folder=app_folder, host=get_host(app_folder)
326
+ variant_name=variant_name,
327
+ app_folder=app_folder,
328
+ host=get_host(app_folder),
317
329
  )
318
330
 
319
331
 
@@ -344,17 +356,15 @@ def serve_cli(app_folder: str, file_name: str):
344
356
  return
345
357
 
346
358
  try:
347
- variant_name = add_variant(
348
- app_folder=app_folder, file_name=file_name, host=host
349
- )
359
+ variant_id = add_variant(app_folder=app_folder, file_name=file_name, host=host)
350
360
  except Exception as e:
351
361
  click.echo(click.style("Failed to add variant.", fg="red"))
352
362
  click.echo(click.style(f"Error message: {str(e)}", fg="red"))
353
363
  return
354
364
 
355
- if variant_name:
365
+ if variant_id:
356
366
  try:
357
- start_variant(variant_name=variant_name, app_folder=app_folder, host=host)
367
+ start_variant(variant_id=variant_id, app_folder=app_folder, host=host)
358
368
  except ConnectionError:
359
369
  error_msg = "Failed to connect to Agenta backend. Here's how you can solve the issue:\n"
360
370
  error_msg += "- First, please ensure that the backend service is running and accessible.\n"
@@ -3,12 +3,18 @@ from typing import List, Optional, Dict, Any
3
3
 
4
4
 
5
5
  class AppVariant(BaseModel):
6
+ app_id: str
6
7
  app_name: str
7
8
  variant_name: str
9
+ variant_id: str
8
10
  parameters: Optional[Dict[str, Any]]
9
11
  previous_variant_name: Optional[str]
10
12
 
11
13
 
14
+ class Variant(BaseModel):
15
+ variant_id: str
16
+
17
+
12
18
  class Image(BaseModel):
13
19
  docker_id: str
14
20
  tags: str
@@ -0,0 +1,253 @@
1
+ import os
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict
4
+
5
+ import requests
6
+ from agenta.client.api_models import AppVariant, Image
7
+ from requests.exceptions import RequestException
8
+
9
+ BACKEND_URL_SUFFIX = os.environ["BACKEND_URL_SUFFIX"]
10
+
11
+
12
+ class APIRequestError(Exception):
13
+ """Exception to be raised when an API request fails."""
14
+
15
+
16
+ def get_app_by_name(app_name: str, host: str) -> str:
17
+ """Get app by its name on the server.
18
+
19
+ Args:
20
+ app_name (str): Name of the app
21
+ host (str): Hostname of the server
22
+ """
23
+
24
+ response = requests.get(
25
+ f"{host}/{BACKEND_URL_SUFFIX}/apps/?app_name={app_name}/",
26
+ timeout=600,
27
+ )
28
+ if response.status_code != 200:
29
+ error_message = response.json()
30
+ raise APIRequestError(
31
+ f"Request to get app failed with status code {response.status_code} and error message: {error_message}."
32
+ )
33
+ return response.json()["app_id"]
34
+
35
+
36
+ def create_new_app(app_name: str, host: str) -> str:
37
+ """Creates new app on the server.
38
+
39
+ Args:
40
+ app_name (str): Name of the app
41
+ host (str): Hostname of the server
42
+ """
43
+
44
+ response = requests.post(
45
+ f"{host}/{BACKEND_URL_SUFFIX}/apps/",
46
+ json={"app_name": app_name},
47
+ timeout=600,
48
+ )
49
+ if response.status_code != 200:
50
+ error_message = response.json()
51
+ raise APIRequestError(
52
+ f"Request to create new app failed with status code {response.status_code} and error message: {error_message}."
53
+ )
54
+ return response.json()["app_id"]
55
+
56
+
57
+ def add_variant_to_server(app_id: str, base_name: str, image: Image, host: str) -> Dict:
58
+ """
59
+ Adds a variant to the server.
60
+
61
+ Args:
62
+ app_id (str): The ID of the app to add the variant to.
63
+ variant_name (str): The name of the variant to add.
64
+ image (Image): The image to use for the variant.
65
+ host (str): The host URL of the server.
66
+
67
+ Returns:
68
+ dict: The JSON response from the server.
69
+ Raises:
70
+ APIRequestError: If the request to the server fails.
71
+ """
72
+ variant_name = f"{base_name.lower()}.default"
73
+ payload = {
74
+ "variant_name": variant_name,
75
+ "base_name": base_name.lower(),
76
+ "config_name": "default",
77
+ "docker_id": image.docker_id,
78
+ "tags": image.tags,
79
+ }
80
+ response = requests.post(
81
+ f"{host}/{BACKEND_URL_SUFFIX}/apps/{app_id}/variant/from-image/",
82
+ json=payload,
83
+ timeout=600,
84
+ )
85
+ if response.status_code != 200:
86
+ error_message = response.json()
87
+ raise APIRequestError(
88
+ f"Request to app_variant endpoint failed with status code {response.status_code} and error message: {error_message}."
89
+ )
90
+ return response.json()
91
+
92
+
93
+ def start_variant(
94
+ variant_id: str, host: str, env_vars: Optional[Dict[str, str]] = None
95
+ ) -> str:
96
+ """
97
+ Starts or stops a container with the given variant and exposes its endpoint.
98
+
99
+ Args:
100
+ variant_id (str): The ID of the variant.
101
+ host (str): The host URL.
102
+ env_vars (Optional[Dict[str, str]]): Optional environment variables to inject into the container.
103
+
104
+ Returns:
105
+ str: The endpoint of the container.
106
+
107
+ Raises:
108
+ APIRequestError: If the API request fails.
109
+ """
110
+ payload = {}
111
+ payload["action"] = {"action": "START"}
112
+ if env_vars:
113
+ payload["env_vars"] = {"env_vars": env_vars}
114
+
115
+ try:
116
+ response = requests.put(
117
+ f"{host}/{BACKEND_URL_SUFFIX}/variants/{variant_id}/",
118
+ json=payload,
119
+ timeout=600,
120
+ )
121
+ if response.status_code == 404:
122
+ raise APIRequestError(
123
+ f"404: Variant with ID {variant_id} does not exist on the server."
124
+ )
125
+ elif response.status_code != 200:
126
+ error_message = response.text
127
+ raise APIRequestError(
128
+ f"Request to start variant endpoint failed with status code {response.status_code} and error message: {error_message}."
129
+ )
130
+ return response.json().get("uri", "")
131
+
132
+ except RequestException as e:
133
+ raise APIRequestError(f"An error occurred while making the request: {e}")
134
+
135
+
136
+ def list_variants(app_id: str, host: str) -> List[AppVariant]:
137
+ """
138
+ Returns a list of AppVariant objects for a given app_id and host.
139
+
140
+ Args:
141
+ app_id (str): The ID of the app to retrieve variants for.
142
+ host (str): The URL of the host to make the request to.
143
+
144
+ Returns:
145
+ List[AppVariant]: A list of AppVariant objects for the given app_id and host.
146
+ """
147
+ response = requests.get(
148
+ f"{host}/{BACKEND_URL_SUFFIX}/apps/{app_id}/variants/",
149
+ timeout=600,
150
+ )
151
+
152
+ # Check for successful request
153
+ if response.status_code != 200:
154
+ error_message = response.json()
155
+ raise APIRequestError(
156
+ f"Request to apps endpoint failed with status code {response.status_code} and error message: {error_message}."
157
+ )
158
+ app_variants = response.json()
159
+ return [AppVariant(**variant) for variant in app_variants]
160
+
161
+
162
+ def remove_variant(variant_id: str, host: str):
163
+ """
164
+ Sends a DELETE request to the Agenta backend to remove a variant with the given ID.
165
+
166
+ Args:
167
+ variant_id (str): The ID of the variant to be removed.
168
+ host (str): The URL of the Agenta backend.
169
+
170
+ Raises:
171
+ APIRequestError: If the request to the remove_variant endpoint fails.
172
+
173
+ Returns:
174
+ None
175
+ """
176
+ response = requests.delete(
177
+ f"{host}/{BACKEND_URL_SUFFIX}/variants/{variant_id}",
178
+ headers={"Content-Type": "application/json"},
179
+ timeout=600,
180
+ )
181
+
182
+ # Check for successful request
183
+ if response.status_code != 200:
184
+ error_message = response.json()
185
+ raise APIRequestError(
186
+ f"Request to remove_variant endpoint failed with status code {response.status_code} and error message: {error_message}"
187
+ )
188
+
189
+
190
+ def update_variant_image(variant_id: str, image: Image, host: str):
191
+ """
192
+ Update the image of a variant with the given ID.
193
+
194
+ Args:
195
+ variant_id (str): The ID of the variant to update.
196
+ image (Image): The new image to set for the variant.
197
+ host (str): The URL of the host to send the request to.
198
+
199
+ Raises:
200
+ APIRequestError: If the request to update the variant fails.
201
+
202
+ Returns:
203
+ None
204
+ """
205
+ response = requests.put(
206
+ f"{host}/{BACKEND_URL_SUFFIX}/variants/{variant_id}/image/",
207
+ json=image.dict(),
208
+ timeout=600,
209
+ )
210
+ if response.status_code != 200:
211
+ error_message = response.json()
212
+ raise APIRequestError(
213
+ f"Request to update app_variant failed with status code {response.status_code} and error message: {error_message}."
214
+ )
215
+
216
+
217
+ def send_docker_tar(app_id: str, base_name: str, tar_path: Path, host: str) -> Image:
218
+ """
219
+ Sends a Docker tar file to the specified host to build an image for the given app ID and variant name.
220
+
221
+ Args:
222
+ app_id (str): The ID of the app.
223
+ base_name (str): The name of the codebase.
224
+ tar_path (Path): The path to the Docker tar file.
225
+ host (str): The URL of the host to send the request to.
226
+
227
+ Returns:
228
+ Image: The built Docker image.
229
+
230
+ Raises:
231
+ Exception: If the response status code is 500, indicating that serving the variant failed.
232
+ """
233
+ with tar_path.open("rb") as tar_file:
234
+ response = requests.post(
235
+ f"{host}/{BACKEND_URL_SUFFIX}/containers/build_image/?app_id={app_id}&base_name={base_name}",
236
+ files={
237
+ "tar_file": tar_file,
238
+ },
239
+ timeout=1200,
240
+ )
241
+
242
+ if response.status_code == 500:
243
+ response_error = response.json()
244
+ error_msg = "Serving the variant failed.\n"
245
+ error_msg += f"Log: {response_error}\n"
246
+ error_msg += "Here's how you may be able to solve the issue:\n"
247
+ error_msg += "- First, make sure that the requirements.txt file has all the dependencies that you need.\n"
248
+ error_msg += "- Second, check the Docker logs for the backend image to see the error when running the Docker container."
249
+ raise Exception(error_msg)
250
+
251
+ response.raise_for_status()
252
+ image = Image.parse_obj(response.json())
253
+ return image
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "agenta"
3
- version = "0.2.12"
3
+ version = "0.3.0"
4
4
  description = "SDK for Agenta an open-source LLMOps platform."
5
5
  readme = "README.md"
6
6
  authors = ["Mahmoud Mabrouk <mahmoud@agenta.ai>"]
@@ -1,177 +0,0 @@
1
- import os
2
- from pathlib import Path
3
- from typing import List
4
-
5
- import agenta.config
6
- import requests
7
- from agenta.client.api_models import AppVariant, Image
8
- from docker.models.images import Image as DockerImage
9
-
10
- BACKEND_URL_SUFFIX = os.environ["BACKEND_URL_SUFFIX"]
11
-
12
-
13
- class APIRequestError(Exception):
14
- """Exception to be raised when an API request fails."""
15
-
16
-
17
- def add_variant_to_server(app_name: str, variant_name: str, image: Image, host: str):
18
- """Adds a variant to the server.
19
-
20
- Arguments:
21
- app_name -- Name of the app
22
- variant_name -- Name of the variant
23
- image_name -- Name of the image
24
- """
25
- app_variant: AppVariant = AppVariant(app_name=app_name, variant_name=variant_name)
26
- response = requests.post(
27
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/add/from_image/",
28
- json={"app_variant": app_variant.dict(), "image": image.dict()},
29
- timeout=600,
30
- )
31
- if response.status_code != 200:
32
- error_message = response.json()
33
- raise APIRequestError(
34
- f"Request to app_variant endpoint failed with status code {response.status_code} and error message: {error_message}."
35
- )
36
-
37
-
38
- def start_variant(app_name: str, variant_name: str, host: str) -> str:
39
- """Starts a container with the variant an expose its endpoint
40
-
41
- Arguments:
42
- app_name --
43
- variant_name -- _description_
44
-
45
- Returns:
46
- The endpoint of the container
47
- """
48
- response = requests.post(
49
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/start/",
50
- json={"app_variant": {"app_name": app_name, "variant_name": variant_name}},
51
- timeout=600,
52
- )
53
-
54
- if response.status_code != 200:
55
- error_message = response.json()
56
- raise APIRequestError(
57
- f"Request to start variant endpoint failed with status code {response.status_code} and error message: {error_message}."
58
- )
59
- return response.json()["uri"]
60
-
61
-
62
- def list_variants(app_name: str, host: str) -> List[AppVariant]:
63
- """Lists all the variants registered in the backend for an app
64
-
65
- Arguments:
66
- app_name -- the app name to which to return all the variants
67
-
68
- Returns:
69
- a list of the variants using the pydantic model
70
- """
71
- response = requests.get(
72
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/list_variants/?app_name={app_name}",
73
- timeout=600,
74
- )
75
-
76
- # Check for successful request
77
- if response.status_code != 200:
78
- error_message = response.json()
79
- raise APIRequestError(
80
- f"Request to list_variants endpoint failed with status code {response.status_code} and error message: {error_message}."
81
- )
82
- app_variants = response.json()
83
- return [AppVariant(**variant) for variant in app_variants]
84
-
85
-
86
- def get_variant_by_name(app_name: str, variant_name: str, host: str) -> AppVariant:
87
- """Gets a variant by name
88
-
89
- Arguments:
90
- app_name -- the app name
91
- variant_name -- the variant name
92
-
93
- Returns:
94
- the variant using the pydantic model
95
- """
96
- response = requests.get(
97
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/get_variant_by_name/?app_name={app_name}&variant_name={variant_name}",
98
- timeout=600,
99
- )
100
-
101
- # Check for successful request
102
- if response.status_code != 200:
103
- error_message = response.json()
104
- raise APIRequestError(
105
- f"Request to get_variant_by_name endpoint failed with status code {response.status_code} and error message: {error_message}."
106
- )
107
-
108
-
109
- def remove_variant(app_name: str, variant_name: str, host: str):
110
- """Removes a variant from the backend
111
-
112
- Arguments:
113
- app_name -- the app name
114
- variant_name -- the variant name
115
- """
116
- app_variant = AppVariant(app_name=app_name, variant_name=variant_name)
117
- app_variant_json = app_variant.json()
118
- response = requests.delete(
119
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/remove_variant/",
120
- data=app_variant_json,
121
- headers={"Content-Type": "application/json"},
122
- timeout=600,
123
- )
124
-
125
- # Check for successful request
126
- if response.status_code != 200:
127
- error_message = response.json()
128
- raise APIRequestError(
129
- f"Request to remove_variant endpoint failed with status code {response.status_code} and error message: {error_message}"
130
- )
131
-
132
-
133
- def update_variant_image(app_name: str, variant_name: str, image: Image, host: str):
134
- """Adds a variant to the server.
135
-
136
- Arguments:
137
- app_name -- Name of the app
138
- variant_name -- Name of the variant
139
- image_name -- Name of the image
140
- """
141
- app_variant: AppVariant = AppVariant(app_name=app_name, variant_name=variant_name)
142
- response = requests.put(
143
- f"{host}/{BACKEND_URL_SUFFIX}/app_variant/update_variant_image/",
144
- json={"app_variant": app_variant.dict(), "image": image.dict()},
145
- timeout=600,
146
- )
147
- if response.status_code != 200:
148
- error_message = response.json()
149
- raise APIRequestError(
150
- f"Request to update app_variant failed with status code {response.status_code} and error message: {error_message}."
151
- )
152
-
153
-
154
- def send_docker_tar(
155
- app_name: str, variant_name: str, tar_path: Path, host: str
156
- ) -> Image:
157
- with tar_path.open("rb") as tar_file:
158
- response = requests.post(
159
- f"{host}/{BACKEND_URL_SUFFIX}/containers/build_image/?app_name={app_name}&variant_name={variant_name}",
160
- files={
161
- "tar_file": tar_file,
162
- },
163
- timeout=1200,
164
- )
165
-
166
- if response.status_code == 500:
167
- response_error = response.json()
168
- error_msg = "Serving the variant failed.\n"
169
- error_msg += f"Log: {response_error}\n"
170
- error_msg += "Here's how you may be able to solve the issue:\n"
171
- error_msg += "- First, make sure that the requirements.txt file has all the dependencies that you need.\n"
172
- error_msg += "- Second, check the Docker logs for the backend image to see the error when running the Docker container."
173
- raise Exception(error_msg)
174
-
175
- response.raise_for_status()
176
- image = Image.parse_obj(response.json())
177
- return image
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes