agenta 0.14.7a0__tar.gz → 0.14.8__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 (164) hide show
  1. {agenta-0.14.7a0 → agenta-0.14.8}/PKG-INFO +1 -1
  2. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/__init__.py +2 -3
  3. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/variant_commands.py +7 -7
  4. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/__init__.py +3 -3
  5. agenta-0.14.8/agenta/sdk/agenta_decorator.py +501 -0
  6. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/agenta_init.py +66 -67
  7. agenta-0.14.8/agenta/sdk/tracing/decorators.py +41 -0
  8. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/tracing/llm_tracing.py +12 -39
  9. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/tracing/tasks_manager.py +3 -1
  10. {agenta-0.14.7a0 → agenta-0.14.8}/pyproject.toml +1 -1
  11. agenta-0.14.7a0/agenta/sdk/decorators/base.py +0 -10
  12. agenta-0.14.7a0/agenta/sdk/decorators/llm_entrypoint.py +0 -493
  13. agenta-0.14.7a0/agenta/sdk/decorators/tracing.py +0 -112
  14. {agenta-0.14.7a0 → agenta-0.14.8}/README.md +0 -0
  15. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/evaluation_commands.py +0 -0
  16. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/helper.py +0 -0
  17. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/main.py +0 -0
  18. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/telemetry.py +0 -0
  19. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/cli/variant_configs.py +0 -0
  20. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/Readme.md +0 -0
  21. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/__init__.py +0 -0
  22. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/api.py +0 -0
  23. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/api_models.py +0 -0
  24. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/__init__.py +0 -0
  25. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/client.py +0 -0
  26. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/__init__.py +0 -0
  27. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/api_error.py +0 -0
  28. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/client_wrapper.py +0 -0
  29. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/datetime_utils.py +0 -0
  30. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/jsonable_encoder.py +0 -0
  31. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/core/remove_none_from_dict.py +0 -0
  32. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/errors/__init__.py +0 -0
  33. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/errors/unprocessable_entity_error.py +0 -0
  34. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/__init__.py +0 -0
  35. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/apps/__init__.py +0 -0
  36. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/apps/client.py +0 -0
  37. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/bases/__init__.py +0 -0
  38. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/bases/client.py +0 -0
  39. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/configs/__init__.py +0 -0
  40. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/configs/client.py +0 -0
  41. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/containers/__init__.py +0 -0
  42. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/containers/client.py +0 -0
  43. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/containers/types/__init__.py +0 -0
  44. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/containers/types/container_templates_response.py +0 -0
  45. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/environments/__init__.py +0 -0
  46. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/environments/client.py +0 -0
  47. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/evaluations/__init__.py +0 -0
  48. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/evaluations/client.py +0 -0
  49. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/evaluators/__init__.py +0 -0
  50. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/evaluators/client.py +0 -0
  51. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/observability/__init__.py +0 -0
  52. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/observability/client.py +0 -0
  53. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/testsets/__init__.py +0 -0
  54. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/testsets/client.py +0 -0
  55. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/variants/__init__.py +0 -0
  56. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/variants/client.py +0 -0
  57. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/variants/types/__init__.py +0 -0
  58. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/resources/variants/types/add_variant_from_base_and_config_response.py +0 -0
  59. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/__init__.py +0 -0
  60. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/aggregated_result.py +0 -0
  61. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/aggregated_result_evaluator_config.py +0 -0
  62. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/app.py +0 -0
  63. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/app_variant_response.py +0 -0
  64. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/app_variant_revision.py +0 -0
  65. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/base_output.py +0 -0
  66. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/body_import_testset.py +0 -0
  67. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/config_db.py +0 -0
  68. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/create_app_output.py +0 -0
  69. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/create_span.py +0 -0
  70. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/create_trace_response.py +0 -0
  71. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/docker_env_vars.py +0 -0
  72. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/environment_output.py +0 -0
  73. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/environment_output_extended.py +0 -0
  74. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/environment_revision.py +0 -0
  75. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/error.py +0 -0
  76. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation.py +0 -0
  77. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_scenario.py +0 -0
  78. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_scenario_input.py +0 -0
  79. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_scenario_output.py +0 -0
  80. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_scenario_result.py +0 -0
  81. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_scenario_score_update.py +0 -0
  82. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_status_enum.py +0 -0
  83. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_type.py +0 -0
  84. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluation_webhook.py +0 -0
  85. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluator.py +0 -0
  86. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/evaluator_config.py +0 -0
  87. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/feedback.py +0 -0
  88. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/get_config_response.py +0 -0
  89. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/http_validation_error.py +0 -0
  90. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation.py +0 -0
  91. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation_scenario.py +0 -0
  92. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation_scenario_input.py +0 -0
  93. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation_scenario_output.py +0 -0
  94. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation_scenario_update.py +0 -0
  95. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/human_evaluation_update.py +0 -0
  96. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/image.py +0 -0
  97. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/invite_request.py +0 -0
  98. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/list_api_keys_response.py +0 -0
  99. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/llm_run_rate_limit.py +0 -0
  100. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/llm_tokens.py +0 -0
  101. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/new_human_evaluation.py +0 -0
  102. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/new_testset.py +0 -0
  103. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/organization.py +0 -0
  104. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/organization_output.py +0 -0
  105. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/permission.py +0 -0
  106. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/result.py +0 -0
  107. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/score.py +0 -0
  108. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/simple_evaluation_output.py +0 -0
  109. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/span.py +0 -0
  110. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/span_detail.py +0 -0
  111. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/span_kind.py +0 -0
  112. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/span_status_code.py +0 -0
  113. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/span_variant.py +0 -0
  114. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/template.py +0 -0
  115. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/template_image_info.py +0 -0
  116. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/test_set_output_response.py +0 -0
  117. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/test_set_simple_response.py +0 -0
  118. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/trace_detail.py +0 -0
  119. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/uri.py +0 -0
  120. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/validation_error.py +0 -0
  121. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/validation_error_loc_item.py +0 -0
  122. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/variant_action.py +0 -0
  123. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/variant_action_enum.py +0 -0
  124. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/with_pagination.py +0 -0
  125. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/workspace_member_response.py +0 -0
  126. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/workspace_permission.py +0 -0
  127. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/workspace_response.py +0 -0
  128. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/workspace_role.py +0 -0
  129. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/backend/types/workspace_role_response.py +0 -0
  130. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/client.py +0 -0
  131. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/client/exceptions.py +0 -0
  132. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/config.py +0 -0
  133. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/config.toml +0 -0
  134. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/Dockerfile.cloud.template +0 -0
  135. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/Dockerfile.template +0 -0
  136. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/README.md +0 -0
  137. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/entrypoint.sh +0 -0
  138. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/lambda_function.py +0 -0
  139. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker-assets/main.py +0 -0
  140. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/docker/docker_utils.py +0 -0
  141. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/client.py +0 -0
  142. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/context.py +0 -0
  143. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/router.py +0 -0
  144. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/tracing/context_manager.py +0 -0
  145. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/tracing/logger.py +0 -0
  146. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/types.py +0 -0
  147. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/utils/globals.py +0 -0
  148. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/utils/helper/openai_cost.py +0 -0
  149. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/sdk/utils/preinit.py +0 -0
  150. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/compose_email/README.md +0 -0
  151. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/compose_email/app.py +0 -0
  152. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/compose_email/env.example +0 -0
  153. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/compose_email/requirements.txt +0 -0
  154. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/compose_email/template.toml +0 -0
  155. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/extract_data_to_json/README.md +0 -0
  156. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/extract_data_to_json/app.py +0 -0
  157. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/extract_data_to_json/env.example +0 -0
  158. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/extract_data_to_json/requirements.txt +0 -0
  159. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/extract_data_to_json/template.toml +0 -0
  160. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/simple_prompt/README.md +0 -0
  161. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/simple_prompt/app.py +0 -0
  162. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/simple_prompt/env.example +0 -0
  163. {agenta-0.14.7a0 → agenta-0.14.8}/agenta/templates/simple_prompt/requirements.txt +0 -0
  164. {agenta-0.14.7a0 → agenta-0.14.8}/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.14.7a0
3
+ Version: 0.14.8
4
4
  Summary: The SDK for agenta is 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 .sdk.utils.preinit import PreInitObject
2
+ from .sdk.agenta_decorator import app, entrypoint
2
3
  from .sdk.context import get_contexts, save_context
3
4
  from .sdk.types import (
4
5
  Context,
@@ -13,9 +14,7 @@ from .sdk.types import (
13
14
  FileInputURL,
14
15
  BinaryParam,
15
16
  )
16
- from .sdk.tracing.llm_tracing import Tracing
17
- from .sdk.decorators.tracing import span, trace
18
- from .sdk.decorators.llm_entrypoint import entrypoint
17
+ from .sdk.tracing.decorators import span
19
18
  from .sdk.agenta_init import Config, init, llm_tracing
20
19
  from .sdk.utils.helper.openai_cost import calculate_token_usage
21
20
  from .sdk.client import Agenta
@@ -104,12 +104,13 @@ def add_variant(
104
104
  )
105
105
 
106
106
  if variant_name in config["variants"] and not overwrite:
107
- overwrite_question = questionary.confirm(
108
- "This variant already exists. Do you want to overwrite it?"
109
- ).ask()
110
- if not overwrite_question:
111
- click.echo("Operation cancelled.")
112
- sys.exit(0)
107
+ if not overwrite:
108
+ overwrite = questionary.confirm(
109
+ "This variant already exists. Do you want to overwrite it?"
110
+ ).ask()
111
+ if not overwrite:
112
+ click.echo("Operation cancelled.")
113
+ return
113
114
 
114
115
  try:
115
116
  click.echo(
@@ -445,7 +446,6 @@ def remove_variant_cli(variant_name: str, app_folder: str):
445
446
  @click.option(
446
447
  "--overwrite",
447
448
  is_flag=True,
448
- default=False,
449
449
  help="Overwrite the existing variant if it exists",
450
450
  )
451
451
  @click.pass_context
@@ -1,4 +1,6 @@
1
1
  from .utils.preinit import PreInitObject # always the first import!
2
+ from . import agenta_decorator, context, types, utils # noqa: F401
3
+ from .agenta_decorator import app, entrypoint
2
4
  from .context import get_contexts, save_context
3
5
  from .types import (
4
6
  Context,
@@ -13,9 +15,7 @@ from .types import (
13
15
  FileInputURL,
14
16
  BinaryParam,
15
17
  )
16
- from .tracing.llm_tracing import Tracing
17
- from .decorators.tracing import span, trace
18
- from .decorators.llm_entrypoint import entrypoint
18
+ from .tracing.decorators import span
19
19
  from .agenta_init import Config, init, llm_tracing
20
20
  from .utils.helper.openai_cost import calculate_token_usage
21
21
 
@@ -0,0 +1,501 @@
1
+ """The code for the Agenta SDK"""
2
+
3
+ import os
4
+ import sys
5
+ import time
6
+ import inspect
7
+ import argparse
8
+ import asyncio
9
+ import traceback
10
+ import functools
11
+ from pathlib import Path
12
+ from tempfile import NamedTemporaryFile
13
+ from typing import Any, Callable, Dict, Optional, Tuple, List
14
+
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+ from fastapi import Body, FastAPI, UploadFile, HTTPException
17
+
18
+ import agenta
19
+ from .context import save_context
20
+ from .router import router as router
21
+ from .types import (
22
+ Context,
23
+ DictInput,
24
+ FloatParam,
25
+ InFile,
26
+ IntParam,
27
+ MultipleChoiceParam,
28
+ GroupedMultipleChoiceParam,
29
+ TextParam,
30
+ MessagesInput,
31
+ FileInputURL,
32
+ FuncResponse,
33
+ BinaryParam,
34
+ )
35
+
36
+ app = FastAPI()
37
+
38
+ origins = [
39
+ "*",
40
+ ]
41
+
42
+ app.add_middleware(
43
+ CORSMiddleware,
44
+ allow_origins=origins,
45
+ allow_credentials=True,
46
+ allow_methods=["*"],
47
+ allow_headers=["*"],
48
+ )
49
+
50
+ app.include_router(router, prefix="")
51
+
52
+
53
+ def ingest_file(upfile: UploadFile):
54
+ temp_file = NamedTemporaryFile(delete=False)
55
+ temp_file.write(upfile.file.read())
56
+ temp_file.close()
57
+ return InFile(file_name=upfile.filename, file_path=temp_file.name)
58
+
59
+
60
+ def entrypoint(func: Callable[..., Any]) -> Callable[..., Any]:
61
+ """
62
+ Decorator to wrap a function for HTTP POST and terminal exposure.
63
+
64
+ Args:
65
+ func: Function to wrap.
66
+
67
+ Returns:
68
+ Wrapped function for HTTP POST and terminal.
69
+ """
70
+
71
+ endpoint_name = "generate"
72
+ func_signature = inspect.signature(func)
73
+ config_params = agenta.config.all()
74
+ ingestible_files = extract_ingestible_files(func_signature)
75
+
76
+ # Initialize tracing
77
+ tracing = agenta.llm_tracing()
78
+
79
+ @functools.wraps(func)
80
+ async def wrapper(*args, **kwargs) -> Any:
81
+ func_params, api_config_params = split_kwargs(kwargs, config_params)
82
+
83
+ # Start tracing
84
+ tracing.start_parent_span(
85
+ name=func.__name__,
86
+ inputs=func_params,
87
+ config=config_params,
88
+ environment="playground", # type: ignore #NOTE: wrapper is only called in playground
89
+ )
90
+
91
+ # Ingest files, prepare configurations and run llm app
92
+ ingest_files(func_params, ingestible_files)
93
+ agenta.config.set(**api_config_params)
94
+ llm_result = await execute_function(
95
+ func, *args, params=func_params, config_params=config_params
96
+ )
97
+
98
+ # End trace recording
99
+ tracing.end_recording(
100
+ outputs=llm_result.dict(),
101
+ span=tracing.active_trace,
102
+ )
103
+ return llm_result
104
+
105
+ @functools.wraps(func)
106
+ async def wrapper_deployed(*args, **kwargs) -> Any:
107
+ func_params = {
108
+ k: v for k, v in kwargs.items() if k not in ["config", "environment"]
109
+ }
110
+ if "environment" in kwargs and kwargs["environment"] is not None:
111
+ agenta.config.pull(environment_name=kwargs["environment"])
112
+ elif "config" in kwargs and kwargs["config"] is not None:
113
+ agenta.config.pull(config_name=kwargs["config"])
114
+ else:
115
+ agenta.config.pull(config_name="default")
116
+
117
+ config = agenta.config.all()
118
+
119
+ # Start tracing
120
+ tracing.start_parent_span(
121
+ name=func.__name__,
122
+ inputs=func_params,
123
+ config=config,
124
+ environment=kwargs["environment"], # type: ignore #NOTE: wrapper is only called in playground
125
+ )
126
+
127
+ llm_result = await execute_function(
128
+ func, *args, params=func_params, config_params=config_params
129
+ )
130
+
131
+ # End trace recording
132
+ tracing.end_recording(
133
+ outputs=llm_result.dict(),
134
+ span=tracing.active_trace,
135
+ )
136
+ return llm_result
137
+
138
+ update_function_signature(wrapper, func_signature, config_params, ingestible_files)
139
+ route = f"/{endpoint_name}"
140
+ app.post(route, response_model=FuncResponse)(wrapper)
141
+
142
+ update_deployed_function_signature(
143
+ wrapper_deployed,
144
+ func_signature,
145
+ ingestible_files,
146
+ )
147
+ route_deployed = f"/{endpoint_name}_deployed"
148
+ app.post(route_deployed, response_model=FuncResponse)(wrapper_deployed)
149
+ override_schema(
150
+ openapi_schema=app.openapi(),
151
+ func_name=func.__name__,
152
+ endpoint=endpoint_name,
153
+ params={**config_params, **func_signature.parameters},
154
+ )
155
+
156
+ if is_main_script(func):
157
+ handle_terminal_run(
158
+ func,
159
+ func_signature.parameters,
160
+ config_params,
161
+ ingestible_files,
162
+ )
163
+ return None
164
+
165
+
166
+ def extract_ingestible_files(
167
+ func_signature: inspect.Signature,
168
+ ) -> Dict[str, inspect.Parameter]:
169
+ """Extract parameters annotated as InFile from function signature."""
170
+
171
+ return {
172
+ name: param
173
+ for name, param in func_signature.parameters.items()
174
+ if param.annotation is InFile
175
+ }
176
+
177
+
178
+ def split_kwargs(
179
+ kwargs: Dict[str, Any], config_params: Dict[str, Any]
180
+ ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
181
+ """Split keyword arguments into function parameters and API configuration parameters."""
182
+
183
+ func_params = {k: v for k, v in kwargs.items() if k not in config_params}
184
+ api_config_params = {k: v for k, v in kwargs.items() if k in config_params}
185
+ return func_params, api_config_params
186
+
187
+
188
+ def ingest_files(
189
+ func_params: Dict[str, Any], ingestible_files: Dict[str, inspect.Parameter]
190
+ ) -> None:
191
+ """Ingest files specified in function parameters."""
192
+
193
+ for name in ingestible_files:
194
+ if name in func_params and func_params[name] is not None:
195
+ func_params[name] = ingest_file(func_params[name])
196
+
197
+
198
+ async def execute_function(func: Callable[..., Any], *args, **func_params):
199
+ """Execute the function and handle any exceptions."""
200
+
201
+ try:
202
+ """Note: The following block is for backward compatibility.
203
+ It allows functions to work seamlessly whether they are synchronous or asynchronous.
204
+ For synchronous functions, it calls them directly, while for asynchronous functions,
205
+ it awaits their execution.
206
+ """
207
+ is_coroutine_function = inspect.iscoroutinefunction(func)
208
+ start_time = time.perf_counter()
209
+ if is_coroutine_function:
210
+ result = await func(*args, **func_params["params"])
211
+ else:
212
+ result = func(*args, **func_params["params"])
213
+
214
+ end_time = time.perf_counter()
215
+ latency = end_time - start_time
216
+
217
+ if isinstance(result, Context):
218
+ save_context(result)
219
+ if isinstance(result, Dict):
220
+ return FuncResponse(**result, latency=round(latency, 4))
221
+ if isinstance(result, str):
222
+ return FuncResponse(message=result, latency=round(latency, 4)) # type: ignore
223
+ except Exception as e:
224
+ handle_exception(e)
225
+ return FuncResponse(message="Unexpected error occurred", latency=0) # type: ignore
226
+
227
+
228
+ def handle_exception(e: Exception):
229
+ """Handle exceptions."""
230
+
231
+ status_code: int = e.status_code if hasattr(e, "status_code") else 500
232
+ traceback_str = traceback.format_exception(e, value=e, tb=e.__traceback__) # type: ignore
233
+ raise HTTPException(
234
+ status_code=status_code,
235
+ detail={"error": str(e), "traceback": "".join(traceback_str)},
236
+ )
237
+
238
+
239
+ def update_wrapper_signature(wrapper: Callable[..., Any], updated_params: List):
240
+ """
241
+ Updates the signature of a wrapper function with a new list of parameters.
242
+
243
+ Args:
244
+ wrapper (callable): A callable object, such as a function or a method, that requires a signature update.
245
+ updated_params (List[inspect.Parameter]): A list of `inspect.Parameter` objects representing the updated parameters
246
+ for the wrapper function.
247
+ """
248
+
249
+ wrapper_signature = inspect.signature(wrapper)
250
+ wrapper_signature = wrapper_signature.replace(parameters=updated_params)
251
+ wrapper.__signature__ = wrapper_signature
252
+
253
+
254
+ def update_function_signature(
255
+ wrapper: Callable[..., Any],
256
+ func_signature: inspect.Signature,
257
+ config_params: Dict[str, Any],
258
+ ingestible_files: Dict[str, inspect.Parameter],
259
+ ) -> None:
260
+ """Update the function signature to include new parameters."""
261
+
262
+ updated_params = []
263
+ add_config_params_to_parser(updated_params, config_params)
264
+ add_func_params_to_parser(updated_params, func_signature, ingestible_files)
265
+ update_wrapper_signature(wrapper, updated_params)
266
+
267
+
268
+ def update_deployed_function_signature(
269
+ wrapper: Callable[..., Any],
270
+ func_signature: inspect.Signature,
271
+ ingestible_files: Dict[str, inspect.Parameter],
272
+ ) -> None:
273
+ """Update the function signature to include new parameters."""
274
+ updated_params = []
275
+ add_func_params_to_parser(updated_params, func_signature, ingestible_files)
276
+ for param in [
277
+ "config",
278
+ "environment",
279
+ ]: # we add the config and environment parameters
280
+ updated_params.append(
281
+ inspect.Parameter(
282
+ param,
283
+ inspect.Parameter.KEYWORD_ONLY,
284
+ default=Body(None),
285
+ annotation=str,
286
+ )
287
+ )
288
+ update_wrapper_signature(wrapper, updated_params)
289
+
290
+
291
+ def add_config_params_to_parser(
292
+ updated_params: list, config_params: Dict[str, Any]
293
+ ) -> None:
294
+ """Add configuration parameters to function signature."""
295
+ for name, param in config_params.items():
296
+ updated_params.append(
297
+ inspect.Parameter(
298
+ name,
299
+ inspect.Parameter.KEYWORD_ONLY,
300
+ default=Body(param),
301
+ annotation=Optional[type(param)],
302
+ )
303
+ )
304
+
305
+
306
+ def add_func_params_to_parser(
307
+ updated_params: list,
308
+ func_signature: inspect.Signature,
309
+ ingestible_files: Dict[str, inspect.Parameter],
310
+ ) -> None:
311
+ """Add function parameters to function signature."""
312
+ for name, param in func_signature.parameters.items():
313
+ if name in ingestible_files:
314
+ updated_params.append(
315
+ inspect.Parameter(name, param.kind, annotation=UploadFile)
316
+ )
317
+ else:
318
+ updated_params.append(
319
+ inspect.Parameter(
320
+ name,
321
+ inspect.Parameter.KEYWORD_ONLY,
322
+ default=Body(..., embed=True),
323
+ annotation=param.annotation,
324
+ )
325
+ )
326
+
327
+
328
+ def is_main_script(func: Callable) -> bool:
329
+ """
330
+ Check if the script containing the function is the main script being run.
331
+
332
+ Args:
333
+ func (Callable): The function object to check.
334
+
335
+ Returns:
336
+ bool: True if the script containing the function is the main script, False otherwise.
337
+
338
+ Example:
339
+ if is_main_script(my_function):
340
+ print("This is the main script.")
341
+ """
342
+ return (
343
+ os.path.splitext(os.path.basename(sys.argv[0]))[0]
344
+ == os.path.splitext(os.path.basename(inspect.getfile(func)))[0]
345
+ )
346
+
347
+
348
+ def handle_terminal_run(
349
+ func: Callable,
350
+ func_params: Dict[str, Any],
351
+ config_params: Dict[str, Any],
352
+ ingestible_files: Dict,
353
+ ) -> None:
354
+ """
355
+ Parses command line arguments and sets configuration when script is run from the terminal.
356
+
357
+ Args:
358
+ func_params (dict): A dictionary containing the function parameters and their annotations.
359
+ config_params (dict): A dictionary containing the configuration parameters.
360
+
361
+ Example:
362
+ handle_terminal_run(func_params=inspect.signature(my_function).parameters, config_params=config.all())
363
+ """
364
+
365
+ # For required parameters, we add them as arguments
366
+ parser = argparse.ArgumentParser()
367
+ for name, param in func_params.items():
368
+ if name in ingestible_files:
369
+ parser.add_argument(name, type=str)
370
+ else:
371
+ parser.add_argument(name, type=param.annotation)
372
+
373
+ for name, param in config_params.items():
374
+ if type(param) is MultipleChoiceParam:
375
+ parser.add_argument(
376
+ f"--{name}",
377
+ type=str,
378
+ default=param.default,
379
+ choices=param.choices,
380
+ )
381
+ else:
382
+ parser.add_argument(
383
+ f"--{name}",
384
+ type=type(param),
385
+ default=param,
386
+ )
387
+
388
+ args = parser.parse_args()
389
+
390
+ # split the arg list into the arg in the app_param and
391
+ # the args from the sig.parameter
392
+ args_config_params = {k: v for k, v in vars(args).items() if k in config_params}
393
+ args_func_params = {k: v for k, v in vars(args).items() if k not in config_params}
394
+ for name in ingestible_files:
395
+ args_func_params[name] = InFile(
396
+ file_name=Path(args_func_params[name]).stem,
397
+ file_path=args_func_params[name],
398
+ )
399
+ agenta.config.set(**args_config_params)
400
+
401
+ loop = asyncio.get_event_loop()
402
+ result = loop.run_until_complete(
403
+ execute_function(
404
+ func, **{"params": args_func_params, "config_params": args_config_params}
405
+ )
406
+ )
407
+ print(result)
408
+
409
+
410
+ def override_schema(openapi_schema: dict, func_name: str, endpoint: str, params: dict):
411
+ """
412
+ Overrides the default openai schema generated by fastapi with additional information about:
413
+ - The choices available for each MultipleChoiceParam instance
414
+ - The min and max values for each FloatParam instance
415
+ - The min and max values for each IntParam instance
416
+ - The default value for DictInput instance
417
+ - The default value for MessagesParam instance
418
+ - The default value for FileInputURL instance
419
+ - The default value for BinaryParam instance
420
+ - ... [PLEASE ADD AT EACH CHANGE]
421
+
422
+ Args:
423
+ openapi_schema (dict): The openapi schema generated by fastapi
424
+ func_name (str): The name of the function to override
425
+ endpoint (str): The name of the endpoint to override
426
+ params (dict(param_name, param_val)): The dictionary of the parameters for the function
427
+ """
428
+
429
+ def find_in_schema(schema: dict, param_name: str, xparam: str):
430
+ """Finds a parameter in the schema based on its name and x-parameter value"""
431
+ for _, value in schema.items():
432
+ value_title_lower = str(value.get("title")).lower()
433
+ value_title = (
434
+ "_".join(value_title_lower.split())
435
+ if len(value_title_lower.split()) >= 2
436
+ else value_title_lower
437
+ )
438
+
439
+ if (
440
+ isinstance(value, dict)
441
+ and value.get("x-parameter") == xparam
442
+ and value_title == param_name
443
+ ):
444
+ return value
445
+
446
+ schema_to_override = openapi_schema["components"]["schemas"][
447
+ f"Body_{func_name}_{endpoint}_post"
448
+ ]["properties"]
449
+ for param_name, param_val in params.items():
450
+ if isinstance(param_val, GroupedMultipleChoiceParam):
451
+ subschema = find_in_schema(schema_to_override, param_name, "grouped_choice")
452
+ assert (
453
+ subschema
454
+ ), f"GroupedMultipleChoiceParam '{param_name}' is in the parameters but could not be found in the openapi.json"
455
+ subschema["choices"] = param_val.choices
456
+ subschema["default"] = param_val.default
457
+ if isinstance(param_val, MultipleChoiceParam):
458
+ subschema = find_in_schema(schema_to_override, param_name, "choice")
459
+ default = str(param_val)
460
+ param_choices = param_val.choices
461
+ choices = (
462
+ [default] + param_choices
463
+ if param_val not in param_choices
464
+ else param_choices
465
+ )
466
+ subschema["enum"] = choices
467
+ subschema["default"] = default if default in param_choices else choices[0]
468
+ if isinstance(param_val, FloatParam):
469
+ subschema = find_in_schema(schema_to_override, param_name, "float")
470
+ subschema["minimum"] = param_val.minval
471
+ subschema["maximum"] = param_val.maxval
472
+ subschema["default"] = param_val
473
+ if isinstance(param_val, IntParam):
474
+ subschema = find_in_schema(schema_to_override, param_name, "int")
475
+ subschema["minimum"] = param_val.minval
476
+ subschema["maximum"] = param_val.maxval
477
+ subschema["default"] = param_val
478
+ if (
479
+ isinstance(param_val, inspect.Parameter)
480
+ and param_val.annotation is DictInput
481
+ ):
482
+ subschema = find_in_schema(schema_to_override, param_name, "dict")
483
+ subschema["default"] = param_val.default["default_keys"]
484
+ if isinstance(param_val, TextParam):
485
+ subschema = find_in_schema(schema_to_override, param_name, "text")
486
+ subschema["default"] = param_val
487
+ if (
488
+ isinstance(param_val, inspect.Parameter)
489
+ and param_val.annotation is MessagesInput
490
+ ):
491
+ subschema = find_in_schema(schema_to_override, param_name, "messages")
492
+ subschema["default"] = param_val.default
493
+ if (
494
+ isinstance(param_val, inspect.Parameter)
495
+ and param_val.annotation is FileInputURL
496
+ ):
497
+ subschema = find_in_schema(schema_to_override, param_name, "file_url")
498
+ subschema["default"] = "https://example.com"
499
+ if isinstance(param_val, BinaryParam):
500
+ subschema = find_in_schema(schema_to_override, param_name, "bool")
501
+ subschema["default"] = param_val.default