diff --git a/.sdk-version b/.sdk-version index c1e14a1..a65f4e9 100644 --- a/.sdk-version +++ b/.sdk-version @@ -1 +1 @@ -v4.67.1 +v4.69.0 diff --git a/README.md b/README.md index d75697b..06a4580 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,8 @@ Class | Method | HTTP request | Description *FunctionsAIDecompilationApi* | [**v3_get_ai_decompilation_rating**](docs/FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_rating) | **GET** /v3/functions/{function_id}/ai-decompilation/rating | Get AI decompilation rating *FunctionsAIDecompilationApi* | [**v3_get_ai_decompilation_tokens**](docs/FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_tokens) | **GET** /v3/functions/{function_id}/ai-decompilation/tokens | Get AI decompilation tokens and user overrides *FunctionsAIDecompilationApi* | [**v3_get_ai_decompilation_type_suggestions**](docs/FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_type_suggestions) | **GET** /v3/functions/{function_id}/ai-decompilation/type-suggestions | Get AI decompilation type suggestions +*FunctionsAIDecompilationApi* | [**v3_get_ai_decompilation_type_suggestions_status**](docs/FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_type_suggestions_status) | **GET** /v3/functions/{function_id}/ai-decompilation/type-suggestions/status | Get type suggestion workflow status +*FunctionsAIDecompilationApi* | [**v3_regenerate_ai_decompilation_type_suggestions**](docs/FunctionsAIDecompilationApi.md#v3_regenerate_ai_decompilation_type_suggestions) | **POST** /v3/functions/{function_id}/ai-decompilation/type-suggestions | Regenerate AI decompilation type suggestions *FunctionsAIDecompilationApi* | [**v3_upsert_ai_decompilation_overrides**](docs/FunctionsAIDecompilationApi.md#v3_upsert_ai_decompilation_overrides) | **PATCH** /v3/functions/{function_id}/ai-decompilation/overrides | Upsert variable/function name overrides *FunctionsAIDecompilationApi* | [**v3_upsert_ai_decompilation_rating**](docs/FunctionsAIDecompilationApi.md#v3_upsert_ai_decompilation_rating) | **PATCH** /v3/functions/{function_id}/ai-decompilation/rating | Upsert AI decompilation rating *FunctionsCoreApi* | [**add_function_callee**](docs/FunctionsCoreApi.md#add_function_callee) | **POST** /v3/functions/{function_id}/callees | Add a callee to a function @@ -606,6 +608,7 @@ Class | Method | HTTP request | Description - [EventTOOLCALLRESULT](docs/EventTOOLCALLRESULT.md) - [EventTOOLCALLSTART](docs/EventTOOLCALLSTART.md) - [EventTOOLCONFIRMATIONREQUIRED](docs/EventTOOLCONFIRMATIONREQUIRED.md) + - [EventTypesApplied](docs/EventTypesApplied.md) - [EventTypesSuggested](docs/EventTypesSuggested.md) - [EventWarning](docs/EventWarning.md) - [EvidenceEffect](docs/EvidenceEffect.md) @@ -979,6 +982,7 @@ Class | Method | HTTP request | Description - [TypeSuggestionsData](docs/TypeSuggestionsData.md) - [TypedefDataType](docs/TypedefDataType.md) - [TypedefDefinition](docs/TypedefDefinition.md) + - [TypesAppliedEvent](docs/TypesAppliedEvent.md) - [TypesSuggestedEvent](docs/TypesSuggestedEvent.md) - [UnionDataType](docs/UnionDataType.md) - [UnionDefinition](docs/UnionDefinition.md) diff --git a/docs/AcceptTypeSuggestionsOutputBody.md b/docs/AcceptTypeSuggestionsOutputBody.md index e63f713..21c0171 100644 --- a/docs/AcceptTypeSuggestionsOutputBody.md +++ b/docs/AcceptTypeSuggestionsOutputBody.md @@ -5,7 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**accepted** | [**List[AcceptedType]**](AcceptedType.md) | One entry per requested suggestion, in request order. | +**accepted** | [**List[AcceptedType]**](AcceptedType.md) | One entry per requested suggestion that had a shape to store, in request order. | **data_types** | [**List[DataTypeEntry]**](DataTypeEntry.md) | The type each requested suggestion resolved to, plus every type minted to satisfy one, ordered by data_type_id. | ## Example diff --git a/docs/EventTypesApplied.md b/docs/EventTypesApplied.md new file mode 100644 index 0000000..eba5478 --- /dev/null +++ b/docs/EventTypesApplied.md @@ -0,0 +1,32 @@ +# EventTypesApplied + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**data** | [**TypesAppliedEvent**](TypesAppliedEvent.md) | | +**event** | **str** | The event name. | +**id** | **int** | The event ID. | [optional] +**retry** | **int** | The retry time in milliseconds. | [optional] + +## Example + +```python +from revengai.models.event_types_applied import EventTypesApplied + +# TODO update the JSON string below +json = "{}" +# create an instance of EventTypesApplied from a JSON string +event_types_applied_instance = EventTypesApplied.from_json(json) +# print the JSON string representation of the object +print(EventTypesApplied.to_json()) + +# convert the object into a dict +event_types_applied_dict = event_types_applied_instance.to_dict() +# create an instance of EventTypesApplied from a dict +event_types_applied_from_dict = EventTypesApplied.from_dict(event_types_applied_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/FunctionsAIDecompilationApi.md b/docs/FunctionsAIDecompilationApi.md index b15d57f..d37f69c 100644 --- a/docs/FunctionsAIDecompilationApi.md +++ b/docs/FunctionsAIDecompilationApi.md @@ -23,12 +23,14 @@ Method | HTTP request | Description [**v3_get_ai_decompilation_rating**](FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_rating) | **GET** /v3/functions/{function_id}/ai-decompilation/rating | Get AI decompilation rating [**v3_get_ai_decompilation_tokens**](FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_tokens) | **GET** /v3/functions/{function_id}/ai-decompilation/tokens | Get AI decompilation tokens and user overrides [**v3_get_ai_decompilation_type_suggestions**](FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_type_suggestions) | **GET** /v3/functions/{function_id}/ai-decompilation/type-suggestions | Get AI decompilation type suggestions +[**v3_get_ai_decompilation_type_suggestions_status**](FunctionsAIDecompilationApi.md#v3_get_ai_decompilation_type_suggestions_status) | **GET** /v3/functions/{function_id}/ai-decompilation/type-suggestions/status | Get type suggestion workflow status +[**v3_regenerate_ai_decompilation_type_suggestions**](FunctionsAIDecompilationApi.md#v3_regenerate_ai_decompilation_type_suggestions) | **POST** /v3/functions/{function_id}/ai-decompilation/type-suggestions | Regenerate AI decompilation type suggestions [**v3_upsert_ai_decompilation_overrides**](FunctionsAIDecompilationApi.md#v3_upsert_ai_decompilation_overrides) | **PATCH** /v3/functions/{function_id}/ai-decompilation/overrides | Upsert variable/function name overrides [**v3_upsert_ai_decompilation_rating**](FunctionsAIDecompilationApi.md#v3_upsert_ai_decompilation_rating) | **PATCH** /v3/functions/{function_id}/ai-decompilation/rating | Upsert AI decompilation rating # **create_ai_decompilation** -> CreateAIDecompOutputBody create_ai_decompilation(function_id, temperature=temperature, type_suggestions=type_suggestions) +> CreateAIDecompOutputBody create_ai_decompilation(function_id, temperature=temperature, type_suggestions=type_suggestions, apply_types=apply_types) Start AI decompilation @@ -80,10 +82,11 @@ with revengai.ApiClient(configuration) as api_client: function_id = 56 # int | Function ID temperature = -1 # float | LLM temperature (0.0-1.0). Overrides the server default when set. Omit or set to -1 to use the server default. (optional) (default to -1) type_suggestions = True # bool | Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off. (optional) (default to True) + apply_types = True # bool | Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. (optional) (default to True) try: # Start AI decompilation - api_response = api_instance.create_ai_decompilation(function_id, temperature=temperature, type_suggestions=type_suggestions) + api_response = api_instance.create_ai_decompilation(function_id, temperature=temperature, type_suggestions=type_suggestions, apply_types=apply_types) print("The response of FunctionsAIDecompilationApi->create_ai_decompilation:\n") pprint(api_response) except Exception as e: @@ -100,6 +103,7 @@ Name | Type | Description | Notes **function_id** | **int**| Function ID | **temperature** | **float**| LLM temperature (0.0-1.0). Overrides the server default when set. Omit or set to -1 to use the server default. | [optional] [default to -1] **type_suggestions** | **bool**| Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off. | [optional] [default to True] + **apply_types** | **bool**| Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. | [optional] [default to True] ### Return type @@ -1340,7 +1344,7 @@ Accept AI decompilation type suggestions Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. -Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed, a `TYPEDEF` where the suggestion is a name for a scalar, and an `UNKNOWN` type where nothing gave it a shape. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. +Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed and a `TYPEDEF` where the suggestion is a name for a scalar. A suggestion nothing gave a shape to is left out, so `accepted` can be shorter than the keys requested. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. @@ -1815,6 +1819,197 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **v3_get_ai_decompilation_type_suggestions_status** +> WorkflowProgress v3_get_ai_decompilation_type_suggestions_status(function_id) + +Get type suggestion workflow status + +Returns fine-grained progress of the type suggestion workflow. Reports PENDING while a decompilation is running, because its own type-naming pass produces the same suggestions. + +**Error codes:** +- `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied +- `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found + +### Example + +* Api Key Authentication (APIKey): +* Bearer Authentication (bearerAuth): + +```python +import revengai +from revengai.models.workflow_progress import WorkflowProgress +from revengai.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.reveng.ai +# See configuration.py for a list of all supported configuration parameters. +configuration = revengai.Configuration( + host = "https://api.reveng.ai" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure API key authorization: APIKey +configuration.api_key['APIKey'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['APIKey'] = 'Bearer' + +# Configure Bearer authorization: bearerAuth +configuration = revengai.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with revengai.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = revengai.FunctionsAIDecompilationApi(api_client) + function_id = 56 # int | Function ID + + try: + # Get type suggestion workflow status + api_response = api_instance.v3_get_ai_decompilation_type_suggestions_status(function_id) + print("The response of FunctionsAIDecompilationApi->v3_get_ai_decompilation_type_suggestions_status:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling FunctionsAIDecompilationApi->v3_get_ai_decompilation_type_suggestions_status: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **function_id** | **int**| Function ID | + +### Return type + +[**WorkflowProgress**](WorkflowProgress.md) + +### Authorization + +[APIKey](../README.md#APIKey), [bearerAuth](../README.md#bearerAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | OK | - | +**403** | Forbidden | - | +**404** | Not Found | - | +**422** | Unprocessable Entity | - | +**500** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **v3_regenerate_ai_decompilation_type_suggestions** +> RegenerateOutputBody v3_regenerate_ai_decompilation_type_suggestions(function_id, apply_types=apply_types) + +Regenerate AI decompilation type suggestions + +Starts a new type suggestion workflow for the function, discarding the suggestions already stored. Requires a successful decompilation; it re-runs only the type-naming pass, so it costs no decompilation credit. The regenerated types are stored as data types of the analysis unless `apply_types=false`; types a previous run stored are not removed. Rejected while a decompilation is running: it runs the same pass itself once its output settles. Poll the type-suggestions status endpoint, which reports PENDING until then, and read the result from the type-suggestions endpoint. + +**Error codes:** +- `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied +- `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found +- `409` [`CONFLICT`](/errors/CONFLICT) — Conflict +- `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + +### Example + +* Api Key Authentication (APIKey): +* Bearer Authentication (bearerAuth): + +```python +import revengai +from revengai.models.regenerate_output_body import RegenerateOutputBody +from revengai.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.reveng.ai +# See configuration.py for a list of all supported configuration parameters. +configuration = revengai.Configuration( + host = "https://api.reveng.ai" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure API key authorization: APIKey +configuration.api_key['APIKey'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['APIKey'] = 'Bearer' + +# Configure Bearer authorization: bearerAuth +configuration = revengai.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with revengai.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = revengai.FunctionsAIDecompilationApi(api_client) + function_id = 56 # int | Function ID + apply_types = True # bool | Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. (optional) (default to True) + + try: + # Regenerate AI decompilation type suggestions + api_response = api_instance.v3_regenerate_ai_decompilation_type_suggestions(function_id, apply_types=apply_types) + print("The response of FunctionsAIDecompilationApi->v3_regenerate_ai_decompilation_type_suggestions:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling FunctionsAIDecompilationApi->v3_regenerate_ai_decompilation_type_suggestions: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **function_id** | **int**| Function ID | + **apply_types** | **bool**| Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. | [optional] [default to True] + +### Return type + +[**RegenerateOutputBody**](RegenerateOutputBody.md) + +### Authorization + +[APIKey](../README.md#APIKey), [bearerAuth](../README.md#bearerAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**202** | Accepted | - | +**403** | Forbidden | - | +**404** | Not Found | - | +**409** | Conflict | - | +**422** | Unprocessable Entity | - | +**500** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **v3_upsert_ai_decompilation_overrides** > UpsertOverridesData v3_upsert_ai_decompilation_overrides(function_id, upsert_overrides_input_body) diff --git a/docs/SuggestedTypeView.md b/docs/SuggestedTypeView.md index c893aca..e143ae7 100644 --- a/docs/SuggestedTypeView.md +++ b/docs/SuggestedTypeView.md @@ -5,10 +5,11 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**data_type_id** | **int** | Existing data type the members were accessed through. Null when nothing resolved to a row; never minted for a suggestion. | [optional] +**applied_data_type_id** | **int** | The type this suggestion became: a newly minted data type holding its name and members. Once set, the suggestion's entities resolve through this id rather than data_type_id. Null when it has not been applied, either because the pass is off or because nothing gave the suggestion a shape to store. | [optional] +**data_type_id** | **int** | The type this suggestion is about: the existing data type the members were accessed through. Never modified by applying a suggestion. Null when nothing resolved to a row, which is what makes the suggestion a proposal. | [optional] **holes** | [**List[SuggestedHole]**](SuggestedHole.md) | Gaps between consecutive placed members, in offset order. | **implied_size** | **int** | Highest byte_offset+byte_size across the members. A lower bound on the type's size, not its size. | [optional] -**key** | **str** | Identity of the suggestion: index:<data_type_id> where the access named a row, else token:<type_token>. | +**key** | **str** | Identity of the suggestion: index:<data_type_id> where the access named a row, type:<type_token> for a type with no observed members, else token:<type_token>. Do not infer data_type_id from the prefix: a type: key may carry one too. | **members** | [**List[SuggestedMemberView]**](SuggestedMemberView.md) | Members in offset order, unplaced ones last. | **name** | **str** | Name the type renders as: a database or frozen name where one exists, else the suggested one. | **type_token** | **str** | Placeholder the type renders as, when it appears in this function's source. | [optional] diff --git a/docs/TypesAppliedEvent.md b/docs/TypesAppliedEvent.md new file mode 100644 index 0000000..3e34070 --- /dev/null +++ b/docs/TypesAppliedEvent.md @@ -0,0 +1,33 @@ +# TypesAppliedEvent + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**attempt** | **int** | | +**seq** | **int** | | +**skipped** | **int** | | +**type** | **str** | | +**types** | **int** | | + +## Example + +```python +from revengai.models.types_applied_event import TypesAppliedEvent + +# TODO update the JSON string below +json = "{}" +# create an instance of TypesAppliedEvent from a JSON string +types_applied_event_instance = TypesAppliedEvent.from_json(json) +# print the JSON string representation of the object +print(TypesAppliedEvent.to_json()) + +# convert the object into a dict +types_applied_event_dict = types_applied_event_instance.to_dict() +# create an instance of TypesAppliedEvent from a dict +types_applied_event_from_dict = TypesAppliedEvent.from_dict(types_applied_event_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/revengai/__init__.py b/revengai/__init__.py index 78cd153..dd4b5b1 100644 --- a/revengai/__init__.py +++ b/revengai/__init__.py @@ -13,7 +13,7 @@ """ # noqa: E501 -__version__ = "v4.67.1" +__version__ = "v4.69.0" # Define package exports __all__ = [ @@ -365,6 +365,7 @@ "EventTOOLCALLRESULT", "EventTOOLCALLSTART", "EventTOOLCONFIRMATIONREQUIRED", + "EventTypesApplied", "EventTypesSuggested", "EventWarning", "EvidenceEffect", @@ -738,6 +739,7 @@ "TypeSuggestionsData", "TypedefDataType", "TypedefDefinition", + "TypesAppliedEvent", "TypesSuggestedEvent", "UnionDataType", "UnionDefinition", @@ -1146,6 +1148,7 @@ from revengai.models.event_toolcallresult import EventTOOLCALLRESULT as EventTOOLCALLRESULT from revengai.models.event_toolcallstart import EventTOOLCALLSTART as EventTOOLCALLSTART from revengai.models.event_toolconfirmationrequired import EventTOOLCONFIRMATIONREQUIRED as EventTOOLCONFIRMATIONREQUIRED +from revengai.models.event_types_applied import EventTypesApplied as EventTypesApplied from revengai.models.event_types_suggested import EventTypesSuggested as EventTypesSuggested from revengai.models.event_warning import EventWarning as EventWarning from revengai.models.evidence_effect import EvidenceEffect as EvidenceEffect @@ -1519,6 +1522,7 @@ from revengai.models.type_suggestions_data import TypeSuggestionsData as TypeSuggestionsData from revengai.models.typedef_data_type import TypedefDataType as TypedefDataType from revengai.models.typedef_definition import TypedefDefinition as TypedefDefinition +from revengai.models.types_applied_event import TypesAppliedEvent as TypesAppliedEvent from revengai.models.types_suggested_event import TypesSuggestedEvent as TypesSuggestedEvent from revengai.models.union_data_type import UnionDataType as UnionDataType from revengai.models.union_definition import UnionDefinition as UnionDefinition diff --git a/revengai/api/functions_ai_decompilation_api.py b/revengai/api/functions_ai_decompilation_api.py index 5ebf39e..5628da6 100644 --- a/revengai/api/functions_ai_decompilation_api.py +++ b/revengai/api/functions_ai_decompilation_api.py @@ -63,6 +63,7 @@ def create_ai_decompilation( function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], temperature: Annotated[Optional[Union[Annotated[float, Field(le=1, strict=True, ge=-1)], Annotated[int, Field(le=1, strict=True, ge=-1)]]], Field(description="LLM temperature (0.0-1.0). Overrides the server default when set. Omit or set to -1 to use the server default.")] = None, type_suggestions: Annotated[Optional[StrictBool], Field(description="Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off.")] = None, + apply_types: Annotated[Optional[StrictBool], Field(description="Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -86,6 +87,8 @@ def create_ai_decompilation( :type temperature: float :param type_suggestions: Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off. :type type_suggestions: bool + :param apply_types: Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -112,6 +115,7 @@ def create_ai_decompilation( function_id=function_id, temperature=temperature, type_suggestions=type_suggestions, + apply_types=apply_types, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -144,6 +148,7 @@ def create_ai_decompilation_with_http_info( function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], temperature: Annotated[Optional[Union[Annotated[float, Field(le=1, strict=True, ge=-1)], Annotated[int, Field(le=1, strict=True, ge=-1)]]], Field(description="LLM temperature (0.0-1.0). Overrides the server default when set. Omit or set to -1 to use the server default.")] = None, type_suggestions: Annotated[Optional[StrictBool], Field(description="Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off.")] = None, + apply_types: Annotated[Optional[StrictBool], Field(description="Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -167,6 +172,8 @@ def create_ai_decompilation_with_http_info( :type temperature: float :param type_suggestions: Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off. :type type_suggestions: bool + :param apply_types: Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -193,6 +200,7 @@ def create_ai_decompilation_with_http_info( function_id=function_id, temperature=temperature, type_suggestions=type_suggestions, + apply_types=apply_types, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -225,6 +233,7 @@ def create_ai_decompilation_without_preload_content( function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], temperature: Annotated[Optional[Union[Annotated[float, Field(le=1, strict=True, ge=-1)], Annotated[int, Field(le=1, strict=True, ge=-1)]]], Field(description="LLM temperature (0.0-1.0). Overrides the server default when set. Omit or set to -1 to use the server default.")] = None, type_suggestions: Annotated[Optional[StrictBool], Field(description="Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off.")] = None, + apply_types: Annotated[Optional[StrictBool], Field(description="Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -248,6 +257,8 @@ def create_ai_decompilation_without_preload_content( :type temperature: float :param type_suggestions: Ask the language model to name the suggested types and their members. Set to false to skip the model call; the statically derived layouts are still computed and stored. Cannot re-enable the pass when the server has it off. :type type_suggestions: bool + :param apply_types: Store the suggested types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -274,6 +285,7 @@ def create_ai_decompilation_without_preload_content( function_id=function_id, temperature=temperature, type_suggestions=type_suggestions, + apply_types=apply_types, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -301,6 +313,7 @@ def _create_ai_decompilation_serialize( function_id, temperature, type_suggestions, + apply_types, _request_auth, _content_type, _headers, @@ -333,6 +346,10 @@ def _create_ai_decompilation_serialize( _query_params.append(('type_suggestions', type_suggestions)) + if apply_types is not None: + + _query_params.append(('apply_types', apply_types)) + # process the header parameters # process the form parameters # process the body parameter @@ -4004,7 +4021,7 @@ def v3_accept_ai_decompilation_type_suggestions( ) -> AcceptTypeSuggestionsOutputBody: """Accept AI decompilation type suggestions - Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed, a `TYPEDEF` where the suggestion is a name for a scalar, and an `UNKNOWN` type where nothing gave it a shape. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed and a `TYPEDEF` where the suggestion is a name for a scalar. A suggestion nothing gave a shape to is left out, so `accepted` can be shorter than the keys requested. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error :param function_id: Function ID (required) :type function_id: int @@ -4081,7 +4098,7 @@ def v3_accept_ai_decompilation_type_suggestions_with_http_info( ) -> ApiResponse[AcceptTypeSuggestionsOutputBody]: """Accept AI decompilation type suggestions - Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed, a `TYPEDEF` where the suggestion is a name for a scalar, and an `UNKNOWN` type where nothing gave it a shape. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed and a `TYPEDEF` where the suggestion is a name for a scalar. A suggestion nothing gave a shape to is left out, so `accepted` can be shorter than the keys requested. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error :param function_id: Function ID (required) :type function_id: int @@ -4158,7 +4175,7 @@ def v3_accept_ai_decompilation_type_suggestions_without_preload_content( ) -> RESTResponseType: """Accept AI decompilation type suggestions - Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed, a `TYPEDEF` where the suggestion is a name for a scalar, and an `UNKNOWN` type where nothing gave it a shape. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + Stores the named type suggestions as data types of this function's analysis, with a `source_type` of `AI_DECOMP` and this function as their `source_function_id`. Each suggestion is stored as the type suggestions endpoint renders it: a `STRUCT` where members were placed and a `TYPEDEF` where the suggestion is a name for a scalar. A suggestion nothing gave a shape to is left out, so `accepted` can be shorter than the keys requested. A member with no offset or width is left out and counted in `skipped_members`. A type expression a member names is matched against the analysis by name alone and created where nothing matches: `char *` creates a `char` `BASE` type and a `POINTER` type pointing at it, reusing either where the analysis already holds it. A member naming another suggestion accepted by the same request resolves to it. Only a trailing `*` is taken apart, so a name like `int &` stands for one type. No size is stored: the widths a suggestion carries are lower bounds rather than the type's own. A suggestion the analysis already holds a type of that name and kind for resolves to it, so repeating a request stores nothing further. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `400` [`BAD_REQUEST`](/errors/BAD_REQUEST) — Bad Request - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `422` [`VALIDATION_FAILED`](/errors/VALIDATION_FAILED) — Validation Failed - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error :param function_id: Function ID (required) :type function_id: int @@ -5388,6 +5405,574 @@ def _v3_get_ai_decompilation_type_suggestions_serialize( + @validate_call + def v3_get_ai_decompilation_type_suggestions_status( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> WorkflowProgress: + """Get type suggestion workflow status + + Returns fine-grained progress of the type suggestion workflow. Reports PENDING while a decompilation is running, because its own type-naming pass produces the same suggestions. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found + + :param function_id: Function ID (required) + :type function_id: int + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_get_ai_decompilation_type_suggestions_status_serialize( + function_id=function_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "WorkflowProgress", + '403': "APIError", + '404': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def v3_get_ai_decompilation_type_suggestions_status_with_http_info( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[WorkflowProgress]: + """Get type suggestion workflow status + + Returns fine-grained progress of the type suggestion workflow. Reports PENDING while a decompilation is running, because its own type-naming pass produces the same suggestions. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found + + :param function_id: Function ID (required) + :type function_id: int + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_get_ai_decompilation_type_suggestions_status_serialize( + function_id=function_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "WorkflowProgress", + '403': "APIError", + '404': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def v3_get_ai_decompilation_type_suggestions_status_without_preload_content( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get type suggestion workflow status + + Returns fine-grained progress of the type suggestion workflow. Reports PENDING while a decompilation is running, because its own type-naming pass produces the same suggestions. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found + + :param function_id: Function ID (required) + :type function_id: int + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_get_ai_decompilation_type_suggestions_status_serialize( + function_id=function_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "WorkflowProgress", + '403': "APIError", + '404': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _v3_get_ai_decompilation_type_suggestions_status_serialize( + self, + function_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if function_id is not None: + _path_params['function_id'] = function_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'APIKey', + 'bearerAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/v3/functions/{function_id}/ai-decompilation/type-suggestions/status', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def v3_regenerate_ai_decompilation_type_suggestions( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + apply_types: Annotated[Optional[StrictBool], Field(description="Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RegenerateOutputBody: + """Regenerate AI decompilation type suggestions + + Starts a new type suggestion workflow for the function, discarding the suggestions already stored. Requires a successful decompilation; it re-runs only the type-naming pass, so it costs no decompilation credit. The regenerated types are stored as data types of the analysis unless `apply_types=false`; types a previous run stored are not removed. Rejected while a decompilation is running: it runs the same pass itself once its output settles. Poll the type-suggestions status endpoint, which reports PENDING until then, and read the result from the type-suggestions endpoint. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + + :param function_id: Function ID (required) + :type function_id: int + :param apply_types: Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_regenerate_ai_decompilation_type_suggestions_serialize( + function_id=function_id, + apply_types=apply_types, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '202': "RegenerateOutputBody", + '403': "APIError", + '404': "APIError", + '409': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def v3_regenerate_ai_decompilation_type_suggestions_with_http_info( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + apply_types: Annotated[Optional[StrictBool], Field(description="Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[RegenerateOutputBody]: + """Regenerate AI decompilation type suggestions + + Starts a new type suggestion workflow for the function, discarding the suggestions already stored. Requires a successful decompilation; it re-runs only the type-naming pass, so it costs no decompilation credit. The regenerated types are stored as data types of the analysis unless `apply_types=false`; types a previous run stored are not removed. Rejected while a decompilation is running: it runs the same pass itself once its output settles. Poll the type-suggestions status endpoint, which reports PENDING until then, and read the result from the type-suggestions endpoint. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + + :param function_id: Function ID (required) + :type function_id: int + :param apply_types: Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_regenerate_ai_decompilation_type_suggestions_serialize( + function_id=function_id, + apply_types=apply_types, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '202': "RegenerateOutputBody", + '403': "APIError", + '404': "APIError", + '409': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def v3_regenerate_ai_decompilation_type_suggestions_without_preload_content( + self, + function_id: Annotated[int, Field(strict=True, ge=1, description="Function ID")], + apply_types: Annotated[Optional[StrictBool], Field(description="Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Regenerate AI decompilation type suggestions + + Starts a new type suggestion workflow for the function, discarding the suggestions already stored. Requires a successful decompilation; it re-runs only the type-naming pass, so it costs no decompilation credit. The regenerated types are stored as data types of the analysis unless `apply_types=false`; types a previous run stored are not removed. Rejected while a decompilation is running: it runs the same pass itself once its output settles. Poll the type-suggestions status endpoint, which reports PENDING until then, and read the result from the type-suggestions endpoint. **Error codes:** - `403` [`ACCESS_DENIED`](/errors/ACCESS_DENIED) — Access Denied - `404` [`NOT_FOUND`](/errors/NOT_FOUND) — Not Found - `409` [`CONFLICT`](/errors/CONFLICT) — Conflict - `500` [`INTERNAL_ERROR`](/errors/INTERNAL_ERROR) — Internal Server Error + + :param function_id: Function ID (required) + :type function_id: int + :param apply_types: Store the regenerated types as data types of this function's analysis, with a source_type of AI_DECOMP. Set to false to leave them as suggestions only. Cannot re-enable the pass when the server has it off. + :type apply_types: bool + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._v3_regenerate_ai_decompilation_type_suggestions_serialize( + function_id=function_id, + apply_types=apply_types, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '202': "RegenerateOutputBody", + '403': "APIError", + '404': "APIError", + '409': "APIError", + '422': "APIError", + '500': "APIError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _v3_regenerate_ai_decompilation_type_suggestions_serialize( + self, + function_id, + apply_types, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if function_id is not None: + _path_params['function_id'] = function_id + # process the query parameters + if apply_types is not None: + + _query_params.append(('apply_types', apply_types)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'APIKey', + 'bearerAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/v3/functions/{function_id}/ai-decompilation/type-suggestions', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + @validate_call def v3_upsert_ai_decompilation_overrides( self, diff --git a/revengai/api_client.py b/revengai/api_client.py index 1b8724d..2342132 100644 --- a/revengai/api_client.py +++ b/revengai/api_client.py @@ -90,7 +90,7 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = 'OpenAPI-Generator/v4.67.1/python' + self.user_agent = 'OpenAPI-Generator/v4.69.0/python' self.client_side_validation = configuration.client_side_validation def __enter__(self): diff --git a/revengai/configuration.py b/revengai/configuration.py index 2495f5c..9a4fd24 100644 --- a/revengai/configuration.py +++ b/revengai/configuration.py @@ -541,8 +541,8 @@ def to_debug_report(self) -> str: return "Python SDK Debug Report:\n"\ "OS: {env}\n"\ "Python Version: {pyversion}\n"\ - "Version of the API: v4.67.1\n"\ - "SDK Package Version: v4.67.1".\ + "Version of the API: v4.69.0\n"\ + "SDK Package Version: v4.69.0".\ format(env=sys.platform, pyversion=sys.version) def get_host_settings(self) -> List[HostSetting]: diff --git a/revengai/models/__init__.py b/revengai/models/__init__.py index 3fca1a2..124f9f2 100644 --- a/revengai/models/__init__.py +++ b/revengai/models/__init__.py @@ -331,6 +331,7 @@ from revengai.models.event_toolcallresult import EventTOOLCALLRESULT from revengai.models.event_toolcallstart import EventTOOLCALLSTART from revengai.models.event_toolconfirmationrequired import EventTOOLCONFIRMATIONREQUIRED +from revengai.models.event_types_applied import EventTypesApplied from revengai.models.event_types_suggested import EventTypesSuggested from revengai.models.event_warning import EventWarning from revengai.models.evidence_effect import EvidenceEffect @@ -704,6 +705,7 @@ from revengai.models.type_suggestions_data import TypeSuggestionsData from revengai.models.typedef_data_type import TypedefDataType from revengai.models.typedef_definition import TypedefDefinition +from revengai.models.types_applied_event import TypesAppliedEvent from revengai.models.types_suggested_event import TypesSuggestedEvent from revengai.models.union_data_type import UnionDataType from revengai.models.union_definition import UnionDefinition diff --git a/revengai/models/accept_type_suggestions_output_body.py b/revengai/models/accept_type_suggestions_output_body.py index a4d04fb..059664c 100644 --- a/revengai/models/accept_type_suggestions_output_body.py +++ b/revengai/models/accept_type_suggestions_output_body.py @@ -27,7 +27,7 @@ class AcceptTypeSuggestionsOutputBody(BaseModel): """ AcceptTypeSuggestionsOutputBody """ # noqa: E501 - accepted: Optional[List[AcceptedType]] = Field(description="One entry per requested suggestion, in request order.") + accepted: Optional[List[AcceptedType]] = Field(description="One entry per requested suggestion that had a shape to store, in request order.") data_types: Optional[List[DataTypeEntry]] = Field(description="The type each requested suggestion resolved to, plus every type minted to satisfy one, ordered by data_type_id.") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["accepted", "data_types"] diff --git a/revengai/models/error_body.py b/revengai/models/error_body.py index 9442dec..055bf2e 100644 --- a/revengai/models/error_body.py +++ b/revengai/models/error_body.py @@ -36,8 +36,8 @@ class ErrorBody(BaseModel): @field_validator('code') def code_validate_enum(cls, value): """Validates the enum""" - if value not in set(['ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api']): - raise ValueError("must be one of enum values ('ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api')") + if value not in set(['ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'PRECONDITION_FAILED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api']): + raise ValueError("must be one of enum values ('ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'PRECONDITION_FAILED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api')") return value model_config = ConfigDict( diff --git a/revengai/models/event_types_applied.py b/revengai/models/event_types_applied.py new file mode 100644 index 0000000..5b1c097 --- /dev/null +++ b/revengai/models/event_types_applied.py @@ -0,0 +1,116 @@ +# coding: utf-8 + +""" + RevEng.AI API + + RevEng.AI is an AI-powered binary analysis platform for reverse engineering and malware analysis. It provides similarity search across executable binaries and functions, AI-driven decompilation, dynamic execution analysis, firmware unpacking, and integration with external threat intelligence sources like VirusTotal. + + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator +from typing import Any, ClassVar, Dict, List, Optional +from revengai.models.types_applied_event import TypesAppliedEvent +from typing import Optional, Set +from typing_extensions import Self + +class EventTypesApplied(BaseModel): + """ + EventTypesApplied + """ # noqa: E501 + data: TypesAppliedEvent + event: StrictStr = Field(description="The event name.") + id: Optional[StrictInt] = Field(default=None, description="The event ID.") + retry: Optional[StrictInt] = Field(default=None, description="The retry time in milliseconds.") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["data", "event", "id", "retry"] + + @field_validator('event') + def event_validate_enum(cls, value): + """Validates the enum""" + if value not in set(['types_applied', 'unknown_default_open_api']): + raise ValueError("must be one of enum values ('types_applied', 'unknown_default_open_api')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of EventTypesApplied from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of data + if self.data: + _dict['data'] = self.data.to_dict() + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of EventTypesApplied from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "data": TypesAppliedEvent.from_dict(obj["data"]) if obj.get("data") is not None else None, + "event": obj.get("event"), + "id": obj.get("id"), + "retry": obj.get("retry") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/revengai/models/status.py b/revengai/models/status.py index 0a94bed..2d22458 100644 --- a/revengai/models/status.py +++ b/revengai/models/status.py @@ -36,8 +36,8 @@ class Status(BaseModel): @field_validator('code') def code_validate_enum(cls, value): """Validates the enum""" - if value not in set(['ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api']): - raise ValueError("must be one of enum values ('ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api')") + if value not in set(['ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'PRECONDITION_FAILED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api']): + raise ValueError("must be one of enum values ('ACCESS_DENIED', 'ALREADY_EXISTS', 'ANALYSIS_NOT_READY', 'BAD_REQUEST', 'CLIENT_CLOSED_REQUEST', 'CONFLICT', 'CONVERSATION_NOT_FOUND', 'DOMAIN_ALREADY_CLAIMED', 'DOMAIN_VERIFICATION_PENDING', 'DYNAMIC_EXECUTION_INCOMPLETE', 'EMAIL_NOT_VERIFIED', 'EXTERNAL_USER', 'FORBIDDEN', 'GATEWAY_TIMEOUT', 'GROUP_HAS_MEMBERS', 'INSUFFICIENT_CREDITS', 'INTERNAL_ERROR', 'INTERNAL_ISSUER', 'INVALID_CONVERSATION_ID', 'INVALID_CREDENTIALS', 'INVALID_INVITE_CODE', 'INVALID_RESET_CODE', 'LAST_ORG_OWNER', 'LAST_TEAM_ADMIN', 'LAST_TEAM_MEMBER', 'LINKED_TO_ORG', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE', 'NOT_FOUND', 'NOT_IMPLEMENTED', 'NO_ACTIVE_RUN', 'NO_PENDING_CONFIRMATION', 'NO_VIRUSTOTAL_KEY', 'OIDC_DISCOVERY_FAILED', 'PASSWORD_RESET_REQUIRED', 'PAYMENT_REQUIRED', 'PRECONDITION_FAILED', 'REPORT_RENDER_FAILED', 'REQUEST_ENTITY_TOO_LARGE', 'RUN_ALREADY_ACTIVE', 'SELF_DELETION_NOT_ALLOWED', 'SERVICE_UNAVAILABLE', 'TOKEN_EXPIRED', 'TOKEN_REUSED', 'TOO_MANY_REQUESTS', 'UNAUTHORIZED', 'UNSUPPORTED_MEDIA_TYPE', 'VALIDATION_FAILED', 'VERIFICATION_EXPIRED', 'VERIFICATION_NOT_FOUND', 'unknown_default_open_api')") return value model_config = ConfigDict( diff --git a/revengai/models/stream_ai_decompilation200_response_inner.py b/revengai/models/stream_ai_decompilation200_response_inner.py index 4ac47da..9070420 100644 --- a/revengai/models/stream_ai_decompilation200_response_inner.py +++ b/revengai/models/stream_ai_decompilation200_response_inner.py @@ -25,13 +25,14 @@ from revengai.models.event_rename_applied import EventRenameApplied from revengai.models.event_source_delta import EventSourceDelta from revengai.models.event_source_reset import EventSourceReset +from revengai.models.event_types_applied import EventTypesApplied from revengai.models.event_types_suggested import EventTypesSuggested from revengai.models.event_warning import EventWarning from pydantic import StrictStr, Field from typing import Union, List, Set, Optional, Dict from typing_extensions import Literal, Self -STREAMAIDECOMPILATION200RESPONSEINNER_ONE_OF_SCHEMAS = ["EventAttemptFailed", "EventAttemptStarted", "EventDecompFailed", "EventDecompFinished", "EventNamesFinished", "EventProse", "EventRenameApplied", "EventSourceDelta", "EventSourceReset", "EventTypesSuggested", "EventWarning"] +STREAMAIDECOMPILATION200RESPONSEINNER_ONE_OF_SCHEMAS = ["EventAttemptFailed", "EventAttemptStarted", "EventDecompFailed", "EventDecompFinished", "EventNamesFinished", "EventProse", "EventRenameApplied", "EventSourceDelta", "EventSourceReset", "EventTypesApplied", "EventTypesSuggested", "EventWarning"] class StreamAiDecompilation200ResponseInner(BaseModel): """ @@ -55,12 +56,14 @@ class StreamAiDecompilation200ResponseInner(BaseModel): oneof_schema_8_validator: Optional[EventSourceDelta] = None # data type: EventSourceReset oneof_schema_9_validator: Optional[EventSourceReset] = None + # data type: EventTypesApplied + oneof_schema_10_validator: Optional[EventTypesApplied] = None # data type: EventTypesSuggested - oneof_schema_10_validator: Optional[EventTypesSuggested] = None + oneof_schema_11_validator: Optional[EventTypesSuggested] = None # data type: EventWarning - oneof_schema_11_validator: Optional[EventWarning] = None - actual_instance: Optional[Union[EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning]] = None - one_of_schemas: Set[str] = { "EventAttemptFailed", "EventAttemptStarted", "EventDecompFailed", "EventDecompFinished", "EventNamesFinished", "EventProse", "EventRenameApplied", "EventSourceDelta", "EventSourceReset", "EventTypesSuggested", "EventWarning" } + oneof_schema_12_validator: Optional[EventWarning] = None + actual_instance: Optional[Union[EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning]] = None + one_of_schemas: Set[str] = { "EventAttemptFailed", "EventAttemptStarted", "EventDecompFailed", "EventDecompFinished", "EventNamesFinished", "EventProse", "EventRenameApplied", "EventSourceDelta", "EventSourceReset", "EventTypesApplied", "EventTypesSuggested", "EventWarning" } model_config = ConfigDict( validate_assignment=True, @@ -128,6 +131,11 @@ def actual_instance_must_validate_oneof(cls, v): error_messages.append(f"Error! Input type `{type(v)}` is not `EventSourceReset`") else: match += 1 + # validate data type: EventTypesApplied + if not isinstance(v, EventTypesApplied): + error_messages.append(f"Error! Input type `{type(v)}` is not `EventTypesApplied`") + else: + match += 1 # validate data type: EventTypesSuggested if not isinstance(v, EventTypesSuggested): error_messages.append(f"Error! Input type `{type(v)}` is not `EventTypesSuggested`") @@ -140,10 +148,10 @@ def actual_instance_must_validate_oneof(cls, v): match += 1 if match > 1: # more than 1 match - raise ValueError("Multiple matches found when setting `actual_instance` in StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) + raise ValueError("Multiple matches found when setting `actual_instance` in StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) elif match == 0: # no match - raise ValueError("No match found when setting `actual_instance` in StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) + raise ValueError("No match found when setting `actual_instance` in StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) else: return v @@ -212,6 +220,12 @@ def from_json(cls, json_str: str) -> Self: match += 1 except (ValidationError, ValueError) as e: error_messages.append(str(e)) + # deserialize data into EventTypesApplied + try: + instance.actual_instance = EventTypesApplied.from_json(json_str) + match += 1 + except (ValidationError, ValueError) as e: + error_messages.append(str(e)) # deserialize data into EventTypesSuggested try: instance.actual_instance = EventTypesSuggested.from_json(json_str) @@ -227,10 +241,10 @@ def from_json(cls, json_str: str) -> Self: if match > 1: # more than 1 match - raise ValueError("Multiple matches found when deserializing the JSON string into StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) + raise ValueError("Multiple matches found when deserializing the JSON string into StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) elif match == 0: # no match - raise ValueError("No match found when deserializing the JSON string into StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) + raise ValueError("No match found when deserializing the JSON string into StreamAiDecompilation200ResponseInner with oneOf schemas: EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning. Details: " + ", ".join(error_messages)) else: return instance @@ -244,7 +258,7 @@ def to_json(self) -> str: else: return json.dumps(self.actual_instance) - def to_dict(self) -> Optional[Union[Dict[str, Any], EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesSuggested, EventWarning]]: + def to_dict(self) -> Optional[Union[Dict[str, Any], EventAttemptFailed, EventAttemptStarted, EventDecompFailed, EventDecompFinished, EventNamesFinished, EventProse, EventRenameApplied, EventSourceDelta, EventSourceReset, EventTypesApplied, EventTypesSuggested, EventWarning]]: """Returns the dict representation of the actual instance""" if self.actual_instance is None: return None diff --git a/revengai/models/suggested_type_view.py b/revengai/models/suggested_type_view.py index 9d5be66..afbb2b5 100644 --- a/revengai/models/suggested_type_view.py +++ b/revengai/models/suggested_type_view.py @@ -27,16 +27,17 @@ class SuggestedTypeView(BaseModel): """ SuggestedTypeView """ # noqa: E501 - data_type_id: Optional[StrictInt] = Field(default=None, description="Existing data type the members were accessed through. Null when nothing resolved to a row; never minted for a suggestion.") + applied_data_type_id: Optional[StrictInt] = Field(default=None, description="The type this suggestion became: a newly minted data type holding its name and members. Once set, the suggestion's entities resolve through this id rather than data_type_id. Null when it has not been applied, either because the pass is off or because nothing gave the suggestion a shape to store.") + data_type_id: Optional[StrictInt] = Field(default=None, description="The type this suggestion is about: the existing data type the members were accessed through. Never modified by applying a suggestion. Null when nothing resolved to a row, which is what makes the suggestion a proposal.") holes: Optional[List[SuggestedHole]] = Field(description="Gaps between consecutive placed members, in offset order.") implied_size: Optional[StrictInt] = Field(default=None, description="Highest byte_offset+byte_size across the members. A lower bound on the type's size, not its size.") - key: StrictStr = Field(description="Identity of the suggestion: index: where the access named a row, else token:.") + key: StrictStr = Field(description="Identity of the suggestion: index: where the access named a row, type: for a type with no observed members, else token:. Do not infer data_type_id from the prefix: a type: key may carry one too.") members: Optional[List[SuggestedMemberView]] = Field(description="Members in offset order, unplaced ones last.") name: StrictStr = Field(description="Name the type renders as: a database or frozen name where one exists, else the suggested one.") type_token: Optional[StrictStr] = Field(default=None, description="Placeholder the type renders as, when it appears in this function's source.") underlying_type: Optional[StrictStr] = Field(default=None, description="Set only for a type with no observed members, where the suggestion is a name and a scalar type rather than a layout.") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["data_type_id", "holes", "implied_size", "key", "members", "name", "type_token", "underlying_type"] + __properties: ClassVar[List[str]] = ["applied_data_type_id", "data_type_id", "holes", "implied_size", "key", "members", "name", "type_token", "underlying_type"] model_config = ConfigDict( populate_by_name=True, @@ -120,6 +121,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "applied_data_type_id": obj.get("applied_data_type_id"), "data_type_id": obj.get("data_type_id"), "holes": [SuggestedHole.from_dict(_item) for _item in obj["holes"]] if obj.get("holes") is not None else None, "implied_size": obj.get("implied_size"), diff --git a/revengai/models/types_applied_event.py b/revengai/models/types_applied_event.py new file mode 100644 index 0000000..331a3d2 --- /dev/null +++ b/revengai/models/types_applied_event.py @@ -0,0 +1,107 @@ +# coding: utf-8 + +""" + RevEng.AI API + + RevEng.AI is an AI-powered binary analysis platform for reverse engineering and malware analysis. It provides similarity search across executable binaries and functions, AI-driven decompilation, dynamic execution analysis, firmware unpacking, and integration with external threat intelligence sources like VirusTotal. + + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class TypesAppliedEvent(BaseModel): + """ + TypesAppliedEvent + """ # noqa: E501 + attempt: StrictInt + seq: StrictInt + skipped: StrictInt + type: StrictStr + types: StrictInt + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["attempt", "seq", "skipped", "type", "types"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of TypesAppliedEvent from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of TypesAppliedEvent from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "attempt": obj.get("attempt"), + "seq": obj.get("seq"), + "skipped": obj.get("skipped"), + "type": obj.get("type"), + "types": obj.get("types") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + +