agenta 0.48.9__py3-none-any.whl → 0.49.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.
Potentially problematic release.
This version of agenta might be problematic. Click here for more details.
- agenta/__init__.py +3 -2
- agenta/client/Readme.md +258 -80
- agenta/client/__init__.py +205 -29
- agenta/client/backend/__init__.py +461 -0
- agenta/client/backend/access_control/__init__.py +2 -0
- agenta/client/backend/access_control/client.py +53 -73
- agenta/client/backend/access_control/raw_client.py +180 -0
- agenta/client/backend/admin/__init__.py +2 -0
- agenta/client/backend/admin/client.py +473 -268
- agenta/client/backend/admin/raw_client.py +1017 -0
- agenta/client/backend/api_keys/__init__.py +2 -0
- agenta/client/backend/api_keys/client.py +43 -276
- agenta/client/backend/api_keys/raw_client.py +364 -0
- agenta/client/backend/apps/__init__.py +2 -0
- agenta/client/backend/apps/client.py +132 -895
- agenta/client/backend/apps/raw_client.py +1516 -0
- agenta/client/backend/bases/__init__.py +2 -0
- agenta/client/backend/bases/client.py +33 -73
- agenta/client/backend/bases/raw_client.py +179 -0
- agenta/client/backend/billing/__init__.py +3 -0
- agenta/client/backend/billing/client.py +564 -0
- agenta/client/backend/billing/raw_client.py +805 -0
- agenta/client/backend/client.py +1268 -0
- agenta/client/backend/configs/__init__.py +2 -0
- agenta/client/backend/configs/client.py +49 -361
- agenta/client/backend/configs/raw_client.py +402 -0
- agenta/client/backend/containers/__init__.py +1 -3
- agenta/client/backend/containers/client.py +25 -548
- agenta/client/backend/containers/raw_client.py +112 -0
- agenta/client/backend/core/__init__.py +5 -0
- agenta/client/backend/core/api_error.py +12 -6
- agenta/client/backend/core/client_wrapper.py +4 -4
- agenta/client/backend/core/file.py +1 -3
- agenta/client/backend/core/force_multipart.py +16 -0
- agenta/client/backend/core/http_client.py +78 -34
- agenta/client/backend/core/http_response.py +55 -0
- agenta/client/backend/core/jsonable_encoder.py +0 -1
- agenta/client/backend/core/pydantic_utilities.py +88 -113
- agenta/client/backend/core/serialization.py +9 -3
- agenta/client/backend/environment.py +7 -0
- agenta/client/backend/environments/__init__.py +2 -0
- agenta/client/backend/environments/client.py +43 -79
- agenta/client/backend/environments/raw_client.py +193 -0
- agenta/client/backend/errors/__init__.py +2 -0
- agenta/client/backend/errors/unprocessable_entity_error.py +8 -2
- agenta/client/backend/evals/__init__.py +3 -0
- agenta/client/backend/evals/client.py +1042 -0
- agenta/client/backend/evals/raw_client.py +1549 -0
- agenta/client/backend/evaluations/__init__.py +2 -0
- agenta/client/backend/evaluations/client.py +106 -590
- agenta/client/backend/evaluations/raw_client.py +1344 -0
- agenta/client/backend/evaluators/__init__.py +2 -0
- agenta/client/backend/evaluators/client.py +99 -516
- agenta/client/backend/evaluators/raw_client.py +1182 -0
- agenta/client/backend/human_evaluations/__init__.py +2 -0
- agenta/client/backend/human_evaluations/client.py +120 -680
- agenta/client/backend/human_evaluations/raw_client.py +1577 -0
- agenta/client/backend/observability/__init__.py +14 -2
- agenta/client/backend/observability/client.py +185 -341
- agenta/client/backend/observability/raw_client.py +943 -0
- agenta/client/backend/observability/types/__init__.py +10 -2
- agenta/client/backend/observability/types/{format.py → fetch_trace_by_id_request_trace_id.py} +1 -1
- agenta/client/backend/observability/types/fetch_trace_by_id_response.py +15 -0
- agenta/client/backend/observability/types/query_analytics_response.py +2 -1
- agenta/client/backend/observability/types/query_traces_response.py +7 -3
- agenta/client/backend/organization/__init__.py +2 -0
- agenta/client/backend/organization/client.py +105 -361
- agenta/client/backend/organization/raw_client.py +774 -0
- agenta/client/backend/raw_client.py +1432 -0
- agenta/client/backend/scopes/__init__.py +2 -0
- agenta/client/backend/scopes/client.py +31 -45
- agenta/client/backend/scopes/raw_client.py +105 -0
- agenta/client/backend/testsets/__init__.py +14 -0
- agenta/client/backend/testsets/client.py +1098 -653
- agenta/client/backend/testsets/raw_client.py +2348 -0
- agenta/client/backend/testsets/types/__init__.py +17 -0
- agenta/client/backend/testsets/types/create_testset_from_file_request_file_type.py +7 -0
- agenta/client/backend/testsets/types/fetch_testset_to_file_request_file_type.py +7 -0
- agenta/client/backend/testsets/types/update_testset_from_file_request_file_type.py +7 -0
- agenta/client/backend/tracing/__init__.py +7 -0
- agenta/client/backend/tracing/client.py +782 -0
- agenta/client/backend/tracing/raw_client.py +1223 -0
- agenta/client/backend/tracing/types/__init__.py +8 -0
- agenta/client/backend/{types/variant_action_enum.py → tracing/types/fetch_trace_request_trace_id.py} +1 -1
- agenta/client/backend/tracing/types/remove_trace_request_trace_id.py +5 -0
- agenta/client/backend/types/__init__.py +153 -26
- agenta/client/backend/types/account_request.py +24 -0
- agenta/client/backend/types/account_response.py +5 -7
- agenta/client/backend/types/agenta_node_dto.py +13 -13
- agenta/client/backend/types/agenta_node_dto_nodes_value.py +1 -0
- agenta/client/backend/types/agenta_nodes_response.py +14 -8
- agenta/client/backend/types/agenta_root_dto.py +16 -8
- agenta/client/backend/types/agenta_roots_response.py +16 -8
- agenta/client/backend/types/agenta_tree_dto.py +16 -8
- agenta/client/backend/types/agenta_trees_response.py +16 -8
- agenta/client/backend/types/aggregated_result.py +5 -7
- agenta/client/backend/types/aggregated_result_evaluator_config.py +1 -0
- agenta/client/backend/types/analytics_response.py +4 -6
- agenta/client/backend/types/annotation.py +50 -0
- agenta/client/backend/types/annotation_create.py +39 -0
- agenta/client/backend/types/annotation_edit.py +31 -0
- agenta/client/backend/types/annotation_kind.py +5 -0
- agenta/client/backend/types/{uri.py → annotation_link.py} +6 -7
- agenta/client/backend/types/{provider_key_dto.py → annotation_link_response.py} +6 -7
- agenta/client/backend/types/annotation_query.py +40 -0
- agenta/client/backend/types/annotation_query_request.py +20 -0
- agenta/client/backend/types/annotation_reference.py +21 -0
- agenta/client/backend/types/annotation_references.py +22 -0
- agenta/client/backend/types/{docker_env_vars.py → annotation_response.py} +6 -7
- agenta/client/backend/types/annotation_source.py +5 -0
- agenta/client/backend/types/annotations_response.py +24 -0
- agenta/client/backend/types/app.py +3 -5
- agenta/client/backend/types/app_variant_response.py +3 -6
- agenta/client/backend/types/app_variant_revision.py +5 -6
- agenta/client/backend/types/artifact.py +44 -0
- agenta/client/backend/types/base_output.py +3 -5
- agenta/client/backend/types/body_fetch_workflow_revision.py +21 -0
- agenta/client/backend/types/body_import_testset.py +3 -5
- agenta/client/backend/types/bucket_dto.py +4 -6
- agenta/client/backend/types/collect_status_response.py +3 -5
- agenta/client/backend/types/config_db.py +3 -5
- agenta/client/backend/types/config_dto.py +5 -7
- agenta/client/backend/types/config_response_model.py +5 -7
- agenta/client/backend/types/correct_answer.py +3 -5
- agenta/client/backend/types/create_app_output.py +3 -5
- agenta/client/backend/types/custom_model_settings_dto.py +3 -5
- agenta/client/backend/types/custom_provider_dto.py +6 -9
- agenta/client/backend/types/custom_provider_kind.py +5 -5
- agenta/client/backend/types/custom_provider_settings_dto.py +3 -5
- agenta/client/backend/types/data.py +2 -1
- agenta/client/backend/types/delete_evaluation.py +3 -5
- agenta/client/backend/types/environment_output.py +3 -5
- agenta/client/backend/types/environment_output_extended.py +4 -6
- agenta/client/backend/types/environment_revision.py +5 -5
- agenta/client/backend/types/error.py +3 -5
- agenta/client/backend/types/evaluation.py +6 -8
- agenta/client/backend/types/evaluation_scenario.py +5 -7
- agenta/client/backend/types/evaluation_scenario_input.py +3 -5
- agenta/client/backend/types/evaluation_scenario_output.py +4 -6
- agenta/client/backend/types/evaluation_scenario_result.py +4 -6
- agenta/client/backend/types/evaluator.py +31 -12
- agenta/client/backend/types/evaluator_config.py +3 -5
- agenta/client/backend/types/evaluator_flags.py +21 -0
- agenta/client/backend/types/evaluator_mapping_output_interface.py +3 -5
- agenta/client/backend/types/evaluator_output_interface.py +3 -5
- agenta/client/backend/types/evaluator_query.py +32 -0
- agenta/client/backend/types/evaluator_query_request.py +30 -0
- agenta/client/backend/types/evaluator_request.py +20 -0
- agenta/client/backend/types/evaluator_response.py +21 -0
- agenta/client/backend/types/evaluators_response.py +21 -0
- agenta/client/backend/types/exception_dto.py +3 -5
- agenta/client/backend/types/{o_tel_spans_response.py → extended_o_tel_tracing_response.py} +5 -7
- agenta/client/backend/types/focus.py +5 -0
- agenta/client/backend/types/format.py +5 -0
- agenta/client/backend/types/full_json_input.py +34 -0
- agenta/client/backend/types/full_json_output.py +29 -0
- agenta/client/backend/types/get_config_response.py +3 -5
- agenta/client/backend/types/{header_dto.py → header.py} +4 -6
- agenta/client/backend/types/http_validation_error.py +4 -6
- agenta/client/backend/types/human_evaluation.py +3 -5
- agenta/client/backend/types/human_evaluation_scenario.py +4 -6
- agenta/client/backend/types/human_evaluation_scenario_input.py +3 -5
- agenta/client/backend/types/human_evaluation_scenario_output.py +3 -5
- agenta/client/backend/types/invite_request.py +4 -6
- agenta/client/backend/types/legacy_analytics_response.py +4 -6
- agenta/client/backend/types/legacy_data_point.py +3 -5
- agenta/client/backend/types/legacy_evaluator.py +26 -0
- agenta/client/backend/types/legacy_scope_request.py +4 -6
- agenta/client/backend/types/legacy_scopes_response.py +3 -5
- agenta/client/backend/types/legacy_subscription_request.py +19 -0
- agenta/client/backend/types/legacy_user_request.py +5 -7
- agenta/client/backend/types/legacy_user_response.py +3 -5
- agenta/client/backend/types/lifecycle_dto.py +3 -5
- agenta/client/backend/types/link_dto.py +4 -6
- agenta/client/backend/types/list_api_keys_response.py +3 -5
- agenta/client/backend/types/llm_run_rate_limit.py +3 -5
- agenta/client/backend/types/meta_request.py +30 -0
- agenta/client/backend/types/metrics_dto.py +3 -5
- agenta/client/backend/types/new_testset.py +3 -5
- agenta/client/backend/types/node_dto.py +4 -6
- agenta/client/backend/types/o_tel_context_dto.py +3 -5
- agenta/client/backend/types/o_tel_event.py +35 -0
- agenta/client/backend/types/o_tel_event_dto.py +3 -5
- agenta/client/backend/types/o_tel_extra_dto.py +4 -6
- agenta/client/backend/types/o_tel_flat_span.py +56 -0
- agenta/client/backend/types/o_tel_flat_span_input_end_time.py +6 -0
- agenta/client/backend/types/o_tel_flat_span_input_start_time.py +6 -0
- agenta/client/backend/types/o_tel_flat_span_output_end_time.py +6 -0
- agenta/client/backend/types/o_tel_flat_span_output_start_time.py +6 -0
- agenta/client/backend/types/o_tel_link.py +34 -0
- agenta/client/backend/types/o_tel_link_dto.py +4 -6
- agenta/client/backend/types/o_tel_links_response.py +22 -0
- agenta/client/backend/types/o_tel_span.py +58 -0
- agenta/client/backend/types/o_tel_span_dto.py +8 -10
- agenta/client/backend/types/o_tel_span_input_end_time.py +6 -0
- agenta/client/backend/types/o_tel_span_input_spans_value.py +7 -0
- agenta/client/backend/types/o_tel_span_input_start_time.py +6 -0
- agenta/client/backend/types/o_tel_span_output_end_time.py +6 -0
- agenta/client/backend/types/o_tel_span_output_spans_value.py +30 -0
- agenta/client/backend/types/o_tel_span_output_start_time.py +6 -0
- agenta/client/backend/types/o_tel_spans_tree.py +22 -0
- agenta/client/backend/types/o_tel_spans_tree_input_spans_value.py +7 -0
- agenta/client/backend/types/o_tel_spans_tree_output_spans_value.py +5 -0
- agenta/client/backend/types/o_tel_status_code.py +1 -1
- agenta/client/backend/types/o_tel_tracing_data_response.py +22 -0
- agenta/client/backend/types/o_tel_tracing_request.py +22 -0
- agenta/client/backend/types/o_tel_tracing_response.py +27 -0
- agenta/client/backend/types/organization.py +3 -5
- agenta/client/backend/types/organization_details.py +3 -5
- agenta/client/backend/types/organization_membership_request.py +5 -7
- agenta/client/backend/types/organization_output.py +3 -5
- agenta/client/backend/types/organization_request.py +3 -5
- agenta/client/backend/types/parent_dto.py +3 -5
- agenta/client/backend/types/permission.py +11 -0
- agenta/client/backend/types/plan.py +14 -0
- agenta/client/backend/types/project_membership_request.py +5 -7
- agenta/client/backend/types/project_request.py +4 -6
- agenta/client/backend/types/project_scope.py +5 -7
- agenta/client/backend/types/projects_response.py +3 -5
- agenta/client/backend/types/recursive_types.py +23 -0
- agenta/client/backend/types/reference.py +18 -5
- agenta/client/backend/types/reference_dto.py +4 -5
- agenta/client/backend/types/reference_request_model.py +4 -5
- agenta/client/backend/types/result.py +4 -6
- agenta/client/backend/types/root_dto.py +3 -5
- agenta/client/backend/types/scopes_response_model.py +4 -6
- agenta/client/backend/types/secret_dto.py +5 -7
- agenta/client/backend/types/secret_response_dto.py +11 -11
- agenta/client/backend/types/simple_evaluation_output.py +4 -6
- agenta/client/backend/types/span_dto.py +18 -14
- agenta/client/backend/types/span_dto_nodes_value.py +1 -1
- agenta/client/backend/types/standard_provider_dto.py +5 -7
- agenta/client/backend/types/standard_provider_settings_dto.py +3 -5
- agenta/client/backend/types/status_dto.py +4 -6
- agenta/client/backend/types/tags_request.py +30 -0
- agenta/client/backend/types/test_set_output_response.py +5 -7
- agenta/client/backend/types/test_set_simple_response.py +3 -5
- agenta/client/backend/types/testcase_response.py +33 -0
- agenta/client/backend/types/testset.py +46 -0
- agenta/client/backend/types/testset_request.py +20 -0
- agenta/client/backend/types/testset_response.py +21 -0
- agenta/client/backend/types/testsets_response.py +21 -0
- agenta/client/backend/types/time_dto.py +3 -5
- agenta/client/backend/types/timestamp.py +6 -0
- agenta/client/backend/types/tree_dto.py +4 -6
- agenta/client/backend/types/update_app_output.py +3 -5
- agenta/client/backend/types/user_request.py +3 -5
- agenta/client/backend/types/validation_error.py +4 -6
- agenta/client/backend/types/workflow_artifact.py +45 -0
- agenta/client/backend/types/workflow_data.py +20 -0
- agenta/client/backend/types/workflow_flags.py +21 -0
- agenta/client/backend/types/workflow_request.py +20 -0
- agenta/client/backend/types/workflow_response.py +21 -0
- agenta/client/backend/types/workflow_revision.py +57 -0
- agenta/client/backend/types/workflow_revision_request.py +20 -0
- agenta/client/backend/types/workflow_revision_response.py +21 -0
- agenta/client/backend/types/workflow_revisions_response.py +21 -0
- agenta/client/backend/types/workflow_variant.py +48 -0
- agenta/client/backend/types/workflow_variant_request.py +20 -0
- agenta/client/backend/types/workflow_variant_response.py +21 -0
- agenta/client/backend/types/workflow_variants_response.py +21 -0
- agenta/client/backend/types/workflows_response.py +21 -0
- agenta/client/backend/types/workspace.py +3 -5
- agenta/client/backend/types/workspace_member_response.py +4 -6
- agenta/client/backend/types/workspace_membership_request.py +5 -7
- agenta/client/backend/types/workspace_permission.py +5 -7
- agenta/client/backend/types/workspace_request.py +4 -6
- agenta/client/backend/types/workspace_response.py +4 -6
- agenta/client/backend/variants/__init__.py +2 -0
- agenta/client/backend/variants/client.py +306 -1651
- agenta/client/backend/variants/raw_client.py +2482 -0
- agenta/client/backend/variants/types/__init__.py +2 -0
- agenta/client/backend/variants/types/add_variant_from_base_and_config_response.py +1 -0
- agenta/client/backend/vault/__init__.py +2 -0
- agenta/client/backend/vault/client.py +69 -323
- agenta/client/backend/vault/raw_client.py +616 -0
- agenta/client/backend/workflows/__init__.py +3 -0
- agenta/client/backend/workflows/client.py +2398 -0
- agenta/client/backend/workflows/raw_client.py +3639 -0
- agenta/client/backend/workspace/__init__.py +2 -0
- agenta/client/backend/workspace/client.py +46 -147
- agenta/client/backend/workspace/raw_client.py +376 -0
- agenta/client/types.py +4 -0
- agenta/sdk/litellm/mocks/__init__.py +144 -0
- agenta/sdk/middleware/auth.py +26 -25
- agenta/sdk/types.py +28 -1
- {agenta-0.48.9.dist-info → agenta-0.49.0.dist-info}/METADATA +1 -1
- agenta-0.49.0.dist-info/RECORD +362 -0
- agenta/client/backend/containers/types/__init__.py +0 -5
- agenta/client/backend/containers/types/container_templates_response.py +0 -6
- agenta/client/backend/types/image.py +0 -25
- agenta/client/backend/types/provider_kind.py +0 -21
- agenta/client/backend/types/template.py +0 -23
- agenta/client/backend/types/template_image_info.py +0 -29
- agenta/client/backend/types/variant_action.py +0 -22
- agenta-0.48.9.dist-info/RECORD +0 -255
- {agenta-0.48.9.dist-info → agenta-0.49.0.dist-info}/WHEEL +0 -0
agenta/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@ from typing import Any, Callable, Optional
|
|
|
2
2
|
|
|
3
3
|
from .sdk.utils.preinit import PreInitObject
|
|
4
4
|
|
|
5
|
+
from agenta.client import AgentaApi, AsyncAgentaApi
|
|
5
6
|
import agenta.client.backend.types as client_types # pylint: disable=wrong-import-order
|
|
6
7
|
|
|
7
8
|
from .sdk.types import (
|
|
@@ -42,8 +43,8 @@ DEFAULT_AGENTA_SINGLETON_INSTANCE = AgentaSingleton()
|
|
|
42
43
|
|
|
43
44
|
types = client_types
|
|
44
45
|
|
|
45
|
-
api =
|
|
46
|
-
async_api =
|
|
46
|
+
api = AgentaApi
|
|
47
|
+
async_api = AsyncAgentaApi
|
|
47
48
|
|
|
48
49
|
tracing = DEFAULT_AGENTA_SINGLETON_INSTANCE.tracing # type: ignore
|
|
49
50
|
tracer = get_tracer(tracing)
|
agenta/client/Readme.md
CHANGED
|
@@ -1,104 +1,282 @@
|
|
|
1
|
-
|
|
1
|
+
# Common Fern Issues with Pydantic Models
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
When using Fern to generate SDKs from FastAPI applications with Pydantic models, you may encounter several issues related to model naming conflicts, schema generation, and recursive type definitions. This document outlines the most common problems and their solutions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Issue 1: Model Name Conflicts
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Problem Description
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
When you have multiple Pydantic models with the same name across different modules/folders and are used by different endpoints, Fern merges them into a single schema, causing field conflicts and unexpected behaviour.
|
|
10
|
+
|
|
11
|
+
**Example:**
|
|
12
|
+
```python
|
|
13
|
+
# users/models.py
|
|
14
|
+
class User(BaseModel):
|
|
15
|
+
id: int
|
|
16
|
+
username: str
|
|
17
|
+
email: str
|
|
18
|
+
|
|
19
|
+
# admin_users/models.py
|
|
20
|
+
class User(BaseModel):
|
|
21
|
+
id: int
|
|
22
|
+
username: str
|
|
23
|
+
permissions: List[str]
|
|
24
|
+
is_admin: bool
|
|
12
25
|
```
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
Fern will merge these into one `User` schema, and when you run the `fern generate` command, it results in an error that involves conflicting field definitions.
|
|
28
|
+
|
|
29
|
+
### Solutions
|
|
30
|
+
|
|
31
|
+
#### Solution 1: Use Unique Model Names
|
|
32
|
+
|
|
33
|
+
Rename your models to be more specific and avoid conflicts:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# users/models.py
|
|
37
|
+
class RegularUser(BaseModel):
|
|
38
|
+
id: int
|
|
39
|
+
username: str
|
|
40
|
+
email: str
|
|
41
|
+
|
|
42
|
+
# admin_users/models.py
|
|
43
|
+
class AdminUser(BaseModel):
|
|
44
|
+
id: int
|
|
45
|
+
username: str
|
|
46
|
+
permissions: List[str]
|
|
47
|
+
is_admin: bool
|
|
17
48
|
```
|
|
18
49
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
#### Solution 2: Use Pydantic's `model_config` with Custom Titles
|
|
51
|
+
|
|
52
|
+
Override the schema title to make models unique:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
# users/models.py
|
|
56
|
+
class User(BaseModel):
|
|
57
|
+
model_config = ConfigDict(title="RegularUser")
|
|
58
|
+
|
|
59
|
+
id: int
|
|
60
|
+
username: str
|
|
61
|
+
email: str
|
|
62
|
+
|
|
63
|
+
# admin_users/models.py
|
|
64
|
+
class User(BaseModel):
|
|
65
|
+
model_config = ConfigDict(title="AdminUser")
|
|
66
|
+
|
|
67
|
+
id: int
|
|
68
|
+
username: str
|
|
69
|
+
permissions: List[str]
|
|
70
|
+
is_admin: bool
|
|
34
71
|
```
|
|
35
72
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
73
|
+
#### Solution 3: Use Module-Prefixed Aliases
|
|
74
|
+
|
|
75
|
+
Create type aliases that include module context:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# users/models.py
|
|
79
|
+
class User(BaseModel):
|
|
80
|
+
id: int
|
|
81
|
+
username: str
|
|
82
|
+
email: str
|
|
83
|
+
|
|
84
|
+
# Create an alias for external use
|
|
85
|
+
UserModel = User
|
|
86
|
+
|
|
87
|
+
# admin_users/models.py
|
|
88
|
+
class User(BaseModel):
|
|
89
|
+
id: int
|
|
90
|
+
username: str
|
|
91
|
+
permissions: List[str]
|
|
92
|
+
is_admin: bool
|
|
93
|
+
|
|
94
|
+
# Create an alias for external use
|
|
95
|
+
AdminUserModel = User
|
|
49
96
|
```
|
|
50
97
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
98
|
+
Then use the aliases in your endpoints:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from users.models import UserModel
|
|
102
|
+
from admin_users.models import AdminUserModel
|
|
103
|
+
|
|
104
|
+
@app.get("/users/{user_id}", response_model=UserModel)
|
|
105
|
+
async def get_user(user_id: int):
|
|
106
|
+
# ...
|
|
107
|
+
|
|
108
|
+
@app.get("/admin/users/{user_id}", response_model=AdminUserModel)
|
|
109
|
+
async def get_admin_user(user_id: int):
|
|
110
|
+
# ...
|
|
59
111
|
```
|
|
60
112
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
113
|
+
## Issue 2: Enum Schema Generation
|
|
114
|
+
|
|
115
|
+
### Problem Description
|
|
116
|
+
|
|
117
|
+
When multiple Pydantic models reference the same Enum, Fern doesn't create a shared enum schema and instead inlines the enum values in each model, leading to code duplication and inconsistency.
|
|
118
|
+
|
|
119
|
+
**Example:**
|
|
120
|
+
```python
|
|
121
|
+
class Status(Enum):
|
|
122
|
+
ACTIVE = "active"
|
|
123
|
+
INACTIVE = "inactive"
|
|
124
|
+
PENDING = "pending"
|
|
125
|
+
|
|
126
|
+
class User(BaseModel):
|
|
127
|
+
id: int
|
|
128
|
+
status: Status
|
|
129
|
+
|
|
130
|
+
class Order(BaseModel):
|
|
131
|
+
id: int
|
|
132
|
+
status: Status # Same enum, but Fern will not reuse the schema
|
|
72
133
|
```
|
|
73
|
-
<img width="1001" alt="image" src="https://github.com/Agenta-AI/agenta/assets/56418363/f537691d-8dbb-4363-b7c0-ecef9f464053">
|
|
74
134
|
|
|
135
|
+
### Solutions
|
|
75
136
|
|
|
76
|
-
|
|
77
|
-
<img width="593" alt="image" src="https://github.com/Agenta-AI/agenta/assets/56418363/0f44255e-50b5-4d78-863b-d33a3ec2eea0">
|
|
137
|
+
#### Solution 1: Explicit Schema Registration
|
|
78
138
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
|
|
139
|
+
Force Pydantic to generate a proper schema reference by using the enum in a standalone model first:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from enum import Enum
|
|
143
|
+
from typing import Union
|
|
144
|
+
from pydantic import BaseModel
|
|
145
|
+
|
|
146
|
+
class Status(str, Enum):
|
|
147
|
+
ACTIVE = "active"
|
|
148
|
+
INACTIVE = "inactive"
|
|
149
|
+
PENDING = "pending"
|
|
150
|
+
|
|
151
|
+
# Create a dedicated schema model
|
|
152
|
+
class StatusSchema(BaseModel):
|
|
153
|
+
status: Status
|
|
154
|
+
|
|
155
|
+
class User(BaseModel):
|
|
156
|
+
id: int
|
|
157
|
+
status: Status
|
|
158
|
+
|
|
159
|
+
class Order(BaseModel):
|
|
160
|
+
id: int
|
|
161
|
+
status: Status
|
|
83
162
|
```
|
|
84
163
|
|
|
85
|
-
|
|
164
|
+
#### Solution 2: Use Field with Schema Customization
|
|
165
|
+
|
|
166
|
+
Customize the field schema to ensure proper enum handling:
|
|
167
|
+
|
|
86
168
|
```python
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
169
|
+
from pydantic import BaseModel, Field
|
|
170
|
+
from enum import Enum
|
|
171
|
+
|
|
172
|
+
class Status(str, Enum):
|
|
173
|
+
ACTIVE = "active"
|
|
174
|
+
INACTIVE = "inactive"
|
|
175
|
+
PENDING = "pending"
|
|
176
|
+
|
|
177
|
+
class User(BaseModel):
|
|
178
|
+
id: int
|
|
179
|
+
status: Status = Field(
|
|
180
|
+
...,
|
|
181
|
+
json_schema_extra={
|
|
182
|
+
"$ref": "#/components/schemas/Status"
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
class Order(BaseModel):
|
|
187
|
+
id: int
|
|
188
|
+
status: Status = Field(
|
|
189
|
+
...,
|
|
190
|
+
json_schema_extra={
|
|
191
|
+
"$ref": "#/components/schemas/Status"
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Issue 3: Recursive Type Definitions
|
|
197
|
+
|
|
198
|
+
### Problem Description
|
|
199
|
+
|
|
200
|
+
When using recursive type definitions with Pydantic v2 and Fern-generated SDKs, you may encounter infinite recursion during schema generation. This happens particularly with self-referential or mutually recursive types, such as JSON structures that can contain nested versions of themselves.
|
|
201
|
+
|
|
202
|
+
**Example of problematic recursive type definitions:**
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from typing_extensions import TypeAliasType
|
|
206
|
+
from typing import Union, Dict, List
|
|
207
|
+
|
|
208
|
+
# This approach causes infinite recursion during schema generation
|
|
209
|
+
OTelJson: TypeAliasType = TypeAliasType(
|
|
210
|
+
"OTelJson",
|
|
211
|
+
Union[str, int, float, bool, None, Dict[str, "OTelJson"], List["OTelJson"]],
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
OTelNumericJson: TypeAliasType = TypeAliasType(
|
|
215
|
+
"OTelNumericJson",
|
|
216
|
+
Union[int, float, Dict[str, "OTelNumericJson"], List["OTelNumericJson"]],
|
|
100
217
|
)
|
|
101
218
|
```
|
|
102
|
-
<img width="995" alt="image" src="https://github.com/Agenta-AI/agenta/assets/56418363/8fab19e3-5226-405b-8a6f-4dcb6df588c9">
|
|
103
219
|
|
|
104
|
-
|
|
220
|
+
Despite `TypeAliasType` being recommended in Pydantic v2 documentation for recursive types, it doesn't work well with Fern-generated models because:
|
|
221
|
+
|
|
222
|
+
1. Fern's model generation may not properly handle these recursive references
|
|
223
|
+
2. During schema generation, Pydantic attempts to expand these types infinitely
|
|
224
|
+
3. Runtime errors occur during initialization or when creating JSON schemas
|
|
225
|
+
|
|
226
|
+
### Solutions
|
|
227
|
+
|
|
228
|
+
#### Solution: Break Recursion with `Any` Type
|
|
229
|
+
|
|
230
|
+
Replace recursive self-references with `Any` for dictionary values and list items:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from typing import Any, Union, Dict, List
|
|
234
|
+
|
|
235
|
+
# Safe non-recursive version that prevents schema generation issues
|
|
236
|
+
OTelJson = Union[str, int, float, bool, None, Dict[str, Any], List[Any]]
|
|
237
|
+
|
|
238
|
+
# Using Any to break recursion cycle during schema generation
|
|
239
|
+
OTelNumericJson = Union[int, float, Dict[str, Any], List[Any]]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### Why This Works
|
|
243
|
+
|
|
244
|
+
1. **Breaks the recursion cycle**: Using `Any` eliminates the self-reference that causes infinite recursion
|
|
245
|
+
2. **Maintains functionality**: The types still functionally represent nested JSON structures
|
|
246
|
+
3. **No schema generation issues**: Pydantic can generate schemas without infinite expansion
|
|
247
|
+
4. **Simple implementation**: Requires no complex patches or runtime modifications
|
|
248
|
+
|
|
249
|
+
#### What to Avoid
|
|
250
|
+
|
|
251
|
+
1. **Don't use complex monkey patching**: Patching Pydantic internals to handle recursion is fragile
|
|
252
|
+
2. **Avoid disabling schema generation globally**: This impacts all models and API documentation
|
|
253
|
+
3. **Don't use custom serialization for every model**: Introduces unnecessary complexity
|
|
254
|
+
|
|
255
|
+
When Fern generates your SDK, always check for recursive type definitions and convert them to use `Any` at appropriate recursion points to prevent these issues.
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
## Troubleshooting
|
|
259
|
+
|
|
260
|
+
### Debug Schema Generation
|
|
261
|
+
|
|
262
|
+
Add debugging to see what schemas are being generated:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
import json
|
|
266
|
+
from your_app import app
|
|
267
|
+
|
|
268
|
+
# Generate and inspect OpenAPI schema
|
|
269
|
+
schema = app.openapi()
|
|
270
|
+
with open("debug_openapi.json", "w") as f:
|
|
271
|
+
json.dump(schema, f, indent=2)
|
|
272
|
+
|
|
273
|
+
# Check for duplicate schemas
|
|
274
|
+
schemas = schema.get("components", {}).get("schemas", {})
|
|
275
|
+
print("Generated schemas:", list(schemas.keys()))
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Common Error Patterns
|
|
279
|
+
|
|
280
|
+
1. **"Schema conflict"** - Usually indicates duplicate model names
|
|
281
|
+
2. **"Enum already exists"** - Enum not properly registered in other components/schemas
|
|
282
|
+
3. **"Field type mismatch"** - Different models with same name have conflicting fields
|