diff --git a/CLAUDE.md b/CLAUDE.md index d0f31ad91..bec4072bf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1848,3 +1848,25 @@ ls $test_file --- *This documentation provides comprehensive guidance for working with the Aignostics Python SDK. Each module has detailed CLAUDE.md files with implementation specifics, usage examples, and best practices.* + +## SDLC Configuration + +- **JIRA Project Key:** PYSDK +- **Atlassian Cloud ID:** fff788d2-8a2a-4c36-a884-dde2bb4a2b49 +- **Ketryx Project:** Python SDK (KXPRJ2Q4PA8AADY975SFMKF276TYV75) + +**Item type locations:** +- Change Requests: Ketryx Change Request (JIRA) +- Stakeholder Requirements: requirements/SHR-*.md (Git) +- Software Requirements: Requirement (JIRA) | requirements/SWR-*.md (Git, preferred) +- Risks: Risk (JIRA) +- Software Item Specs: Software Item Spec (JIRA) | specifications/SPEC-*.md (Git, preferred) +- Test Cases: tests/**/TC-*.feature (Git) + +**Approval structure:** +- Ketryx Change Request: Product Manager → Engineering Tech Lead → Quality Managers → Risk Managers +- Software Requirement: Area Lead (BD) → Security Engineer → Regulatory Affairs Specialist → Engineer → Engineering Tech Lead → Product Manager +- Software Item Spec: Engineer → Engineering Tech Lead +- Risk: Quality Managers → Security Engineer → Product Managers → Tech Lead → Engineer → Engineering Tech Lead → Product Manager → Engineer +- Test Case: Engineer → Engineering Tech Lead +- Anomaly: Engineer → Engineering Tech Lead diff --git a/codegen/in/archive/openapi_1.5.0.json b/codegen/in/archive/openapi_1.5.0.json new file mode 100644 index 000000000..1e0c6e0e4 --- /dev/null +++ b/codegen/in/archive/openapi_1.5.0.json @@ -0,0 +1,3336 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Aignostics Platform API", + "description": "\nThe Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. \n\nTo begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. \n\nMore information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com).\n\n**How to authorize and test API endpoints:**\n\n1. Click the \"Authorize\" button in the right corner below\n3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials\n4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint\n\n**Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized.\n\n", + "version": "1.5.0" + }, + "servers": [ + { + "url": "/api" + } + ], + "paths": { + "/v1/applications": { + "get": { + "tags": [ + "Public" + ], + "summary": "List available applications", + "description": "Returns the list of the applications, available to the caller.\n\nThe application is available if any of the versions of the application is assigned to the caller's organization.\nThe response is paginated and sorted according to the provided parameters.", + "operationId": "list_applications_v1_applications_get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "title": "Page" + } + }, + { + "name": "page-size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 5, + "default": 50, + "title": "Page-Size" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Sort the results by one or more fields. Use `+` for ascending and `-` for descending order.\n\n**Available fields:**\n- `application_id`\n- `name`\n- `description`\n- `regulatory_classes`\n\n**Examples:**\n- `?sort=application_id` - Sort by application_id ascending\n- `?sort=-name` - Sort by name descending\n- `?sort=+description&sort=name` - Sort by description ascending, then name descending", + "title": "Sort" + }, + "description": "Sort the results by one or more fields. Use `+` for ascending and `-` for descending order.\n\n**Available fields:**\n- `application_id`\n- `name`\n- `description`\n- `regulatory_classes`\n\n**Examples:**\n- `?sort=application_id` - Sort by application_id ascending\n- `?sort=-name` - Sort by name descending\n- `?sort=+description&sort=name` - Sort by description ascending, then name descending" + } + ], + "responses": { + "200": { + "description": "A list of applications available to the caller", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApplicationReadShortResponse" + }, + "title": "Response List Applications V1 Applications Get" + }, + "example": [ + { + "application_id": "he-tme", + "name": "Atlas H&E-TME", + "regulatory_classes": [ + "RUO" + ], + "description": "The Atlas H&E TME is an AI application designed to examine FFPE (formalin-fixed, paraffin-embedded) tissues stained with H&E (hematoxylin and eosin), delivering comprehensive insights into the tumor microenvironment.", + "latest_version": { + "number": "1.0.0", + "released_at": "2025-09-01T19:01:05.401Z" + } + }, + { + "application_id": "test-app", + "name": "Test Application", + "regulatory_classes": [ + "RUO" + ], + "description": "This is the test application with two algorithms: TissueQc and Tissue Segmentation", + "latest_version": { + "number": "2.0.0", + "released_at": "2025-09-02T19:01:05.401Z" + } + } + ] + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing authentication" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Read Application By Id", + "description": "Retrieve details of a specific application by its ID.", + "operationId": "read_application_by_id_v1_applications__application_id__get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplicationReadResponse" + } + } + } + }, + "403": { + "description": "Forbidden - You don't have permission to see this application" + }, + "404": { + "description": "Not Found - Application with the given ID does not exist" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Application Version Details", + "description": "Get the application version details.\n\nAllows caller to retrieve information about application version based on provided application version ID.", + "operationId": "application_version_details_v1_applications__application_id__versions__version__get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "title": "Version" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VersionReadResponse" + }, + "example": { + "version_number": "0.4.4", + "changelog": "New deployment", + "input_artifacts": [ + { + "name": "whole_slide_image", + "mime_type": "image/tiff", + "metadata_schema": { + "type": "object", + "$defs": { + "LungCancerMetadata": { + "type": "object", + "title": "LungCancerMetadata", + "required": [ + "type", + "tissue" + ], + "properties": { + "type": { + "enum": [ + "lung" + ], + "type": "string", + "const": "lung", + "title": "Type" + }, + "tissue": { + "enum": [ + "lung", + "lymph node", + "liver", + "adrenal gland", + "bone", + "brain" + ], + "type": "string", + "title": "Tissue" + } + }, + "additionalProperties": false + } + }, + "title": "ExternalImageMetadata", + "$schema": "http://json-schema.org/draft-07/schema#", + "required": [ + "checksum_crc32c", + "base_mpp", + "width", + "height", + "cancer" + ], + "properties": { + "stain": { + "enum": [ + "H&E" + ], + "type": "string", + "const": "H&E", + "title": "Stain", + "default": "H&E" + }, + "width": { + "type": "integer", + "title": "Width", + "maximum": 150000, + "minimum": 1 + }, + "cancer": { + "anyOf": [ + { + "$ref": "#/$defs/LungCancerMetadata" + } + ], + "title": "Cancer" + }, + "height": { + "type": "integer", + "title": "Height", + "maximum": 150000, + "minimum": 1 + }, + "base_mpp": { + "type": "number", + "title": "Base Mpp", + "maximum": 0.5, + "minimum": 0.125 + }, + "mime_type": { + "enum": [ + "application/dicom", + "image/tiff" + ], + "type": "string", + "title": "Mime Type", + "default": "image/tiff" + }, + "checksum_crc32c": { + "type": "string", + "title": "Checksum Crc32C" + } + }, + "description": "Metadata corresponding to an external image.", + "additionalProperties": false + } + } + ], + "output_artifacts": [ + { + "name": "tissue_qc:tiff_heatmap", + "mime_type": "image/tiff", + "metadata_schema": { + "type": "object", + "title": "HeatmapMetadata", + "$schema": "http://json-schema.org/draft-07/schema#", + "required": [ + "checksum_crc32c", + "width", + "height", + "class_colors" + ], + "properties": { + "width": { + "type": "integer", + "title": "Width" + }, + "height": { + "type": "integer", + "title": "Height" + }, + "base_mpp": { + "type": "number", + "title": "Base Mpp", + "maximum": 0.5, + "minimum": 0.125 + }, + "mime_type": { + "enum": [ + "image/tiff" + ], + "type": "string", + "const": "image/tiff", + "title": "Mime Type", + "default": "image/tiff" + }, + "class_colors": { + "type": "object", + "title": "Class Colors", + "additionalProperties": { + "type": "array", + "maxItems": 3, + "minItems": 3, + "prefixItems": [ + { + "type": "integer", + "maximum": 255, + "minimum": 0 + }, + { + "type": "integer", + "maximum": 255, + "minimum": 0 + }, + { + "type": "integer", + "maximum": 255, + "minimum": 0 + } + ] + } + }, + "checksum_crc32c": { + "type": "string", + "title": "Checksum Crc32C" + } + }, + "description": "Metadata corresponding to a segmentation heatmap file.", + "additionalProperties": false + }, + "scope": "ITEM", + "visibility": "EXTERNAL" + } + ], + "released_at": "2025-04-16T08:45:20.655972Z" + } + } + } + }, + "403": { + "description": "Forbidden - You don't have permission to see this version" + }, + "404": { + "description": "Not Found - Application version with given ID is not available to you or does not exist" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs": { + "get": { + "tags": [ + "Public" + ], + "summary": "List Runs", + "description": "List runs with filtering, sorting, and pagination capabilities.\n\nReturns paginated runs that were submitted by the user.", + "operationId": "list_runs_v1_runs_get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional application ID filter", + "examples": [ + "tissue-segmentation", + "heta" + ], + "title": "Application Id" + }, + "description": "Optional application ID filter" + }, + { + "name": "application_version", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optional Version Name", + "examples": [ + "1.0.2", + "1.0.1-beta2" + ], + "title": "Application Version" + }, + "description": "Optional Version Name" + }, + { + "name": "external_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Optionally filter runs by items with this external ID", + "examples": [ + "slide_001", + "patient_12345_sample_A" + ], + "title": "External Id" + }, + "description": "Optionally filter runs by items with this external ID" + }, + { + "name": "custom_metadata", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "maxLength": 1000 + }, + { + "type": "null" + } + ], + "description": "Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata.\n#### URL Encoding Required\n**Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding.\n\n#### Examples (Clear Format):\n- **Field existence**: `$.study` - Runs that have a study field defined\n- **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value\n- **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75\n- **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\"\n- **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements\n\n#### Examples (URL-Encoded Format):\n- **Field existence**: `%24.study`\n- **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)`\n- **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)`\n- **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)`\n- **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)`\n\n#### Notes\n- JSONPath expressions are evaluated using PostgreSQL's `@?` operator\n- The `$.` prefix is automatically added to root-level field references if missing\n- String values in conditions must be enclosed in double quotes\n- Use `&&` for AND operations and `||` for OR operations\n- Regular expressions use `like_regex` with standard regex syntax\n- **Please remember to URL-encode the entire JSONPath expression when making HTTP requests**\n\n ", + "title": "Custom Metadata" + }, + "description": "Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata.\n#### URL Encoding Required\n**Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding.\n\n#### Examples (Clear Format):\n- **Field existence**: `$.study` - Runs that have a study field defined\n- **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value\n- **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75\n- **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\"\n- **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements\n\n#### Examples (URL-Encoded Format):\n- **Field existence**: `%24.study`\n- **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)`\n- **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)`\n- **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)`\n- **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)`\n\n#### Notes\n- JSONPath expressions are evaluated using PostgreSQL's `@?` operator\n- The `$.` prefix is automatically added to root-level field references if missing\n- String values in conditions must be enclosed in double quotes\n- Use `&&` for AND operations and `||` for OR operations\n- Regular expressions use `like_regex` with standard regex syntax\n- **Please remember to URL-encode the entire JSONPath expression when making HTTP requests**\n\n ", + "examples": { + "no_filter": { + "summary": "No filter (returns all)", + "description": "Returns all items without filtering by custom metadata", + "value": "$" + }, + "field_exists": { + "summary": "Check if field exists", + "description": "Find applications that have a project field defined", + "value": "$.study" + }, + "field_has_value": { + "summary": "Check if field has a certain value", + "description": "Compare a field value against a certain value", + "value": "$.study ? (@ == \"abc-1\")" + }, + "numeric_comparisons": { + "summary": "Compare to a numeric value of a field", + "description": "Compare a field value against a numeric value of a field", + "value": "$.confidence_score ? (@ > 0.75)" + }, + "array_operations": { + "summary": "Check if an array contains a certain value", + "description": "Check if an array contains a certain value", + "value": "$.tags[*] ? (@ == \"draft\")" + }, + "complex_filters": { + "summary": "Combine multiple checks", + "description": "Combine multiple checks", + "value": "$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)" + } + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "title": "Page" + } + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 5, + "default": 50, + "title": "Page Size" + } + }, + { + "name": "for_organization", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.", + "title": "For Organization" + }, + "description": "Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs." + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Sort the results by one or more fields. Use `+` for ascending and `-` for descending order.\n\n**Available fields:**\n- `run_id`\n- `application_id`\n- `version_number`\n- `custom_metadata`\n- `submitted_at`\n- `submitted_by`\n- `terminated_at`\n- `termination_reason`\n\n**Examples:**\n- `?sort=submitted_at` - Sort by creation time (ascending)\n- `?sort=-submitted_at` - Sort by creation time (descending)\n- `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending)\n", + "title": "Sort" + }, + "description": "Sort the results by one or more fields. Use `+` for ascending and `-` for descending order.\n\n**Available fields:**\n- `run_id`\n- `application_id`\n- `version_number`\n- `custom_metadata`\n- `submitted_at`\n- `submitted_by`\n- `terminated_at`\n- `termination_reason`\n\n**Examples:**\n- `?sort=submitted_at` - Sort by creation time (ascending)\n- `?sort=-submitted_at` - Sort by creation time (descending)\n- `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending)\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RunReadResponse" + }, + "title": "Response List Runs V1 Runs Get" + } + } + } + }, + "404": { + "description": "Run not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "Public" + ], + "summary": "Initiate Run", + "description": "This endpoint initiates a processing run for a selected application and version, and returns a `run_id` for tracking purposes.\n\nSlide processing occurs asynchronously, allowing you to retrieve results for individual slides as soon as they\ncomplete processing. The system typically processes slides in batches.\nBelow is an example of the required payload for initiating an Atlas H&E TME processing run.\n\n\n### Payload\n\nThe payload includes `application_id`, optional `version_number`, and `items` base fields.\n\n`application_id` is the unique identifier for the application.\n`version_number` is the semantic version to use. If not provided, the latest available version will be used.\n\n`items` includes the list of the items to process (slides, in case of HETA application).\nEvery item has a set of standard fields defined by the API, plus the custom_metadata, specific to the\nchosen application.\n\nExample payload structure with the comments:\n```\n{\n application_id: \"he-tme\",\n version_number: \"1.0.0-beta\",\n items: [{\n \"external_id\": \"slide_1\",\n \"custom_metadata\": {\"project\": \"sample-study\"},\n \"input_artifacts\": [{\n \"name\": \"user_slide\",\n \"download_url\": \"https://...\",\n \"metadata\": {\n \"specimen\": {\n \"disease\": \"LUNG_CANCER\",\n \"tissue\": \"LUNG\"\n },\n \"staining_method\": \"H&E\",\n \"width_px\": 136223,\n \"height_px\": 87761,\n \"resolution_mpp\": 0.2628238,\n \"media-type\":\"image/tiff\",\n \"checksum_base64_crc32c\": \"64RKKA==\"\n }\n }]\n }]\n}\n```\n\n| Parameter | Description |\n| :---- | :---- |\n| `application_id` required | Unique ID for the application |\n| `version_number` optional | Semantic version of the application. If not provided, the latest available version will be used |\n| `items` required | List of submitted items i.e. whole slide images (WSIs) with parameters described below. |\n| `external_id` required | Unique WSI name or ID for easy reference to items, provided by the caller. The `external_id` should be unique across all items of the run. |\n| `input_artifacts` required | List of provided artifacts for a WSI; at the moment Atlas H&E-TME receives only 1 artifact per slide (the slide itself), but for some other applications this can be a slide and a segmentation map |\n| `name` required | Type of artifact; Atlas H&E-TME supports only `\"input_slide\"` |\n| `download_url` required | Signed URL to the input file in the S3 or GCS; Should be valid for at least 6 days |\n| `specimen: disease` required | Supported cancer types for Atlas H&E-TME (see full list in Atlas H&E-TME manual) |\n| `specimen: tissue` required | Supported tissue types for Atlas H&E-TME (see full list in Atlas H&E-TME manual) |\n| `staining_method` required | WSI stain bio-marker; Atlas H&E-TME supports only `\"H&E\"` |\n| `width_px` required | Integer value. Number of pixels of the WSI in the X dimension. |\n| `height_px` required | Integer value. Number of pixels of the WSI in the Y dimension. |\n| `resolution_mpp` required | Resolution of WSI in micrometers per pixel; check allowed range in Atlas H&E-TME manual |\n| `media-type` required | Supported media formats; available values are: image/tiff (for .tiff or .tif WSI), application/dicom (for DICOM ), application/zip (for zipped DICOM), and application/octet-stream (for .svs WSI) |\n| `checksum_base64_crc32c` required | Base64-encoded big-endian CRC32C checksum of the WSI image |\n\n\n\n### Response\n\nThe endpoint returns the run UUID. After that, the job is scheduled for the execution in the background.\n\nTo check the status of the run, call `GET v1/runs/{run_id}` endpoint with the returned run UUID.\n\n### Rejection\n\nApart from the authentication, authorization, and malformed input error, the request can be\nrejected when specific quota limit is exceeded. More details on quotas is described in the\ndocumentation", + "operationId": "create_run_v1_runs_post", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunCreationRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunCreationResponse" + } + } + } + }, + "404": { + "description": "Application version not found" + }, + "403": { + "description": "Forbidden - You don't have permission to create this run" + }, + "400": { + "description": "Bad Request - Input validation failed" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get run details", + "description": "This endpoint allows the caller to retrieve the current status of a run along with other relevant run details.\n A run becomes available immediately after it is created through the `POST /v1/runs/` endpoint.\n\n To download the output results, use `GET /v1/runs/{run_id}/` items to get outputs for all slides.\nAccess to a run is restricted to the user who created it.", + "operationId": "get_run_v1_runs__run_id__get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /v1/runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /v1/runs/` endpoint" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunReadResponse" + } + } + } + }, + "404": { + "description": "Run not found because it was deleted." + }, + "403": { + "description": "Forbidden - You don't have permission to see this run" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/cancel": { + "post": { + "tags": [ + "Public" + ], + "summary": "Cancel Run", + "description": "The run can be canceled by the user who created the run.\n\nThe execution can be canceled any time while the run is not in the terminated state. The\npending items of a canceled run will not be processed and will not add to the cost.\n\nWhen the run is canceled, the already completed items remain available for download.", + "operationId": "cancel_run_v1_runs__run_id__cancel_post", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /runs/` endpoint" + } + ], + "responses": { + "202": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Run not found" + }, + "403": { + "description": "Forbidden - You don't have permission to cancel this run" + }, + "409": { + "description": "Conflict - The Run is already cancelled" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/items": { + "get": { + "tags": [ + "Public" + ], + "summary": "List Run Items", + "description": "List items in a run with filtering, sorting, and pagination capabilities.\n\nReturns paginated items within a specific run. Results can be filtered\nby `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions.\n\n## JSONPath Metadata Filtering\nUse PostgreSQL JSONPath expressions to filter items using their custom_metadata.\n\n### Examples:\n- **Field existence**: `$.case_id` - Results that have a case_id field defined\n- **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority\n- **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence\n- **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed\n- **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds\n\n## Notes\n- JSONPath expressions are evaluated using PostgreSQL's `@?` operator\n- The `$.` prefix is automatically added to root-level field references if missing\n- String values in conditions must be enclosed in double quotes\n- Use `&&` for AND operations and `||` for OR operations", + "operationId": "list_run_items_v1_runs__run_id__items_get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /v1/runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /v1/runs/` endpoint" + }, + { + "name": "item_id__in", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + { + "type": "null" + } + ], + "description": "Filter for item ids", + "title": "Item Id In" + }, + "description": "Filter for item ids" + }, + { + "name": "external_id__in", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Filter for items by their external_id from the input payload", + "title": "External Id In" + }, + "description": "Filter for items by their external_id from the input payload" + }, + { + "name": "state", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/ItemState" + }, + { + "type": "null" + } + ], + "description": "Filter items by their state", + "title": "State" + }, + "description": "Filter items by their state" + }, + { + "name": "termination_reason", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/ItemTerminationReason" + }, + { + "type": "null" + } + ], + "description": "Filter items by their termination reason. Only applies to TERMINATED items.", + "title": "Termination Reason" + }, + "description": "Filter items by their termination reason. Only applies to TERMINATED items." + }, + { + "name": "custom_metadata", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "maxLength": 1000 + }, + { + "type": "null" + } + ], + "description": "JSONPath expression to filter items by their custom_metadata", + "title": "Custom Metadata" + }, + "description": "JSONPath expression to filter items by their custom_metadata", + "examples": { + "no_filter": { + "summary": "No filter (returns all)", + "description": "Returns all items without filtering by custom metadata", + "value": "$" + }, + "field_exists": { + "summary": "Check if field exists", + "description": "Find items that have a project field defined", + "value": "$.project" + }, + "field_has_value": { + "summary": "Check if field has a certain value", + "description": "Compare a field value against a certain value", + "value": "$.project ? (@ == \"cancer-research\")" + }, + "numeric_comparisons": { + "summary": "Compare to a numeric value of a field", + "description": "Compare a field value against a numeric value of a field", + "value": "$.duration_hours ? (@ < 2)" + }, + "array_operations": { + "summary": "Check if an array contains a certain value", + "description": "Check if an array contains a certain value", + "value": "$.tags[*] ? (@ == \"production\")" + }, + "complex_filters": { + "summary": "Combine multiple checks", + "description": "Combine multiple checks", + "value": "$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)" + } + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "title": "Page" + } + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 5, + "default": 50, + "title": "Page Size" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Sort the items by one or more fields. Use `+` for ascending and `-` for descending order.\n **Available fields:**\n- `item_id`\n- `external_id`\n- `custom_metadata`\n- `terminated_at`\n- `termination_reason`\n\n**Examples:**\n- `?sort=item_id` - Sort by id of the item (ascending)\n- `?sort=-external_id` - Sort by external ID (descending)\n- `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)", + "title": "Sort" + }, + "description": "Sort the items by one or more fields. Use `+` for ascending and `-` for descending order.\n **Available fields:**\n- `item_id`\n- `external_id`\n- `custom_metadata`\n- `terminated_at`\n- `termination_reason`\n\n**Examples:**\n- `?sort=item_id` - Sort by id of the item (ascending)\n- `?sort=-external_id` - Sort by external ID (descending)\n- `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ItemResultReadResponse" + }, + "title": "Response List Run Items V1 Runs Run Id Items Get" + } + } + } + }, + "404": { + "description": "Run not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/items/{external_id}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get Item By Run", + "description": "Retrieve details of a specific item (slide) by its external ID and the run ID.", + "operationId": "get_item_by_run_v1_runs__run_id__items__external_id__get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "The run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "The run id, returned by `POST /runs/` endpoint" + }, + { + "name": "external_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "description": "The `external_id` that was defined for the item by the customer that triggered the run.", + "title": "External Id" + }, + "description": "The `external_id` that was defined for the item by the customer that triggered the run." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemResultReadResponse" + } + } + } + }, + "404": { + "description": "Not Found - Item with given ID does not exist" + }, + "403": { + "description": "Forbidden - You don't have permission to see this item" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/artifacts/{artifact_id}/file": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get Artifact Url", + "description": "Download the artifact file with the specified artifact_id, belonging to the specified run.\nThe artifact_is is returned by the `GET /v1/runs/{run_id}/items` endpoint as part of the item results, and can also\nbe retrieved via `GET /v1/runs/{run_id}/items/{external_id}`.\n\nThe endpoint may return a redirect response with a presigned URL to download the artifact file from the storage\nbucket. The presigned URL is valid for a limited time, so it should be used immediately after receiving the response.", + "operationId": "get_artifact_url_v1_runs__run_id__artifacts__artifact_id__file_get", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /runs/` endpoint" + }, + { + "name": "artifact_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "The artifact id to download", + "title": "Artifact Id" + }, + "description": "The artifact id to download" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Not Found - Artifact not found for the specified run" + }, + "307": { + "description": "Temporary Redirect - Redirect to the artifact file URL" + }, + "403": { + "description": "Forbidden - You don't have permission to download this artifact" + }, + "410": { + "description": "Gone - Artifact has been deleted" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/artifacts": { + "delete": { + "tags": [ + "Public" + ], + "summary": "Delete Run Items", + "description": "This endpoint allows the caller to explicitly delete artifacts generated by a run.\nIt can only be invoked when the run has reached a final state, i.e.\n`PROCESSED`, `CANCELED_SYSTEM`, or `CANCELED_USER`.\nNote that by default, all artifacts are automatically deleted 30 days after the run finishes,\nregardless of whether the caller explicitly requests such deletion.", + "operationId": "delete_run_items_v1_runs__run_id__artifacts_delete", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /runs/` endpoint" + } + ], + "responses": { + "200": { + "description": "Run artifacts deleted", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Run not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/custom-metadata": { + "put": { + "tags": [ + "Public" + ], + "summary": "Put Run Custom Metadata", + "description": "Update the custom metadata of a run with the specified `run_id`.\n\nOptionally, a checksum may be provided along the custom metadata JSON.\nIt can be used to verify if the custom metadata was updated since the last time it was accessed.\nIf the checksum is provided, it must match the existing custom metadata in the system, ensuring that the current\ncustom metadata value to be overwritten is acknowledged by the user.\nIf no checksum is provided, submitted metadata directly overwrites the existing metadata, without any checks.\n\nThe latest custom metadata and checksum can be retrieved for the run via the `GET /v1/runs/{run_id}` endpoint.\n\n**Note on deadlines:** Run deadlines must be set during run creation and cannot be modified afterward.\nAny deadline changes in custom metadata will be ignored by the system.", + "operationId": "put_run_custom_metadata_v1_runs__run_id__custom_metadata_put", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "Run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "Run id, returned by `POST /runs/` endpoint" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomMetadataUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Custom metadata successfully updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomMetadataUpdateResponse" + } + } + } + }, + "404": { + "description": "Run not found" + }, + "403": { + "description": "Forbidden - You don't have permission to update this run" + }, + "412": { + "description": "Precondition Failed - Checksum mismatch, resource has been modified" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/runs/{run_id}/items/{external_id}/custom-metadata": { + "put": { + "tags": [ + "Public" + ], + "summary": "Put Item Custom Metadata By Run", + "description": "Update the custom metadata of the item with the specified `external_id`, belonging to the specified run.\n\nOptionally, a checksum may be provided along the custom metadata JSON.\nIt can be used to verify if the custom metadata was updated since the last time it was accessed.\nIf the checksum is provided, it must match the existing custom metadata in the system, ensuring that the current\ncustom metadata value to be overwritten is acknowledged by the user.\nIf no checksum is provided, submitted metadata directly overwrites the existing metadata, without any checks.\n\nThe latest custom metadata and checksum can be retrieved\n for individual items via `GET /v1/runs/{run_id}/items/{external_id}`,\n and for all items of a run via `GET /v1/runs/{run_id}/items`.", + "operationId": "put_item_custom_metadata_by_run_v1_runs__run_id__items__external_id__custom_metadata_put", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "run_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "description": "The run id, returned by `POST /runs/` endpoint", + "title": "Run Id" + }, + "description": "The run id, returned by `POST /runs/` endpoint" + }, + { + "name": "external_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "description": "The `external_id` that was defined for the item by the customer that triggered the run.", + "title": "External Id" + }, + "description": "The `external_id` that was defined for the item by the customer that triggered the run." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomMetadataUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Custom metadata successfully updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomMetadataUpdateResponse" + } + } + } + }, + "403": { + "description": "Forbidden - You don't have permission to update this item" + }, + "404": { + "description": "Item not found" + }, + "412": { + "description": "Precondition Failed - Checksum mismatch" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/me": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get current user", + "description": "Retrieves your identity details, including name, email, and organization.\nThis is useful for verifying that the request is being made under the correct user profile\nand organization context, as well as confirming that the expected environment variables are correctly set\n(in case you are using Python SDK)", + "operationId": "get_me_v1_me_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MeReadResponse" + } + } + } + } + }, + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ] + } + }, + "/v1/applications/{application_id}/versions/{version}/documents": { + "get": { + "tags": [ + "Public" + ], + "summary": "List version documents", + "description": "List public documents attached to an application version.\n\nReturns only documents with ``visibility=public`` and ``status=uploaded``.", + "operationId": "list_version_documents", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VersionDocumentResponse" + }, + "title": "Response List Version Documents" + } + } + } + }, + "404": { + "description": "Application version not found or not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get version document metadata", + "description": "Return metadata for a single public document attached to an application version.", + "operationId": "get_version_document", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VersionDocumentResponse" + } + } + } + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}/file": { + "get": { + "tags": [ + "Public" + ], + "summary": "Download version document (browser)", + "description": "307 redirect to a short-lived GCS signed URL for downloading a document.\n\nThe signed URL includes ``response-content-disposition=attachment; filename=\"\"``\nso browsers prompt a save-as dialog rather than rendering inline.\nResponse carries ``Cache-Control: no-store``.", + "operationId": "get_version_document_file", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "307": { + "description": "Temporary redirect to signed GCS URL with Content-Disposition: attachment" + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}/content": { + "get": { + "tags": [ + "Public" + ], + "summary": "Stream version document content (programmatic)", + "description": "307 redirect to a short-lived GCS signed URL for streaming document content.\n\nUnlike ``/file``, no ``Content-Disposition`` override is set — GCS serves\nthe object body with its stored ``Content-Type``. Intended for programmatic\nclients that follow redirects and consume the content directly.\nResponse carries ``Cache-Control: no-store``.", + "operationId": "get_version_document_content", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "307": { + "description": "Temporary redirect to signed GCS URL; GCS serves the object with its stored Content-Type" + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ApplicationReadResponse": { + "properties": { + "application_id": { + "type": "string", + "title": "Application Id", + "description": "Application ID", + "examples": [ + "he-tme" + ] + }, + "name": { + "type": "string", + "title": "Name", + "description": "Application display name", + "examples": [ + "Atlas H&E-TME" + ] + }, + "regulatory_classes": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Regulatory Classes", + "description": "Regulatory classes, to which the applications comply with. Possible values include: RUO, IVDR, FDA.", + "examples": [ + [ + "RUO" + ] + ] + }, + "description": { + "type": "string", + "title": "Description", + "description": "Describing what the application can do ", + "examples": [ + "The Atlas H&E TME is an AI application designed to examine FFPE (formalin-fixed, paraffin-embedded) tissues stained with H&E (hematoxylin and eosin), delivering comprehensive insights into the tumor microenvironment." + ] + }, + "versions": { + "items": { + "$ref": "#/components/schemas/ApplicationVersion" + }, + "type": "array", + "title": "Versions", + "description": "All version numbers available to the user" + } + }, + "type": "object", + "required": [ + "application_id", + "name", + "regulatory_classes", + "description", + "versions" + ], + "title": "ApplicationReadResponse", + "description": "Response schema for `List available applications` and `Read Application by Id` endpoints" + }, + "ApplicationReadShortResponse": { + "properties": { + "application_id": { + "type": "string", + "title": "Application Id", + "description": "Application ID", + "examples": [ + "he-tme" + ] + }, + "name": { + "type": "string", + "title": "Name", + "description": "Application display name", + "examples": [ + "Atlas H&E-TME" + ] + }, + "regulatory_classes": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Regulatory Classes", + "description": "Regulatory classes, to which the applications comply with. Possible values include: RUO, IVDR, FDA.", + "examples": [ + [ + "RUO" + ] + ] + }, + "description": { + "type": "string", + "title": "Description", + "description": "Describing what the application can do ", + "examples": [ + "The Atlas H&E TME is an AI application designed to examine FFPE (formalin-fixed, paraffin-embedded) tissues stained with H&E (hematoxylin and eosin), delivering comprehensive insights into the tumor microenvironment." + ] + }, + "latest_version": { + "anyOf": [ + { + "$ref": "#/components/schemas/ApplicationVersion" + }, + { + "type": "null" + } + ], + "description": "The version with highest version number available to the user" + } + }, + "type": "object", + "required": [ + "application_id", + "name", + "regulatory_classes", + "description" + ], + "title": "ApplicationReadShortResponse", + "description": "Response schema for `List available applications` and `Read Application by Id` endpoints" + }, + "ApplicationVersion": { + "properties": { + "number": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "title": "Number", + "description": "The number of the latest version", + "examples": [ + "1.0.0" + ] + }, + "released_at": { + "type": "string", + "format": "date-time", + "title": "Released At", + "description": "The timestamp for when the application version was made available in the Platform", + "examples": [ + "2025-09-15T10:30:45.123Z" + ] + } + }, + "type": "object", + "required": [ + "number", + "released_at" + ], + "title": "ApplicationVersion" + }, + "ArtifactOutput": { + "type": "string", + "enum": [ + "NONE", + "AVAILABLE", + "DELETED_BY_USER", + "DELETED_BY_SYSTEM" + ], + "title": "ArtifactOutput" + }, + "ArtifactState": { + "type": "string", + "enum": [ + "PENDING", + "PROCESSING", + "TERMINATED" + ], + "title": "ArtifactState" + }, + "ArtifactTerminationReason": { + "type": "string", + "enum": [ + "SUCCEEDED", + "USER_ERROR", + "SYSTEM_ERROR", + "SKIPPED" + ], + "title": "ArtifactTerminationReason" + }, + "CustomMetadataUpdateRequest": { + "properties": { + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata", + "description": "JSON metadata that should be set for the run", + "examples": [ + { + "department": "D1", + "study": "abc-1" + } + ] + }, + "custom_metadata_checksum": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata Checksum", + "description": "Optional field to verify that the latest custom metadata was known. If set to the checksum retrieved via the /runs endpoint, it must match the checksum of the current value in the database.", + "examples": [ + "f54fe109" + ] + } + }, + "type": "object", + "title": "CustomMetadataUpdateRequest" + }, + "CustomMetadataUpdateResponse": { + "properties": { + "custom_metadata_checksum": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata Checksum", + "description": "The checksum of the updated custom metadata. If the `custom_metadata` is None,\nthe checksum also None.", + "readOnly": true + } + }, + "type": "object", + "required": [ + "custom_metadata_checksum" + ], + "title": "CustomMetadataUpdateResponse" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "InputArtifact": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "mime_type": { + "type": "string", + "pattern": "^\\w+\\/\\w+[-+.|\\w+]+\\w+$", + "title": "Mime Type", + "examples": [ + "image/tiff" + ] + }, + "metadata_schema": { + "additionalProperties": true, + "type": "object", + "title": "Metadata Schema" + } + }, + "type": "object", + "required": [ + "name", + "mime_type", + "metadata_schema" + ], + "title": "InputArtifact" + }, + "InputArtifactCreationRequest": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Type of artifact. For Atlas H&E-TME, use \"input_slide\"", + "examples": [ + "input_slide" + ] + }, + "download_url": { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri", + "title": "Download Url", + "description": "[Signed URL](https://cloud.google.com/cdn/docs/using-signed-urls) to the input artifact file. The URL should be valid for at least 6 days from the payload submission time.", + "examples": [ + "https://example.com/case-no-1-slide.tiff" + ] + }, + "metadata": { + "additionalProperties": true, + "type": "object", + "title": "Metadata", + "description": "The metadata of the artifact, required by the application version. The JSON schema of the metadata can be requested by `/v1/versions/{application_version_id}`. The schema is located in `input_artifacts.[].metadata_schema`", + "examples": [ + { + "checksum_base64_crc32c": "752f9554", + "height": 2000, + "height_mpp": 0.5, + "width": 10000, + "width_mpp": 0.5 + } + ] + } + }, + "type": "object", + "required": [ + "name", + "download_url", + "metadata" + ], + "title": "InputArtifactCreationRequest", + "description": "Input artifact containing the slide image and associated metadata." + }, + "InputArtifactResultReadResponse": { + "properties": { + "input_artifact_id": { + "type": "string", + "format": "uuid", + "title": "Input Artifact Id", + "description": "The Id of the artifact. Used internally" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the input from the schema from the `/v1/versions/{version_id}` endpoint.", + "examples": [ + "whole_slide_image" + ] + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Metadata", + "description": "The metadata of the input artifact, provided by the user." + }, + "download_url": { + "anyOf": [ + { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri" + }, + { + "type": "null" + } + ], + "title": "Download Url", + "description": "The download URL to for the input artifact provided by the user." + } + }, + "type": "object", + "required": [ + "input_artifact_id", + "name" + ], + "title": "InputArtifactResultReadResponse" + }, + "ItemCreationRequest": { + "properties": { + "external_id": { + "type": "string", + "maxLength": 255, + "title": "External Id", + "description": "Unique identifier for this item within the run. Used for referencing items. Must be unique across all items in the same run", + "examples": [ + "slide_1", + "patient_001_slide_A", + "sample_12345" + ] + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata", + "description": "Optional JSON custom_metadata to store additional information alongside an item.", + "examples": [ + { + "case": "abc" + } + ] + }, + "input_artifacts": { + "items": { + "$ref": "#/components/schemas/InputArtifactCreationRequest" + }, + "type": "array", + "title": "Input Artifacts", + "description": "List of input artifacts for this item. For Atlas H&E-TME, typically contains one artifact (the slide image)", + "examples": [ + [ + { + "download_url": "https://example-bucket.s3.amazonaws.com/slide1.tiff", + "metadata": { + "checksum_base64_crc32c": "64RKKA==", + "height_px": 87761, + "media-type": "image/tiff", + "resolution_mpp": 0.2628238, + "specimen": { + "disease": "LUNG_CANCER", + "tissue": "LUNG" + }, + "staining_method": "H&E", + "width_px": 136223 + }, + "name": "input_slide" + } + ] + ] + } + }, + "type": "object", + "required": [ + "external_id", + "input_artifacts" + ], + "title": "ItemCreationRequest", + "description": "Individual item (slide) to be processed in a run." + }, + "ItemOutput": { + "type": "string", + "enum": [ + "NONE", + "FULL" + ], + "title": "ItemOutput" + }, + "ItemResultReadResponse": { + "properties": { + "item_id": { + "type": "string", + "format": "uuid", + "title": "Item Id", + "description": "Item UUID generated by the Platform" + }, + "external_id": { + "type": "string", + "title": "External Id", + "description": "The external_id of the item from the user payload", + "examples": [ + "slide_1" + ] + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata", + "description": "The custom_metadata of the item that has been provided by the user on run creation." + }, + "custom_metadata_checksum": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata Checksum", + "description": "The checksum of the `custom_metadata` field.\nCan be used in the `PUT /runs/{run-id}/items/{external_id}/custom_metadata`\nrequest to avoid unwanted override of the values in concurrent requests.", + "examples": [ + "f54fe109" + ] + }, + "queue_position_org": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Queue Position Org", + "description": "The position of the item in the organization's queue." + }, + "queue_position_platform": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Queue Position Platform", + "description": "The position of the item in the platform's queue." + }, + "state": { + "$ref": "#/components/schemas/ItemState", + "description": "\nThe item moves from `PENDING` to `PROCESSING` to `TERMINATED` state.\nWhen terminated, consult the `termination_reason` property to see whether it was successful.\n " + }, + "output": { + "$ref": "#/components/schemas/ItemOutput", + "description": "The output status of the item (NONE, FULL)" + }, + "termination_reason": { + "anyOf": [ + { + "$ref": "#/components/schemas/ItemTerminationReason" + }, + { + "type": "null" + } + ], + "description": "\nWhen the `state` is `TERMINATED` this will explain why\n`SUCCEEDED` -> Successful processing.\n`USER_ERROR` -> Failed because the provided input was invalid.\n`SYSTEM_ERROR` -> There was an error in the model or platform.\n`SKIPPED` -> Was cancelled\n" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Code" + }, + "error_message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Message", + "description": "\n The error message in case the `termination_reason` is in `USER_ERROR` or `SYSTEM_ERROR`\n ", + "examples": [ + "This item was not processed because the threshold of 3 items finishing in error state (user or system error) was reached before the item was processed.", + "The item was not processed because the run was cancelled by the user before the item was processed.", + "User error raised by Application because the input data provided by the user cannot be processed:\nThe image width is 123000 px, but the maximum width is 100000 px", + "A system error occurred during the item execution:\n System went out of memory in cell classification", + "An unknown system error occurred during the item execution" + ] + }, + "terminated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Terminated At", + "description": "Timestamp showing when the item reached a terminal state.", + "examples": [ + "2024-01-15T10:30:45.123Z" + ] + }, + "input_artifacts": { + "items": { + "$ref": "#/components/schemas/InputArtifactResultReadResponse" + }, + "type": "array", + "title": "Input Artifacts", + "description": "\nThe input artifact(s) provided by the user. For most applications, this will be one artifact that\ndefines the whole slide image to be processed.\n " + }, + "output_artifacts": { + "items": { + "$ref": "#/components/schemas/OutputArtifactResultReadResponse" + }, + "type": "array", + "title": "Output Artifacts", + "description": "\nThe list of the results generated by the application algorithm. The number of files and their\ntypes depend on the particular application version, call `/v1/versions/{version_id}` to get\nthe details.\n " + } + }, + "type": "object", + "required": [ + "item_id", + "external_id", + "custom_metadata", + "state", + "output", + "input_artifacts", + "output_artifacts" + ], + "title": "ItemResultReadResponse", + "description": "Response schema for items in `List Run Items` endpoint" + }, + "ItemState": { + "type": "string", + "enum": [ + "PENDING", + "PROCESSING", + "TERMINATED" + ], + "title": "ItemState" + }, + "ItemTerminationReason": { + "type": "string", + "enum": [ + "SUCCEEDED", + "USER_ERROR", + "SYSTEM_ERROR", + "SKIPPED" + ], + "title": "ItemTerminationReason" + }, + "MeReadResponse": { + "properties": { + "user": { + "$ref": "#/components/schemas/UserReadResponse" + }, + "organization": { + "$ref": "#/components/schemas/OrganizationReadResponse" + } + }, + "type": "object", + "required": [ + "user", + "organization" + ], + "title": "MeReadResponse", + "description": "Response schema for `Get current user` endpoint" + }, + "OrganizationReadResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Unique organization identifier", + "examples": [ + "org_123456" + ] + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name", + "description": "Organization name (E.g. “aignx”)", + "examples": [ + "aignx" + ] + }, + "display_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Display Name", + "description": "Public organization name (E.g. “Aignostics GmbH”)", + "examples": [ + "Aignostics GmbH" + ] + }, + "aignostics_bucket_hmac_access_key_id": { + "type": "string", + "title": "Aignostics Bucket Hmac Access Key Id", + "description": "HMAC access key ID for the Aignostics-provided storage bucket. Used to authenticate requests for uploading files and generating signed URLs", + "examples": [ + "YOUR_HMAC_ACCESS_KEY_ID" + ] + }, + "aignostics_bucket_hmac_secret_access_key": { + "type": "string", + "title": "Aignostics Bucket Hmac Secret Access Key", + "description": "HMAC secret access key paired with the access key ID. Keep this credential secure.", + "examples": [ + "YOUR/HMAC/SECRET_ACCESS_KEY" + ] + }, + "aignostics_bucket_name": { + "type": "string", + "title": "Aignostics Bucket Name", + "description": "Name of the bucket provided by Aignostics for storing input artifacts (slide images)", + "examples": [ + "aignostics-platform-bucket" + ] + }, + "aignostics_bucket_protocol": { + "type": "string", + "title": "Aignostics Bucket Protocol", + "description": "Protocol to use for bucket access. Defines the URL scheme for connecting to the storage service", + "examples": [ + "gs" + ] + }, + "aignostics_logfire_token": { + "type": "string", + "title": "Aignostics Logfire Token", + "description": "Authentication token for Logfire observability service. Enables sending application logs and performance metrics to Aignostics for monitoring and support", + "examples": [ + "your-logfire-token" + ] + }, + "aignostics_sentry_dsn": { + "type": "string", + "title": "Aignostics Sentry Dsn", + "description": "Data Source Name (DSN) for Sentry error tracking service. Allows automatic reporting of errors and exceptions to Aignostics support team", + "examples": [ + "https://2354s3#ewsha@o44.ingest.us.sentry.io/34345123432" + ] + } + }, + "type": "object", + "required": [ + "id", + "aignostics_bucket_hmac_access_key_id", + "aignostics_bucket_hmac_secret_access_key", + "aignostics_bucket_name", + "aignostics_bucket_protocol", + "aignostics_logfire_token", + "aignostics_sentry_dsn" + ], + "title": "OrganizationReadResponse", + "description": "Part of response schema for Organization object in `Get current user` endpoint.\nThis model corresponds to the response schema returned from\nAuth0 GET /v2/organizations/{id} endpoint, flattens out the metadata out\nand doesn't return branding or token_quota objects.\nFor details, see:\nhttps://auth0.com/docs/api/management/v2/organizations/get-organizations-by-id\n\n#### Configuration for integrating with Aignostics Platform services.\n\nThe Aignostics Platform API requires signed URLs for input artifacts (slide images). To simplify this process,\nAignostics provides a dedicated storage bucket. The HMAC credentials below grant read and write\naccess to this bucket, allowing you to upload files and generate the signed URLs needed for API calls.\n\nAdditionally, logging and error reporting tokens enable Aignostics to provide better support and monitor\nsystem performance for your integration." + }, + "OutputArtifact": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "mime_type": { + "type": "string", + "pattern": "^\\w+\\/\\w+[-+.|\\w+]+\\w+$", + "title": "Mime Type", + "examples": [ + "application/vnd.apache.parquet" + ] + }, + "metadata_schema": { + "additionalProperties": true, + "type": "object", + "title": "Metadata Schema" + }, + "scope": { + "$ref": "#/components/schemas/OutputArtifactScope" + }, + "visibility": { + "$ref": "#/components/schemas/OutputArtifactVisibility" + } + }, + "type": "object", + "required": [ + "name", + "mime_type", + "metadata_schema", + "scope", + "visibility" + ], + "title": "OutputArtifact" + }, + "OutputArtifactResultReadResponse": { + "properties": { + "output_artifact_id": { + "type": "string", + "format": "uuid", + "title": "Output Artifact Id", + "description": "The Id of the artifact. Used internally" + }, + "name": { + "type": "string", + "title": "Name", + "description": "\nName of the output from the output schema from the `/v1/versions/{version_id}` endpoint.\n ", + "examples": [ + "tissue_qc:tiff_heatmap" + ] + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Metadata", + "description": "The metadata of the output artifact, provided by the application. Can only be None if the artifact itself was deleted." + }, + "state": { + "$ref": "#/components/schemas/ArtifactState", + "description": "The current state of the artifact (PENDING, PROCESSING, TERMINATED)" + }, + "termination_reason": { + "anyOf": [ + { + "$ref": "#/components/schemas/ArtifactTerminationReason" + }, + { + "type": "null" + } + ], + "description": "The reason for termination when state is TERMINATED" + }, + "output": { + "$ref": "#/components/schemas/ArtifactOutput", + "description": "The output status of the artifact (NONE, FULL)" + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Code" + }, + "error_message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Message" + }, + "download_url": { + "anyOf": [ + { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri" + }, + { + "type": "null" + } + ], + "title": "Download Url", + "description": "\nThe download URL to the output file. The URL is valid for 1 hour after the endpoint is called.\nA new URL is generated every time the endpoint is called.\n ", + "deprecated": true + } + }, + "type": "object", + "required": [ + "output_artifact_id", + "name", + "state", + "output" + ], + "title": "OutputArtifactResultReadResponse" + }, + "OutputArtifactScope": { + "type": "string", + "enum": [ + "ITEM", + "GLOBAL" + ], + "title": "OutputArtifactScope" + }, + "OutputArtifactVisibility": { + "type": "string", + "enum": [ + "INTERNAL", + "EXTERNAL" + ], + "title": "OutputArtifactVisibility" + }, + "RunCreationRequest": { + "properties": { + "application_id": { + "type": "string", + "title": "Application Id", + "description": "Unique ID for the application to use for processing", + "examples": [ + "he-tme" + ] + }, + "version_number": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Version Number", + "description": "Semantic version of the application to use for processing. If not provided, the latest available version will be used", + "examples": [ + "1.0.0-beta1" + ] + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata", + "description": "Optional JSON metadata to store additional information alongside the run", + "examples": [ + { + "department": "D1", + "study": "abc-1" + } + ] + }, + "scheduling": { + "anyOf": [ + { + "$ref": "#/components/schemas/SchedulingRequest" + }, + { + "type": "null" + } + ], + "description": "Optional scheduling constraints for this run.", + "examples": [ + { + "deadline": "2026-03-05T23:59:59Z", + "due_date": "2026-03-04T23:59:59Z" + } + ] + }, + "items": { + "items": { + "$ref": "#/components/schemas/ItemCreationRequest" + }, + "type": "array", + "minItems": 1, + "title": "Items", + "description": "List of items (slides) to process. Each item represents a whole slide image (WSI) with its associated metadata and artifacts", + "examples": [ + [ + { + "external_id": "slide_1", + "input_artifacts": [ + { + "download_url": "https://example-bucket.s3.amazonaws.com/slide1.tiff?signature=...", + "metadata": { + "checksum_base64_crc32c": "64RKKA==", + "height_px": 87761, + "media-type": "image/tiff", + "resolution_mpp": 0.2628238, + "specimen": { + "disease": "LUNG_CANCER", + "tissue": "LUNG" + }, + "staining_method": "H&E", + "width_px": 136223 + }, + "name": "input_slide" + } + ] + } + ] + ] + } + }, + "type": "object", + "required": [ + "application_id", + "items" + ], + "title": "RunCreationRequest", + "description": "Request schema for `Initiate Run` endpoint.\nIt describes which application version is chosen, and which user data should be processed." + }, + "RunCreationResponse": { + "properties": { + "run_id": { + "type": "string", + "format": "uuid", + "title": "Run Id", + "examples": [ + "3fa85f64-5717-4562-b3fc-2c963f66afa6" + ] + } + }, + "type": "object", + "required": [ + "run_id" + ], + "title": "RunCreationResponse" + }, + "RunItemStatistics": { + "properties": { + "item_count": { + "type": "integer", + "title": "Item Count", + "description": "Total number of the items in the run" + }, + "item_pending_count": { + "type": "integer", + "title": "Item Pending Count", + "description": "The number of items in `PENDING` state" + }, + "item_processing_count": { + "type": "integer", + "title": "Item Processing Count", + "description": "The number of items in `PROCESSING` state" + }, + "item_user_error_count": { + "type": "integer", + "title": "Item User Error Count", + "description": "The number of items in `TERMINATED` state, and the item termination reason is `USER_ERROR`" + }, + "item_system_error_count": { + "type": "integer", + "title": "Item System Error Count", + "description": "The number of items in `TERMINATED` state, and the item termination reason is `SYSTEM_ERROR`" + }, + "item_skipped_count": { + "type": "integer", + "title": "Item Skipped Count", + "description": "The number of items in `TERMINATED` state, and the item termination reason is `SKIPPED`" + }, + "item_succeeded_count": { + "type": "integer", + "title": "Item Succeeded Count", + "description": "The number of items in `TERMINATED` state, and the item termination reason is `SUCCEEDED`" + } + }, + "type": "object", + "required": [ + "item_count", + "item_pending_count", + "item_processing_count", + "item_user_error_count", + "item_system_error_count", + "item_skipped_count", + "item_succeeded_count" + ], + "title": "RunItemStatistics" + }, + "RunOutput": { + "type": "string", + "enum": [ + "NONE", + "PARTIAL", + "FULL" + ], + "title": "RunOutput" + }, + "RunReadResponse": { + "properties": { + "run_id": { + "type": "string", + "format": "uuid", + "title": "Run Id", + "description": "UUID of the application" + }, + "application_id": { + "type": "string", + "title": "Application Id", + "description": "Application id", + "examples": [ + "he-tme" + ] + }, + "version_number": { + "type": "string", + "title": "Version Number", + "description": "Application version number", + "examples": [ + "0.4.4" + ] + }, + "state": { + "$ref": "#/components/schemas/RunState", + "description": "When the run request is received by the Platform, the `state` of it is set to\n`PENDING`. The state changes to `PROCESSING` when at least one item is being processed. After `PROCESSING`, the\nstate of the run can switch back to `PENDING` if there are no processing items, or to `TERMINATED` when the run\nfinished processing." + }, + "output": { + "$ref": "#/components/schemas/RunOutput", + "description": "The status of the output of the run. When 0 items are successfully processed the output is\n`NONE`, after one item is successfully processed, the value is set to `PARTIAL`. When all items of the run are\nsuccessfully processed, the output is set to `FULL`." + }, + "termination_reason": { + "anyOf": [ + { + "$ref": "#/components/schemas/RunTerminationReason" + }, + { + "type": "null" + } + ], + "description": "The termination reason of the run. When the run is not in `TERMINATED` state, the\n termination_reason is `null`. If all items of of the run are processed (successfully or with an error), then\n termination_reason is set to `ALL_ITEMS_PROCESSED`. If the run is cancelled by the user, the value is set to\n `CANCELED_BY_USER`. If the run reaches the threshold of number of failed items, the Platform cancels the run\n and sets the termination_reason to `CANCELED_BY_SYSTEM`.\n " + }, + "error_code": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Code", + "description": "When the termination_reason is set to CANCELED_BY_SYSTEM, the error_code is set to define the\n structured description of the error.", + "examples": [ + "SCHEDULER.ITEMS_WITH_ERROR_THRESHOLD_REACHED" + ] + }, + "error_message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Message", + "description": "When the termination_reason is set to CANCELED_BY_SYSTEM, the error_message is set to provide\n more insights to the error cause.", + "examples": [ + "Run canceled given errors on more than 10 items." + ] + }, + "statistics": { + "$ref": "#/components/schemas/RunItemStatistics", + "description": "Aggregated statistics of the run execution" + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata", + "description": "Optional JSON metadata that was stored in alongside the run by the user", + "examples": [ + { + "department": "D1", + "study": "abc-1" + } + ] + }, + "custom_metadata_checksum": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata Checksum", + "description": "The checksum of the `custom_metadata` field. Can be used in the `PUT /runs/{run-id}/custom_metadata`\nrequest to avoid unwanted override of the values in concurrent requests.", + "examples": [ + "f54fe109" + ] + }, + "submitted_at": { + "type": "string", + "format": "date-time", + "title": "Submitted At", + "description": "Timestamp showing when the run was triggered" + }, + "submitted_by": { + "type": "string", + "title": "Submitted By", + "description": "Id of the user who triggered the run", + "examples": [ + "auth0|123456" + ] + }, + "terminated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Terminated At", + "description": "Timestamp showing when the run reached a terminal state.", + "examples": [ + "2024-01-15T10:30:45.123Z" + ] + }, + "num_preceding_items_org": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Num Preceding Items Org", + "description": "How many Items from other Runs in the same Organization are due to begin processing before this Run's next Item does." + }, + "num_preceding_items_platform": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Num Preceding Items Platform", + "description": "How many Items from other Runs are due to begin processing before this Run's next Item does." + }, + "scheduling": { + "anyOf": [ + { + "$ref": "#/components/schemas/SchedulingResponse" + }, + { + "type": "null" + } + ], + "description": "Scheduling constraints set for this run." + } + }, + "type": "object", + "required": [ + "run_id", + "application_id", + "version_number", + "state", + "output", + "termination_reason", + "error_code", + "error_message", + "statistics", + "submitted_at", + "submitted_by" + ], + "title": "RunReadResponse", + "description": "Response schema for `Get run details` endpoint" + }, + "RunState": { + "type": "string", + "enum": [ + "PENDING", + "PROCESSING", + "TERMINATED" + ], + "title": "RunState" + }, + "RunTerminationReason": { + "type": "string", + "enum": [ + "ALL_ITEMS_PROCESSED", + "CANCELED_BY_SYSTEM", + "CANCELED_BY_USER" + ], + "title": "RunTerminationReason" + }, + "SchedulingRequest": { + "properties": { + "due_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Due Date", + "description": "Requested completion time. Items are prioritized to meet this target.", + "examples": [ + "2026-03-04T23:59:59Z" + ] + }, + "deadline": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Deadline", + "description": "Hard deadline. The run will be cancelled if not completed by this time.", + "examples": [ + "2026-03-05T23:59:59Z" + ] + } + }, + "type": "object", + "title": "SchedulingRequest", + "description": "Scheduling constraints for a run." + }, + "SchedulingResponse": { + "properties": { + "due_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Due Date" + }, + "deadline": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Deadline" + } + }, + "type": "object", + "title": "SchedulingResponse", + "description": "Scheduling fields returned in run responses." + }, + "UserReadResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Unique user identifier", + "examples": [ + "auth0|123456" + ] + }, + "email": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Email", + "description": "User email", + "examples": [ + "user@domain.com" + ] + }, + "email_verified": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Email Verified", + "examples": [ + true + ] + }, + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name", + "description": "First and last name of the user", + "examples": [ + "Jane Doe" + ] + }, + "given_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Given Name", + "examples": [ + "Jane" + ] + }, + "family_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Family Name", + "examples": [ + "Doe" + ] + }, + "nickname": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Nickname", + "examples": [ + "jdoe" + ] + }, + "picture": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Picture", + "examples": [ + "https://example.com/jdoe.jpg" + ] + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At", + "examples": [ + "2023-10-05T14:48:00.000Z" + ] + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "UserReadResponse", + "description": "Part of response schema for User object in `Get current user` endpoint.\nThis model corresponds to the response schema returned from\nAuth0 GET /v2/users/{id} endpoint.\nFor details, see:\nhttps://auth0.com/docs/api/management/v2/users/get-users-by-id" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + }, + "input": { + "title": "Input" + }, + "ctx": { + "type": "object", + "title": "Context" + } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" + }, + "VersionDocumentResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "Id" + }, + "name": { + "type": "string", + "title": "Name" + }, + "mime_type": { + "type": "string", + "title": "Mime Type" + }, + "visibility": { + "$ref": "#/components/schemas/VersionDocumentVisibility" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At" + } + }, + "type": "object", + "required": [ + "id", + "name", + "mime_type", + "visibility", + "created_at", + "updated_at" + ], + "title": "VersionDocumentResponse" + }, + "VersionDocumentVisibility": { + "type": "string", + "enum": [ + "public", + "internal" + ], + "title": "VersionDocumentVisibility" + }, + "VersionReadResponse": { + "properties": { + "version_number": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "title": "Version Number", + "description": "Semantic version of the application" + }, + "changelog": { + "type": "string", + "title": "Changelog", + "description": "Description of the changes relative to the previous version" + }, + "input_artifacts": { + "items": { + "$ref": "#/components/schemas/InputArtifact" + }, + "type": "array", + "title": "Input Artifacts", + "description": "List of the input fields, provided by the User" + }, + "output_artifacts": { + "items": { + "$ref": "#/components/schemas/OutputArtifact" + }, + "type": "array", + "title": "Output Artifacts", + "description": "List of the output fields, generated by the application" + }, + "released_at": { + "type": "string", + "format": "date-time", + "title": "Released At", + "description": "The timestamp when the application version was registered" + } + }, + "type": "object", + "required": [ + "version_number", + "changelog", + "input_artifacts", + "output_artifacts", + "released_at" + ], + "title": "VersionReadResponse", + "description": "Base Response schema for the `Application Version Details` endpoint" + } + }, + "securitySchemes": { + "OAuth2AuthorizationCodeBearer": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "scopes": {}, + "authorizationUrl": "https://aignostics-platform-staging.eu.auth0.com/authorize", + "tokenUrl": "https://aignostics-platform-staging.eu.auth0.com/oauth/token" + } + } + } + } + } +} diff --git a/codegen/in/openapi.json b/codegen/in/openapi.json index cae9e0200..1e0c6e0e4 100644 --- a/codegen/in/openapi.json +++ b/codegen/in/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "Aignostics Platform API", "description": "\nThe Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. \n\nTo begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. \n\nMore information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com).\n\n**How to authorize and test API endpoints:**\n\n1. Click the \"Authorize\" button in the right corner below\n3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials\n4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint\n\n**Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized.\n\n", - "version": "1.4.0" + "version": "1.5.0" }, "servers": [ { @@ -1425,6 +1425,263 @@ } ] } + }, + "/v1/applications/{application_id}/versions/{version}/documents": { + "get": { + "tags": [ + "Public" + ], + "summary": "List version documents", + "description": "List public documents attached to an application version.\n\nReturns only documents with ``visibility=public`` and ``status=uploaded``.", + "operationId": "list_version_documents", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VersionDocumentResponse" + }, + "title": "Response List Version Documents" + } + } + } + }, + "404": { + "description": "Application version not found or not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}": { + "get": { + "tags": [ + "Public" + ], + "summary": "Get version document metadata", + "description": "Return metadata for a single public document attached to an application version.", + "operationId": "get_version_document", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VersionDocumentResponse" + } + } + } + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}/file": { + "get": { + "tags": [ + "Public" + ], + "summary": "Download version document (browser)", + "description": "307 redirect to a short-lived GCS signed URL for downloading a document.\n\nThe signed URL includes ``response-content-disposition=attachment; filename=\"\"``\nso browsers prompt a save-as dialog rather than rendering inline.\nResponse carries ``Cache-Control: no-store``.", + "operationId": "get_version_document_file", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "307": { + "description": "Temporary redirect to signed GCS URL with Content-Disposition: attachment" + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/v1/applications/{application_id}/versions/{version}/documents/{name}/content": { + "get": { + "tags": [ + "Public" + ], + "summary": "Stream version document content (programmatic)", + "description": "307 redirect to a short-lived GCS signed URL for streaming document content.\n\nUnlike ``/file``, no ``Content-Disposition`` override is set — GCS serves\nthe object body with its stored ``Content-Type``. Intended for programmatic\nclients that follow redirects and consume the content directly.\nResponse carries ``Cache-Control: no-store``.", + "operationId": "get_version_document_content", + "security": [ + { + "OAuth2AuthorizationCodeBearer": [] + } + ], + "parameters": [ + { + "name": "application_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Application Id" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Version" + } + }, + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Name" + } + } + ], + "responses": { + "307": { + "description": "Temporary redirect to signed GCS URL; GCS serves the object with its stored Content-Type" + }, + "404": { + "description": "Document not found, not public, or version not accessible" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } } }, "components": { @@ -1755,6 +2012,58 @@ "title": "InputArtifactCreationRequest", "description": "Input artifact containing the slide image and associated metadata." }, + "InputArtifactResultReadResponse": { + "properties": { + "input_artifact_id": { + "type": "string", + "format": "uuid", + "title": "Input Artifact Id", + "description": "The Id of the artifact. Used internally" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the input from the schema from the `/v1/versions/{version_id}` endpoint.", + "examples": [ + "whole_slide_image" + ] + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Metadata", + "description": "The metadata of the input artifact, provided by the user." + }, + "download_url": { + "anyOf": [ + { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri" + }, + { + "type": "null" + } + ], + "title": "Download Url", + "description": "The download URL to for the input artifact provided by the user." + } + }, + "type": "object", + "required": [ + "input_artifact_id", + "name" + ], + "title": "InputArtifactResultReadResponse" + }, "ItemCreationRequest": { "properties": { "external_id": { @@ -1964,6 +2273,14 @@ "2024-01-15T10:30:45.123Z" ] }, + "input_artifacts": { + "items": { + "$ref": "#/components/schemas/InputArtifactResultReadResponse" + }, + "type": "array", + "title": "Input Artifacts", + "description": "\nThe input artifact(s) provided by the user. For most applications, this will be one artifact that\ndefines the whole slide image to be processed.\n " + }, "output_artifacts": { "items": { "$ref": "#/components/schemas/OutputArtifactResultReadResponse" @@ -1980,6 +2297,7 @@ "custom_metadata", "state", "output", + "input_artifacts", "output_artifacts" ], "title": "ItemResultReadResponse", @@ -2906,6 +3224,54 @@ ], "title": "ValidationError" }, + "VersionDocumentResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "Id" + }, + "name": { + "type": "string", + "title": "Name" + }, + "mime_type": { + "type": "string", + "title": "Mime Type" + }, + "visibility": { + "$ref": "#/components/schemas/VersionDocumentVisibility" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At" + } + }, + "type": "object", + "required": [ + "id", + "name", + "mime_type", + "visibility", + "created_at", + "updated_at" + ], + "title": "VersionDocumentResponse" + }, + "VersionDocumentVisibility": { + "type": "string", + "enum": [ + "public", + "internal" + ], + "title": "VersionDocumentVisibility" + }, "VersionReadResponse": { "properties": { "version_number": { diff --git a/codegen/out/.openapi-generator/FILES b/codegen/out/.openapi-generator/FILES index ee99c756f..56c6dba42 100644 --- a/codegen/out/.openapi-generator/FILES +++ b/codegen/out/.openapi-generator/FILES @@ -14,6 +14,7 @@ aignx/codegen/models/custom_metadata_update_response.py aignx/codegen/models/http_validation_error.py aignx/codegen/models/input_artifact.py aignx/codegen/models/input_artifact_creation_request.py +aignx/codegen/models/input_artifact_result_read_response.py aignx/codegen/models/item_creation_request.py aignx/codegen/models/item_output.py aignx/codegen/models/item_result_read_response.py @@ -37,6 +38,8 @@ aignx/codegen/models/scheduling_response.py aignx/codegen/models/user_read_response.py aignx/codegen/models/validation_error.py aignx/codegen/models/validation_error_loc_inner.py +aignx/codegen/models/version_document_response.py +aignx/codegen/models/version_document_visibility.py aignx/codegen/models/version_read_response.py aignx/codegen/rest.py docs/PublicApi.md diff --git a/codegen/out/aignx/codegen/api/public_api.py b/codegen/out/aignx/codegen/api/public_api.py index fdaaedae8..1a74d4508 100644 --- a/codegen/out/aignx/codegen/api/public_api.py +++ b/codegen/out/aignx/codegen/api/public_api.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. @@ -30,6 +30,7 @@ from aignx.codegen.models.run_creation_request import RunCreationRequest from aignx.codegen.models.run_creation_response import RunCreationResponse from aignx.codegen.models.run_read_response import RunReadResponse +from aignx.codegen.models.version_document_response import VersionDocumentResponse from aignx.codegen.models.version_read_response import VersionReadResponse from aignx.codegen.api_client import ApiClient, RequestSerialized @@ -2254,11 +2255,11 @@ def _get_run_v1_runs_run_id_get_serialize( @validate_call - def list_applications_v1_applications_get( + def get_version_document( self, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2271,17 +2272,17 @@ def list_applications_v1_applications_get( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> List[ApplicationReadShortResponse]: - """List available applications + ) -> VersionDocumentResponse: + """Get version document metadata - Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + Return metadata for a single public document attached to an application version. - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2304,10 +2305,10 @@ def list_applications_v1_applications_get( :return: Returns the result object. """ # noqa: E501 - _param = self._list_applications_v1_applications_get_serialize( - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2315,8 +2316,8 @@ def list_applications_v1_applications_get( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ApplicationReadShortResponse]", - '401': None, + '200': "VersionDocumentResponse", + '404': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -2331,11 +2332,11 @@ def list_applications_v1_applications_get( @validate_call - def list_applications_v1_applications_get_with_http_info( + def get_version_document_with_http_info( self, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2348,17 +2349,17 @@ def list_applications_v1_applications_get_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[List[ApplicationReadShortResponse]]: - """List available applications + ) -> ApiResponse[VersionDocumentResponse]: + """Get version document metadata - Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + Return metadata for a single public document attached to an application version. - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2381,10 +2382,10 @@ def list_applications_v1_applications_get_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._list_applications_v1_applications_get_serialize( - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2392,8 +2393,8 @@ def list_applications_v1_applications_get_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ApplicationReadShortResponse]", - '401': None, + '200': "VersionDocumentResponse", + '404': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -2408,11 +2409,11 @@ def list_applications_v1_applications_get_with_http_info( @validate_call - def list_applications_v1_applications_get_without_preload_content( + def get_version_document_without_preload_content( self, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2426,16 +2427,16 @@ def list_applications_v1_applications_get_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """List available applications + """Get version document metadata - Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + Return metadata for a single public document attached to an application version. - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2458,10 +2459,10 @@ def list_applications_v1_applications_get_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._list_applications_v1_applications_get_serialize( - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2469,8 +2470,8 @@ def list_applications_v1_applications_get_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ApplicationReadShortResponse]", - '401': None, + '200': "VersionDocumentResponse", + '404': None, '422': "HTTPValidationError", } response_data = self.api_client.call_api( @@ -2480,11 +2481,11 @@ def list_applications_v1_applications_get_without_preload_content( return response_data.response - def _list_applications_v1_applications_get_serialize( + def _get_version_document_serialize( self, - page, - page_size, - sort, + application_id, + version, + name, _request_auth, _content_type, _headers, @@ -2494,7 +2495,6 @@ def _list_applications_v1_applications_get_serialize( _host = None _collection_formats: Dict[str, str] = { - 'sort': 'multi', } _path_params: Dict[str, str] = {} @@ -2507,19 +2507,13 @@ def _list_applications_v1_applications_get_serialize( _body_params: Optional[bytes] = None # process the path parameters + if application_id is not None: + _path_params['application_id'] = application_id + if version is not None: + _path_params['version'] = version + if name is not None: + _path_params['name'] = name # process the query parameters - if page is not None: - - _query_params.append(('page', page)) - - if page_size is not None: - - _query_params.append(('page-size', page_size)) - - if sort is not None: - - _query_params.append(('sort', sort)) - # process the header parameters # process the form parameters # process the body parameter @@ -2541,7 +2535,7 @@ def _list_applications_v1_applications_get_serialize( return self.api_client.param_serialize( method='GET', - resource_path='/api/v1/applications', + resource_path='/api/v1/applications/{application_id}/versions/{version}/documents/{name}', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -2558,17 +2552,11 @@ def _list_applications_v1_applications_get_serialize( @validate_call - def list_run_items_v1_runs_run_id_items_get( + def get_version_document_content( self, - run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], - item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, - external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, - state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, - termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2581,29 +2569,17 @@ def list_run_items_v1_runs_run_id_items_get( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> List[ItemResultReadResponse]: - """List Run Items + ) -> None: + """Stream version document content (programmatic) - List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + 307 redirect to a short-lived GCS signed URL for streaming document content. Unlike ``/file``, no ``Content-Disposition`` override is set — GCS serves the object body with its stored ``Content-Type``. Intended for programmatic clients that follow redirects and consume the content directly. Response carries ``Cache-Control: no-store``. - :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) - :type run_id: str - :param item_id__in: Filter for item ids - :type item_id__in: List[str] - :param external_id__in: Filter for items by their external_id from the input payload - :type external_id__in: List[str] - :param state: Filter items by their state - :type state: ItemState - :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. - :type termination_reason: ItemTerminationReason - :param custom_metadata: JSONPath expression to filter items by their custom_metadata - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2626,16 +2602,10 @@ def list_run_items_v1_runs_run_id_items_get( :return: Returns the result object. """ # noqa: E501 - _param = self._list_run_items_v1_runs_run_id_items_get_serialize( - run_id=run_id, - item_id__in=item_id__in, - external_id__in=external_id__in, - state=state, - termination_reason=termination_reason, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_content_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2643,7 +2613,7 @@ def list_run_items_v1_runs_run_id_items_get( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ItemResultReadResponse]", + '307': None, '404': None, '422': "HTTPValidationError", } @@ -2659,17 +2629,11 @@ def list_run_items_v1_runs_run_id_items_get( @validate_call - def list_run_items_v1_runs_run_id_items_get_with_http_info( + def get_version_document_content_with_http_info( self, - run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], - item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, - external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, - state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, - termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2682,29 +2646,17 @@ def list_run_items_v1_runs_run_id_items_get_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[List[ItemResultReadResponse]]: - """List Run Items + ) -> ApiResponse[None]: + """Stream version document content (programmatic) - List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + 307 redirect to a short-lived GCS signed URL for streaming document content. Unlike ``/file``, no ``Content-Disposition`` override is set — GCS serves the object body with its stored ``Content-Type``. Intended for programmatic clients that follow redirects and consume the content directly. Response carries ``Cache-Control: no-store``. - :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) - :type run_id: str - :param item_id__in: Filter for item ids - :type item_id__in: List[str] - :param external_id__in: Filter for items by their external_id from the input payload - :type external_id__in: List[str] - :param state: Filter items by their state - :type state: ItemState - :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. - :type termination_reason: ItemTerminationReason - :param custom_metadata: JSONPath expression to filter items by their custom_metadata - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2727,16 +2679,10 @@ def list_run_items_v1_runs_run_id_items_get_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._list_run_items_v1_runs_run_id_items_get_serialize( - run_id=run_id, - item_id__in=item_id__in, - external_id__in=external_id__in, - state=state, - termination_reason=termination_reason, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_content_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2744,7 +2690,7 @@ def list_run_items_v1_runs_run_id_items_get_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ItemResultReadResponse]", + '307': None, '404': None, '422': "HTTPValidationError", } @@ -2760,17 +2706,11 @@ def list_run_items_v1_runs_run_id_items_get_with_http_info( @validate_call - def list_run_items_v1_runs_run_id_items_get_without_preload_content( + def get_version_document_content_without_preload_content( self, - run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], - item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, - external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, - state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, - termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = None, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2784,28 +2724,16 @@ def list_run_items_v1_runs_run_id_items_get_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """List Run Items + """Stream version document content (programmatic) - List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + 307 redirect to a short-lived GCS signed URL for streaming document content. Unlike ``/file``, no ``Content-Disposition`` override is set — GCS serves the object body with its stored ``Content-Type``. Intended for programmatic clients that follow redirects and consume the content directly. Response carries ``Cache-Control: no-store``. - :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) - :type run_id: str - :param item_id__in: Filter for item ids - :type item_id__in: List[str] - :param external_id__in: Filter for items by their external_id from the input payload - :type external_id__in: List[str] - :param state: Filter items by their state - :type state: ItemState - :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. - :type termination_reason: ItemTerminationReason - :param custom_metadata: JSONPath expression to filter items by their custom_metadata - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) - :type sort: List[str] + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str :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 @@ -2828,16 +2756,10 @@ def list_run_items_v1_runs_run_id_items_get_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._list_run_items_v1_runs_run_id_items_get_serialize( - run_id=run_id, - item_id__in=item_id__in, - external_id__in=external_id__in, - state=state, - termination_reason=termination_reason, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - sort=sort, + _param = self._get_version_document_content_serialize( + application_id=application_id, + version=version, + name=name, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -2845,7 +2767,7 @@ def list_run_items_v1_runs_run_id_items_get_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[ItemResultReadResponse]", + '307': None, '404': None, '422': "HTTPValidationError", } @@ -2856,10 +2778,980 @@ def list_run_items_v1_runs_run_id_items_get_without_preload_content( return response_data.response - def _list_run_items_v1_runs_run_id_items_get_serialize( + def _get_version_document_content_serialize( self, - run_id, - item_id__in, + application_id, + version, + name, + _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 application_id is not None: + _path_params['application_id'] = application_id + if version is not None: + _path_params['version'] = version + if name is not None: + _path_params['name'] = name + # 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] = [ + 'OAuth2AuthorizationCodeBearer' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/applications/{application_id}/versions/{version}/documents/{name}/content', + 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 get_version_document_file( + self, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, + _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, + ) -> None: + """Download version document (browser) + + 307 redirect to a short-lived GCS signed URL for downloading a document. The signed URL includes ``response-content-disposition=attachment; filename=\"\"`` so browsers prompt a save-as dialog rather than rendering inline. Response carries ``Cache-Control: no-store``. + + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str + :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._get_version_document_file_serialize( + application_id=application_id, + version=version, + name=name, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '307': None, + '404': None, + '422': "HTTPValidationError", + } + 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 get_version_document_file_with_http_info( + self, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, + _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[None]: + """Download version document (browser) + + 307 redirect to a short-lived GCS signed URL for downloading a document. The signed URL includes ``response-content-disposition=attachment; filename=\"\"`` so browsers prompt a save-as dialog rather than rendering inline. Response carries ``Cache-Control: no-store``. + + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str + :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._get_version_document_file_serialize( + application_id=application_id, + version=version, + name=name, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '307': None, + '404': None, + '422': "HTTPValidationError", + } + 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 get_version_document_file_without_preload_content( + self, + application_id: StrictStr, + version: StrictStr, + name: StrictStr, + _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: + """Download version document (browser) + + 307 redirect to a short-lived GCS signed URL for downloading a document. The signed URL includes ``response-content-disposition=attachment; filename=\"\"`` so browsers prompt a save-as dialog rather than rendering inline. Response carries ``Cache-Control: no-store``. + + :param application_id: (required) + :type application_id: str + :param version: (required) + :type version: str + :param name: (required) + :type name: str + :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._get_version_document_file_serialize( + application_id=application_id, + version=version, + name=name, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '307': None, + '404': None, + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _get_version_document_file_serialize( + self, + application_id, + version, + name, + _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 application_id is not None: + _path_params['application_id'] = application_id + if version is not None: + _path_params['version'] = version + if name is not None: + _path_params['name'] = name + # 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] = [ + 'OAuth2AuthorizationCodeBearer' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/applications/{application_id}/versions/{version}/documents/{name}/file', + 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 list_applications_v1_applications_get( + self, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = 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, + ) -> List[ApplicationReadShortResponse]: + """List available applications + + Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending + :type sort: List[str] + :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._list_applications_v1_applications_get_serialize( + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ApplicationReadShortResponse]", + '401': None, + '422': "HTTPValidationError", + } + 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 list_applications_v1_applications_get_with_http_info( + self, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = 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[List[ApplicationReadShortResponse]]: + """List available applications + + Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending + :type sort: List[str] + :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._list_applications_v1_applications_get_serialize( + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ApplicationReadShortResponse]", + '401': None, + '422': "HTTPValidationError", + } + 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 list_applications_v1_applications_get_without_preload_content( + self, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending")] = 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: + """List available applications + + Returns the list of the applications, available to the caller. The application is available if any of the versions of the application is assigned to the caller's organization. The response is paginated and sorted according to the provided parameters. + + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `application_id` - `name` - `description` - `regulatory_classes` **Examples:** - `?sort=application_id` - Sort by application_id ascending - `?sort=-name` - Sort by name descending - `?sort=+description&sort=name` - Sort by description ascending, then name descending + :type sort: List[str] + :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._list_applications_v1_applications_get_serialize( + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ApplicationReadShortResponse]", + '401': None, + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _list_applications_v1_applications_get_serialize( + self, + page, + page_size, + sort, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + 'sort': 'multi', + } + + _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 + # process the query parameters + if page is not None: + + _query_params.append(('page', page)) + + if page_size is not None: + + _query_params.append(('page-size', page_size)) + + if sort is not None: + + _query_params.append(('sort', sort)) + + # 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] = [ + 'OAuth2AuthorizationCodeBearer' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/applications', + 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 list_run_items_v1_runs_run_id_items_get( + self, + run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], + item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, + external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, + state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, + termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = 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, + ) -> List[ItemResultReadResponse]: + """List Run Items + + List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + + :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) + :type run_id: str + :param item_id__in: Filter for item ids + :type item_id__in: List[str] + :param external_id__in: Filter for items by their external_id from the input payload + :type external_id__in: List[str] + :param state: Filter items by their state + :type state: ItemState + :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. + :type termination_reason: ItemTerminationReason + :param custom_metadata: JSONPath expression to filter items by their custom_metadata + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) + :type sort: List[str] + :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._list_run_items_v1_runs_run_id_items_get_serialize( + run_id=run_id, + item_id__in=item_id__in, + external_id__in=external_id__in, + state=state, + termination_reason=termination_reason, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ItemResultReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + 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 list_run_items_v1_runs_run_id_items_get_with_http_info( + self, + run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], + item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, + external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, + state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, + termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = 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[List[ItemResultReadResponse]]: + """List Run Items + + List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + + :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) + :type run_id: str + :param item_id__in: Filter for item ids + :type item_id__in: List[str] + :param external_id__in: Filter for items by their external_id from the input payload + :type external_id__in: List[str] + :param state: Filter items by their state + :type state: ItemState + :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. + :type termination_reason: ItemTerminationReason + :param custom_metadata: JSONPath expression to filter items by their custom_metadata + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) + :type sort: List[str] + :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._list_run_items_v1_runs_run_id_items_get_serialize( + run_id=run_id, + item_id__in=item_id__in, + external_id__in=external_id__in, + state=state, + termination_reason=termination_reason, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ItemResultReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + 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 list_run_items_v1_runs_run_id_items_get_without_preload_content( + self, + run_id: Annotated[StrictStr, Field(description="Run id, returned by `POST /v1/runs/` endpoint")], + item_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for item ids")] = None, + external_id__in: Annotated[Optional[List[StrictStr]], Field(description="Filter for items by their external_id from the input payload")] = None, + state: Annotated[Optional[ItemState], Field(description="Filter items by their state")] = None, + termination_reason: Annotated[Optional[ItemTerminationReason], Field(description="Filter items by their termination reason. Only applies to TERMINATED items.")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="JSONPath expression to filter items by their custom_metadata")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending)")] = 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: + """List Run Items + + List items in a run with filtering, sorting, and pagination capabilities. Returns paginated items within a specific run. Results can be filtered by `item_id`, `external_ids`, `custom_metadata`, `terminated_at`, and `termination_reason` using JSONPath expressions. ## JSONPath Metadata Filtering Use PostgreSQL JSONPath expressions to filter items using their custom_metadata. ### Examples: - **Field existence**: `$.case_id` - Results that have a case_id field defined - **Exact value match**: `$.priority ? (@ == \"high\")` - Results with high priority - **Numeric comparison**: `$.confidence_score ? (@ > 0.95)` - Results with high confidence - **Array operations**: `$.flags[*] ? (@ == \"reviewed\")` - Results flagged as reviewed - **Complex conditions**: `$.metrics ? (@.accuracy > 0.9 && @.recall > 0.8)` - Results meeting performance thresholds ## Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations + + :param run_id: Run id, returned by `POST /v1/runs/` endpoint (required) + :type run_id: str + :param item_id__in: Filter for item ids + :type item_id__in: List[str] + :param external_id__in: Filter for items by their external_id from the input payload + :type external_id__in: List[str] + :param state: Filter items by their state + :type state: ItemState + :param termination_reason: Filter items by their termination reason. Only applies to TERMINATED items. + :type termination_reason: ItemTerminationReason + :param custom_metadata: JSONPath expression to filter items by their custom_metadata + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param sort: Sort the items by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `item_id` - `external_id` - `custom_metadata` - `terminated_at` - `termination_reason` **Examples:** - `?sort=item_id` - Sort by id of the item (ascending) - `?sort=-external_id` - Sort by external ID (descending) - `?sort=custom_metadata&sort=-external_id` - Sort by metadata, then by external ID (descending) + :type sort: List[str] + :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._list_run_items_v1_runs_run_id_items_get_serialize( + run_id=run_id, + item_id__in=item_id__in, + external_id__in=external_id__in, + state=state, + termination_reason=termination_reason, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[ItemResultReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _list_run_items_v1_runs_run_id_items_get_serialize( + self, + run_id, + item_id__in, external_id__in, state, termination_reason, @@ -2876,8 +3768,399 @@ def _list_run_items_v1_runs_run_id_items_get_serialize( _host = None _collection_formats: Dict[str, str] = { - 'item_id__in': 'multi', - 'external_id__in': 'multi', + 'item_id__in': 'multi', + 'external_id__in': 'multi', + 'sort': 'multi', + } + + _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 run_id is not None: + _path_params['run_id'] = run_id + # process the query parameters + if item_id__in is not None: + + _query_params.append(('item_id__in', item_id__in)) + + if external_id__in is not None: + + _query_params.append(('external_id__in', external_id__in)) + + if state is not None: + + _query_params.append(('state', state.value)) + + if termination_reason is not None: + + _query_params.append(('termination_reason', termination_reason.value)) + + if custom_metadata is not None: + + _query_params.append(('custom_metadata', custom_metadata)) + + if page is not None: + + _query_params.append(('page', page)) + + if page_size is not None: + + _query_params.append(('page_size', page_size)) + + if sort is not None: + + _query_params.append(('sort', sort)) + + # 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] = [ + 'OAuth2AuthorizationCodeBearer' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/api/v1/runs/{run_id}/items', + 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 list_runs_v1_runs_get( + self, + application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, + application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = 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, + ) -> List[RunReadResponse]: + """List Runs + + List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + + :param application_id: Optional application ID filter + :type application_id: str + :param application_version: Optional Version Name + :type application_version: str + :param external_id: Optionally filter runs by items with this external ID + :type external_id: str + :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. + :type for_organization: str + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) + :type sort: List[str] + :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._list_runs_v1_runs_get_serialize( + application_id=application_id, + application_version=application_version, + external_id=external_id, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + for_organization=for_organization, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[RunReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + 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 list_runs_v1_runs_get_with_http_info( + self, + application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, + application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = 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[List[RunReadResponse]]: + """List Runs + + List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + + :param application_id: Optional application ID filter + :type application_id: str + :param application_version: Optional Version Name + :type application_version: str + :param external_id: Optionally filter runs by items with this external ID + :type external_id: str + :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. + :type for_organization: str + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) + :type sort: List[str] + :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._list_runs_v1_runs_get_serialize( + application_id=application_id, + application_version=application_version, + external_id=external_id, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + for_organization=for_organization, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[RunReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + 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 list_runs_v1_runs_get_without_preload_content( + self, + application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, + application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, + external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, + custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, + page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, + page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, + for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, + sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = 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: + """List Runs + + List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + + :param application_id: Optional application ID filter + :type application_id: str + :param application_version: Optional Version Name + :type application_version: str + :param external_id: Optionally filter runs by items with this external ID + :type external_id: str + :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** + :type custom_metadata: str + :param page: + :type page: int + :param page_size: + :type page_size: int + :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. + :type for_organization: str + :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) + :type sort: List[str] + :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._list_runs_v1_runs_get_serialize( + application_id=application_id, + application_version=application_version, + external_id=external_id, + custom_metadata=custom_metadata, + page=page, + page_size=page_size, + for_organization=for_organization, + sort=sort, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "List[RunReadResponse]", + '404': None, + '422': "HTTPValidationError", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _list_runs_v1_runs_get_serialize( + self, + application_id, + application_version, + external_id, + custom_metadata, + page, + page_size, + for_organization, + sort, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { 'sort': 'multi', } @@ -2891,24 +4174,18 @@ def _list_run_items_v1_runs_run_id_items_get_serialize( _body_params: Optional[bytes] = None # process the path parameters - if run_id is not None: - _path_params['run_id'] = run_id # process the query parameters - if item_id__in is not None: - - _query_params.append(('item_id__in', item_id__in)) - - if external_id__in is not None: + if application_id is not None: - _query_params.append(('external_id__in', external_id__in)) + _query_params.append(('application_id', application_id)) - if state is not None: + if application_version is not None: - _query_params.append(('state', state.value)) + _query_params.append(('application_version', application_version)) - if termination_reason is not None: + if external_id is not None: - _query_params.append(('termination_reason', termination_reason.value)) + _query_params.append(('external_id', external_id)) if custom_metadata is not None: @@ -2922,6 +4199,10 @@ def _list_run_items_v1_runs_run_id_items_get_serialize( _query_params.append(('page_size', page_size)) + if for_organization is not None: + + _query_params.append(('for_organization', for_organization)) + if sort is not None: _query_params.append(('sort', sort)) @@ -2947,7 +4228,7 @@ def _list_run_items_v1_runs_run_id_items_get_serialize( return self.api_client.param_serialize( method='GET', - resource_path='/api/v1/runs/{run_id}/items', + resource_path='/api/v1/runs', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -2964,16 +4245,10 @@ def _list_run_items_v1_runs_run_id_items_get_serialize( @validate_call - def list_runs_v1_runs_get( + def list_version_documents( self, - application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, - application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, - external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = None, + application_id: StrictStr, + version: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -2986,27 +4261,15 @@ def list_runs_v1_runs_get( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> List[RunReadResponse]: - """List Runs + ) -> List[VersionDocumentResponse]: + """List version documents - List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + List public documents attached to an application version. Returns only documents with ``visibility=public`` and ``status=uploaded``. - :param application_id: Optional application ID filter + :param application_id: (required) :type application_id: str - :param application_version: Optional Version Name - :type application_version: str - :param external_id: Optionally filter runs by items with this external ID - :type external_id: str - :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. - :type for_organization: str - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) - :type sort: List[str] + :param version: (required) + :type version: str :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 @@ -3029,15 +4292,9 @@ def list_runs_v1_runs_get( :return: Returns the result object. """ # noqa: E501 - _param = self._list_runs_v1_runs_get_serialize( + _param = self._list_version_documents_serialize( application_id=application_id, - application_version=application_version, - external_id=external_id, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - for_organization=for_organization, - sort=sort, + version=version, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3045,7 +4302,7 @@ def list_runs_v1_runs_get( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[RunReadResponse]", + '200': "List[VersionDocumentResponse]", '404': None, '422': "HTTPValidationError", } @@ -3061,16 +4318,10 @@ def list_runs_v1_runs_get( @validate_call - def list_runs_v1_runs_get_with_http_info( + def list_version_documents_with_http_info( self, - application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, - application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, - external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = None, + application_id: StrictStr, + version: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3083,27 +4334,15 @@ def list_runs_v1_runs_get_with_http_info( _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[List[RunReadResponse]]: - """List Runs + ) -> ApiResponse[List[VersionDocumentResponse]]: + """List version documents - List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + List public documents attached to an application version. Returns only documents with ``visibility=public`` and ``status=uploaded``. - :param application_id: Optional application ID filter + :param application_id: (required) :type application_id: str - :param application_version: Optional Version Name - :type application_version: str - :param external_id: Optionally filter runs by items with this external ID - :type external_id: str - :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. - :type for_organization: str - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) - :type sort: List[str] + :param version: (required) + :type version: str :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 @@ -3126,15 +4365,9 @@ def list_runs_v1_runs_get_with_http_info( :return: Returns the result object. """ # noqa: E501 - _param = self._list_runs_v1_runs_get_serialize( + _param = self._list_version_documents_serialize( application_id=application_id, - application_version=application_version, - external_id=external_id, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - for_organization=for_organization, - sort=sort, + version=version, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3142,7 +4375,7 @@ def list_runs_v1_runs_get_with_http_info( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[RunReadResponse]", + '200': "List[VersionDocumentResponse]", '404': None, '422': "HTTPValidationError", } @@ -3158,16 +4391,10 @@ def list_runs_v1_runs_get_with_http_info( @validate_call - def list_runs_v1_runs_get_without_preload_content( + def list_version_documents_without_preload_content( self, - application_id: Annotated[Optional[StrictStr], Field(description="Optional application ID filter")] = None, - application_version: Annotated[Optional[StrictStr], Field(description="Optional Version Name")] = None, - external_id: Annotated[Optional[StrictStr], Field(description="Optionally filter runs by items with this external ID")] = None, - custom_metadata: Annotated[Optional[Annotated[str, Field(strict=True, max_length=1000)]], Field(description="Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** ")] = None, - page: Optional[Annotated[int, Field(strict=True, ge=1)]] = None, - page_size: Optional[Annotated[int, Field(le=100, strict=True, ge=5)]] = None, - for_organization: Annotated[Optional[StrictStr], Field(description="Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs.")] = None, - sort: Annotated[Optional[List[StrictStr]], Field(description="Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) ")] = None, + application_id: StrictStr, + version: StrictStr, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3181,26 +4408,14 @@ def list_runs_v1_runs_get_without_preload_content( _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, ) -> RESTResponseType: - """List Runs + """List version documents - List runs with filtering, sorting, and pagination capabilities. Returns paginated runs that were submitted by the user. + List public documents attached to an application version. Returns only documents with ``visibility=public`` and ``status=uploaded``. - :param application_id: Optional application ID filter + :param application_id: (required) :type application_id: str - :param application_version: Optional Version Name - :type application_version: str - :param external_id: Optionally filter runs by items with this external ID - :type external_id: str - :param custom_metadata: Use PostgreSQL JSONPath expressions to filter runs by their custom_metadata. #### URL Encoding Required **Important**: JSONPath expressions contain special characters that must be URL-encoded when used in query parameters. Most HTTP clients handle this automatically, but when constructing URLs manually, please ensure proper encoding. #### Examples (Clear Format): - **Field existence**: `$.study` - Runs that have a study field defined - **Exact value match**: `$.study ? (@ == \"high\")` - Runs with specific study value - **Numeric comparison**: `$.confidence_score ? (@ > 0.75)` - Runs with confidence score greater than 0.75 - **Array operations**: `$.tags[*] ? (@ == \"draft\")` - Runs with tags array containing \"draft\" - **Complex conditions**: `$.resources ? (@.gpu_count > 2 && @.memory_gb >= 16)` - Runs with high resource requirements #### Examples (URL-Encoded Format): - **Field existence**: `%24.study` - **Exact value match**: `%24.study%20%3F%20(%40%20%3D%3D%20%22high%22)` - **Numeric comparison**: `%24.confidence_score%20%3F%20(%40%20%3E%200.75)` - **Array operations**: `%24.tags%5B*%5D%20%3F%20(%40%20%3D%3D%20%22draft%22)` - **Complex conditions**: `%24.resources%20%3F%20(%40.gpu_count%20%3E%202%20%26%26%20%40.memory_gb%20%3E%3D%2016)` #### Notes - JSONPath expressions are evaluated using PostgreSQL's `@?` operator - The `$.` prefix is automatically added to root-level field references if missing - String values in conditions must be enclosed in double quotes - Use `&&` for AND operations and `||` for OR operations - Regular expressions use `like_regex` with standard regex syntax - **Please remember to URL-encode the entire JSONPath expression when making HTTP requests** - :type custom_metadata: str - :param page: - :type page: int - :param page_size: - :type page_size: int - :param for_organization: Filter runs by organization ID. Available for superadmins (any org) and admins (own org only). When provided, returns all runs for the specified organization instead of only the caller's own runs. - :type for_organization: str - :param sort: Sort the results by one or more fields. Use `+` for ascending and `-` for descending order. **Available fields:** - `run_id` - `application_id` - `version_number` - `custom_metadata` - `submitted_at` - `submitted_by` - `terminated_at` - `termination_reason` **Examples:** - `?sort=submitted_at` - Sort by creation time (ascending) - `?sort=-submitted_at` - Sort by creation time (descending) - `?sort=state&sort=-submitted_at` - Sort by state, then by time (descending) - :type sort: List[str] + :param version: (required) + :type version: str :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 @@ -3223,15 +4438,9 @@ def list_runs_v1_runs_get_without_preload_content( :return: Returns the result object. """ # noqa: E501 - _param = self._list_runs_v1_runs_get_serialize( + _param = self._list_version_documents_serialize( application_id=application_id, - application_version=application_version, - external_id=external_id, - custom_metadata=custom_metadata, - page=page, - page_size=page_size, - for_organization=for_organization, - sort=sort, + version=version, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3239,7 +4448,7 @@ def list_runs_v1_runs_get_without_preload_content( ) _response_types_map: Dict[str, Optional[str]] = { - '200': "List[RunReadResponse]", + '200': "List[VersionDocumentResponse]", '404': None, '422': "HTTPValidationError", } @@ -3250,16 +4459,10 @@ def list_runs_v1_runs_get_without_preload_content( return response_data.response - def _list_runs_v1_runs_get_serialize( + def _list_version_documents_serialize( self, application_id, - application_version, - external_id, - custom_metadata, - page, - page_size, - for_organization, - sort, + version, _request_auth, _content_type, _headers, @@ -3269,7 +4472,6 @@ def _list_runs_v1_runs_get_serialize( _host = None _collection_formats: Dict[str, str] = { - 'sort': 'multi', } _path_params: Dict[str, str] = {} @@ -3282,39 +4484,11 @@ def _list_runs_v1_runs_get_serialize( _body_params: Optional[bytes] = None # process the path parameters - # process the query parameters if application_id is not None: - - _query_params.append(('application_id', application_id)) - - if application_version is not None: - - _query_params.append(('application_version', application_version)) - - if external_id is not None: - - _query_params.append(('external_id', external_id)) - - if custom_metadata is not None: - - _query_params.append(('custom_metadata', custom_metadata)) - - if page is not None: - - _query_params.append(('page', page)) - - if page_size is not None: - - _query_params.append(('page_size', page_size)) - - if for_organization is not None: - - _query_params.append(('for_organization', for_organization)) - - if sort is not None: - - _query_params.append(('sort', sort)) - + _path_params['application_id'] = application_id + if version is not None: + _path_params['version'] = version + # process the query parameters # process the header parameters # process the form parameters # process the body parameter @@ -3336,7 +4510,7 @@ def _list_runs_v1_runs_get_serialize( return self.api_client.param_serialize( method='GET', - resource_path='/api/v1/runs', + resource_path='/api/v1/applications/{application_id}/versions/{version}/documents', path_params=_path_params, query_params=_query_params, header_params=_header_params, diff --git a/codegen/out/aignx/codegen/api_client.py b/codegen/out/aignx/codegen/api_client.py index b56edae2b..1f5b8fc8d 100644 --- a/codegen/out/aignx/codegen/api_client.py +++ b/codegen/out/aignx/codegen/api_client.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/configuration.py b/codegen/out/aignx/codegen/configuration.py index ac221d92e..007c409c3 100644 --- a/codegen/out/aignx/codegen/configuration.py +++ b/codegen/out/aignx/codegen/configuration.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. @@ -502,7 +502,7 @@ def to_debug_report(self) -> str: return "Python SDK Debug Report:\n"\ "OS: {env}\n"\ "Python Version: {pyversion}\n"\ - "Version of the API: 1.4.0\n"\ + "Version of the API: 1.5.0\n"\ "SDK Package Version: 1.0.0".\ format(env=sys.platform, pyversion=sys.version) diff --git a/codegen/out/aignx/codegen/exceptions.py b/codegen/out/aignx/codegen/exceptions.py index 4f7dfe5b4..0da9a49e5 100644 --- a/codegen/out/aignx/codegen/exceptions.py +++ b/codegen/out/aignx/codegen/exceptions.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/__init__.py b/codegen/out/aignx/codegen/models/__init__.py index 382b6ac7b..b6d754dc8 100644 --- a/codegen/out/aignx/codegen/models/__init__.py +++ b/codegen/out/aignx/codegen/models/__init__.py @@ -9,6 +9,7 @@ from .organization_read_response import * from .validation_error import * from .application_read_response import * +from .version_document_response import * from .application_read_short_response import * from .output_artifact_scope import * from .scheduling_response import * @@ -20,8 +21,10 @@ from .application_version import * from .http_validation_error import * from .custom_metadata_update_response import * +from .version_document_visibility import * from .user_read_response import * from .run_termination_reason import * +from .input_artifact_result_read_response import * from .input_artifact import * from .output_artifact_result_read_response import * from .version_read_response import * diff --git a/codegen/out/aignx/codegen/models/application_read_response.py b/codegen/out/aignx/codegen/models/application_read_response.py index 9fea43961..23abca29c 100644 --- a/codegen/out/aignx/codegen/models/application_read_response.py +++ b/codegen/out/aignx/codegen/models/application_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/application_read_short_response.py b/codegen/out/aignx/codegen/models/application_read_short_response.py index da128fa5e..7bfce4e2a 100644 --- a/codegen/out/aignx/codegen/models/application_read_short_response.py +++ b/codegen/out/aignx/codegen/models/application_read_short_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/application_version.py b/codegen/out/aignx/codegen/models/application_version.py index b7c6b700a..fed544e18 100644 --- a/codegen/out/aignx/codegen/models/application_version.py +++ b/codegen/out/aignx/codegen/models/application_version.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/artifact_output.py b/codegen/out/aignx/codegen/models/artifact_output.py index 150698d7c..88b210599 100644 --- a/codegen/out/aignx/codegen/models/artifact_output.py +++ b/codegen/out/aignx/codegen/models/artifact_output.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/artifact_state.py b/codegen/out/aignx/codegen/models/artifact_state.py index b90f2272a..da25ba6a4 100644 --- a/codegen/out/aignx/codegen/models/artifact_state.py +++ b/codegen/out/aignx/codegen/models/artifact_state.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/artifact_termination_reason.py b/codegen/out/aignx/codegen/models/artifact_termination_reason.py index 6f06896b0..2e7573e1c 100644 --- a/codegen/out/aignx/codegen/models/artifact_termination_reason.py +++ b/codegen/out/aignx/codegen/models/artifact_termination_reason.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/custom_metadata_update_request.py b/codegen/out/aignx/codegen/models/custom_metadata_update_request.py index 5cd0650b0..9143c4df3 100644 --- a/codegen/out/aignx/codegen/models/custom_metadata_update_request.py +++ b/codegen/out/aignx/codegen/models/custom_metadata_update_request.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/custom_metadata_update_response.py b/codegen/out/aignx/codegen/models/custom_metadata_update_response.py index c1bf3b6db..2cfc00a64 100644 --- a/codegen/out/aignx/codegen/models/custom_metadata_update_response.py +++ b/codegen/out/aignx/codegen/models/custom_metadata_update_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/http_validation_error.py b/codegen/out/aignx/codegen/models/http_validation_error.py index f3834b746..a54b96060 100644 --- a/codegen/out/aignx/codegen/models/http_validation_error.py +++ b/codegen/out/aignx/codegen/models/http_validation_error.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/input_artifact.py b/codegen/out/aignx/codegen/models/input_artifact.py index 02324f488..9cf652222 100644 --- a/codegen/out/aignx/codegen/models/input_artifact.py +++ b/codegen/out/aignx/codegen/models/input_artifact.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/input_artifact_creation_request.py b/codegen/out/aignx/codegen/models/input_artifact_creation_request.py index 80af637ae..4a7844e60 100644 --- a/codegen/out/aignx/codegen/models/input_artifact_creation_request.py +++ b/codegen/out/aignx/codegen/models/input_artifact_creation_request.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/input_artifact_result_read_response.py b/codegen/out/aignx/codegen/models/input_artifact_result_read_response.py new file mode 100644 index 000000000..da7fd3822 --- /dev/null +++ b/codegen/out/aignx/codegen/models/input_artifact_result_read_response.py @@ -0,0 +1,104 @@ +# coding: utf-8 + +""" + Aignostics Platform API + + The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. + + The version of the OpenAPI document: 1.5.0 + 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, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing_extensions import Annotated +from typing import Optional, Set +from typing_extensions import Self + +class InputArtifactResultReadResponse(BaseModel): + """ + InputArtifactResultReadResponse + """ # noqa: E501 + input_artifact_id: StrictStr = Field(description="The Id of the artifact. Used internally") + name: StrictStr = Field(description="Name of the input from the schema from the `/v1/versions/{version_id}` endpoint.") + metadata: Optional[Dict[str, Any]] = None + download_url: Optional[Annotated[str, Field(min_length=1, strict=True, max_length=2083)]] = None + __properties: ClassVar[List[str]] = ["input_artifact_id", "name", "metadata", "download_url"] + + 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 InputArtifactResultReadResponse 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. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if metadata (nullable) is None + # and model_fields_set contains the field + if self.metadata is None and "metadata" in self.model_fields_set: + _dict['metadata'] = None + + # set to None if download_url (nullable) is None + # and model_fields_set contains the field + if self.download_url is None and "download_url" in self.model_fields_set: + _dict['download_url'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of InputArtifactResultReadResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "input_artifact_id": obj.get("input_artifact_id"), + "name": obj.get("name"), + "metadata": obj.get("metadata"), + "download_url": obj.get("download_url") + }) + return _obj + + diff --git a/codegen/out/aignx/codegen/models/item_creation_request.py b/codegen/out/aignx/codegen/models/item_creation_request.py index 593eff96c..3f49dc409 100644 --- a/codegen/out/aignx/codegen/models/item_creation_request.py +++ b/codegen/out/aignx/codegen/models/item_creation_request.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/item_output.py b/codegen/out/aignx/codegen/models/item_output.py index d313e54c9..127b03723 100644 --- a/codegen/out/aignx/codegen/models/item_output.py +++ b/codegen/out/aignx/codegen/models/item_output.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/item_result_read_response.py b/codegen/out/aignx/codegen/models/item_result_read_response.py index f4f334179..6c8fe46ba 100644 --- a/codegen/out/aignx/codegen/models/item_result_read_response.py +++ b/codegen/out/aignx/codegen/models/item_result_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. @@ -20,6 +20,7 @@ from datetime import datetime from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional +from aignx.codegen.models.input_artifact_result_read_response import InputArtifactResultReadResponse from aignx.codegen.models.item_output import ItemOutput from aignx.codegen.models.item_state import ItemState from aignx.codegen.models.item_termination_reason import ItemTerminationReason @@ -43,8 +44,9 @@ class ItemResultReadResponse(BaseModel): error_code: Optional[StrictStr] = None error_message: Optional[StrictStr] = None terminated_at: Optional[datetime] = None + input_artifacts: List[InputArtifactResultReadResponse] = Field(description=" The input artifact(s) provided by the user. For most applications, this will be one artifact that defines the whole slide image to be processed. ") output_artifacts: List[OutputArtifactResultReadResponse] = Field(description=" The list of the results generated by the application algorithm. The number of files and their types depend on the particular application version, call `/v1/versions/{version_id}` to get the details. ") - __properties: ClassVar[List[str]] = ["item_id", "external_id", "custom_metadata", "custom_metadata_checksum", "queue_position_org", "queue_position_platform", "state", "output", "termination_reason", "error_code", "error_message", "terminated_at", "output_artifacts"] + __properties: ClassVar[List[str]] = ["item_id", "external_id", "custom_metadata", "custom_metadata_checksum", "queue_position_org", "queue_position_platform", "state", "output", "termination_reason", "error_code", "error_message", "terminated_at", "input_artifacts", "output_artifacts"] model_config = ConfigDict( populate_by_name=True, @@ -85,6 +87,13 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # override the default output from pydantic by calling `to_dict()` of each item in input_artifacts (list) + _items = [] + if self.input_artifacts: + for _item_input_artifacts in self.input_artifacts: + if _item_input_artifacts: + _items.append(_item_input_artifacts.to_dict()) + _dict['input_artifacts'] = _items # override the default output from pydantic by calling `to_dict()` of each item in output_artifacts (list) _items = [] if self.output_artifacts: @@ -156,6 +165,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "error_code": obj.get("error_code"), "error_message": obj.get("error_message"), "terminated_at": obj.get("terminated_at"), + "input_artifacts": [InputArtifactResultReadResponse.from_dict(_item) for _item in obj["input_artifacts"]] if obj.get("input_artifacts") is not None else None, "output_artifacts": [OutputArtifactResultReadResponse.from_dict(_item) for _item in obj["output_artifacts"]] if obj.get("output_artifacts") is not None else None }) return _obj diff --git a/codegen/out/aignx/codegen/models/item_state.py b/codegen/out/aignx/codegen/models/item_state.py index 8e4928c16..5dfdcdf39 100644 --- a/codegen/out/aignx/codegen/models/item_state.py +++ b/codegen/out/aignx/codegen/models/item_state.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/item_termination_reason.py b/codegen/out/aignx/codegen/models/item_termination_reason.py index 04070e10b..7f6d5e6d3 100644 --- a/codegen/out/aignx/codegen/models/item_termination_reason.py +++ b/codegen/out/aignx/codegen/models/item_termination_reason.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/me_read_response.py b/codegen/out/aignx/codegen/models/me_read_response.py index b25865ec2..dd63abf4e 100644 --- a/codegen/out/aignx/codegen/models/me_read_response.py +++ b/codegen/out/aignx/codegen/models/me_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/organization_read_response.py b/codegen/out/aignx/codegen/models/organization_read_response.py index 7b3b5c4ee..0f85155cf 100644 --- a/codegen/out/aignx/codegen/models/organization_read_response.py +++ b/codegen/out/aignx/codegen/models/organization_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/output_artifact.py b/codegen/out/aignx/codegen/models/output_artifact.py index dd62295a7..cc6230290 100644 --- a/codegen/out/aignx/codegen/models/output_artifact.py +++ b/codegen/out/aignx/codegen/models/output_artifact.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py b/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py index 131c0101f..fd0069b75 100644 --- a/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py +++ b/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/output_artifact_scope.py b/codegen/out/aignx/codegen/models/output_artifact_scope.py index d1f927a4c..8e4d0c6dd 100644 --- a/codegen/out/aignx/codegen/models/output_artifact_scope.py +++ b/codegen/out/aignx/codegen/models/output_artifact_scope.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/output_artifact_visibility.py b/codegen/out/aignx/codegen/models/output_artifact_visibility.py index 48a346d0e..5e6e492da 100644 --- a/codegen/out/aignx/codegen/models/output_artifact_visibility.py +++ b/codegen/out/aignx/codegen/models/output_artifact_visibility.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_creation_request.py b/codegen/out/aignx/codegen/models/run_creation_request.py index c6e7bfb95..e29fabe6d 100644 --- a/codegen/out/aignx/codegen/models/run_creation_request.py +++ b/codegen/out/aignx/codegen/models/run_creation_request.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_creation_response.py b/codegen/out/aignx/codegen/models/run_creation_response.py index 7277899ff..9868cc07c 100644 --- a/codegen/out/aignx/codegen/models/run_creation_response.py +++ b/codegen/out/aignx/codegen/models/run_creation_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_item_statistics.py b/codegen/out/aignx/codegen/models/run_item_statistics.py index f3d24fa07..fd3a98cf0 100644 --- a/codegen/out/aignx/codegen/models/run_item_statistics.py +++ b/codegen/out/aignx/codegen/models/run_item_statistics.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_output.py b/codegen/out/aignx/codegen/models/run_output.py index 29837ab76..521bfd3ec 100644 --- a/codegen/out/aignx/codegen/models/run_output.py +++ b/codegen/out/aignx/codegen/models/run_output.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_read_response.py b/codegen/out/aignx/codegen/models/run_read_response.py index 0e3ff1a31..9f1a1d55b 100644 --- a/codegen/out/aignx/codegen/models/run_read_response.py +++ b/codegen/out/aignx/codegen/models/run_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_state.py b/codegen/out/aignx/codegen/models/run_state.py index 734e55890..c7cabff90 100644 --- a/codegen/out/aignx/codegen/models/run_state.py +++ b/codegen/out/aignx/codegen/models/run_state.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/run_termination_reason.py b/codegen/out/aignx/codegen/models/run_termination_reason.py index 5e700de27..3b116235f 100644 --- a/codegen/out/aignx/codegen/models/run_termination_reason.py +++ b/codegen/out/aignx/codegen/models/run_termination_reason.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/scheduling_request.py b/codegen/out/aignx/codegen/models/scheduling_request.py index 6b3be7d0d..712374162 100644 --- a/codegen/out/aignx/codegen/models/scheduling_request.py +++ b/codegen/out/aignx/codegen/models/scheduling_request.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/scheduling_response.py b/codegen/out/aignx/codegen/models/scheduling_response.py index fd647acce..c077ab1d7 100644 --- a/codegen/out/aignx/codegen/models/scheduling_response.py +++ b/codegen/out/aignx/codegen/models/scheduling_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/user_read_response.py b/codegen/out/aignx/codegen/models/user_read_response.py index 542122424..74f46eeef 100644 --- a/codegen/out/aignx/codegen/models/user_read_response.py +++ b/codegen/out/aignx/codegen/models/user_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/validation_error.py b/codegen/out/aignx/codegen/models/validation_error.py index 17fa7ef39..aa8a684a4 100644 --- a/codegen/out/aignx/codegen/models/validation_error.py +++ b/codegen/out/aignx/codegen/models/validation_error.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/validation_error_loc_inner.py b/codegen/out/aignx/codegen/models/validation_error_loc_inner.py index 8f81623fe..bc7371a62 100644 --- a/codegen/out/aignx/codegen/models/validation_error_loc_inner.py +++ b/codegen/out/aignx/codegen/models/validation_error_loc_inner.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/models/version_document_response.py b/codegen/out/aignx/codegen/models/version_document_response.py new file mode 100644 index 000000000..8053168ed --- /dev/null +++ b/codegen/out/aignx/codegen/models/version_document_response.py @@ -0,0 +1,99 @@ +# coding: utf-8 + +""" + Aignostics Platform API + + The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. + + The version of the OpenAPI document: 1.5.0 + 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 datetime import datetime +from pydantic import BaseModel, ConfigDict, StrictStr +from typing import Any, ClassVar, Dict, List +from aignx.codegen.models.version_document_visibility import VersionDocumentVisibility +from typing import Optional, Set +from typing_extensions import Self + +class VersionDocumentResponse(BaseModel): + """ + VersionDocumentResponse + """ # noqa: E501 + id: StrictStr + name: StrictStr + mime_type: StrictStr + visibility: VersionDocumentVisibility + created_at: datetime + updated_at: datetime + __properties: ClassVar[List[str]] = ["id", "name", "mime_type", "visibility", "created_at", "updated_at"] + + 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 VersionDocumentResponse 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. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of VersionDocumentResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "id": obj.get("id"), + "name": obj.get("name"), + "mime_type": obj.get("mime_type"), + "visibility": obj.get("visibility"), + "created_at": obj.get("created_at"), + "updated_at": obj.get("updated_at") + }) + return _obj + + diff --git a/codegen/out/aignx/codegen/models/version_document_visibility.py b/codegen/out/aignx/codegen/models/version_document_visibility.py new file mode 100644 index 000000000..82e5977a8 --- /dev/null +++ b/codegen/out/aignx/codegen/models/version_document_visibility.py @@ -0,0 +1,37 @@ +# coding: utf-8 + +""" + Aignostics Platform API + + The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. + + The version of the OpenAPI document: 1.5.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import json +from enum import Enum +from typing_extensions import Self + + +class VersionDocumentVisibility(str, Enum): + """ + VersionDocumentVisibility + """ + + """ + allowed enum values + """ + PUBLIC = 'public' + INTERNAL = 'internal' + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of VersionDocumentVisibility from a JSON string""" + return cls(json.loads(json_str)) + + diff --git a/codegen/out/aignx/codegen/models/version_read_response.py b/codegen/out/aignx/codegen/models/version_read_response.py index 55e4cf4c4..5d7ba6b9a 100644 --- a/codegen/out/aignx/codegen/models/version_read_response.py +++ b/codegen/out/aignx/codegen/models/version_read_response.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/aignx/codegen/rest.py b/codegen/out/aignx/codegen/rest.py index 824e7f3d3..1237dd274 100644 --- a/codegen/out/aignx/codegen/rest.py +++ b/codegen/out/aignx/codegen/rest.py @@ -5,7 +5,7 @@ The Aignostics Platform is a cloud-based service that enables organizations to access advanced computational pathology applications through a secure API. The platform provides standardized access to Aignostics' portfolio of computational pathology solutions, with Atlas H&E-TME serving as an example of the available API endpoints. To begin using the platform, your organization must first be registered by our business support team. If you don't have an account yet, please contact your account manager or email support@aignostics.com to get started. More information about our applications can be found on [https://platform.aignostics.com](https://platform.aignostics.com). **How to authorize and test API endpoints:** 1. Click the \"Authorize\" button in the right corner below 3. Click \"Authorize\" button in the dialog to log in with your Aignostics Platform credentials 4. After successful login, you'll be redirected back and can use \"Try it out\" on any endpoint **Note**: You only need to authorize once per session. The lock icons next to endpoints will show green when authorized. - The version of the OpenAPI document: 1.4.0 + The version of the OpenAPI document: 1.5.0 Generated by OpenAPI Generator (https://openapi-generator.tech) Do not edit the class manually. diff --git a/codegen/out/docs/PublicApi.md b/codegen/out/docs/PublicApi.md index 82fdb6bd2..0524b92cd 100644 --- a/codegen/out/docs/PublicApi.md +++ b/codegen/out/docs/PublicApi.md @@ -12,9 +12,13 @@ Method | HTTP request | Description [**get_item_by_run_v1_runs_run_id_items_external_id_get**](PublicApi.md#get_item_by_run_v1_runs_run_id_items_external_id_get) | **GET** /v1/runs/{run_id}/items/{external_id} | Get Item By Run [**get_me_v1_me_get**](PublicApi.md#get_me_v1_me_get) | **GET** /v1/me | Get current user [**get_run_v1_runs_run_id_get**](PublicApi.md#get_run_v1_runs_run_id_get) | **GET** /v1/runs/{run_id} | Get run details +[**get_version_document**](PublicApi.md#get_version_document) | **GET** /v1/applications/{application_id}/versions/{version}/documents/{name} | Get version document metadata +[**get_version_document_content**](PublicApi.md#get_version_document_content) | **GET** /v1/applications/{application_id}/versions/{version}/documents/{name}/content | Stream version document content (programmatic) +[**get_version_document_file**](PublicApi.md#get_version_document_file) | **GET** /v1/applications/{application_id}/versions/{version}/documents/{name}/file | Download version document (browser) [**list_applications_v1_applications_get**](PublicApi.md#list_applications_v1_applications_get) | **GET** /v1/applications | List available applications [**list_run_items_v1_runs_run_id_items_get**](PublicApi.md#list_run_items_v1_runs_run_id_items_get) | **GET** /v1/runs/{run_id}/items | List Run Items [**list_runs_v1_runs_get**](PublicApi.md#list_runs_v1_runs_get) | **GET** /v1/runs | List Runs +[**list_version_documents**](PublicApi.md#list_version_documents) | **GET** /v1/applications/{application_id}/versions/{version}/documents | List version documents [**put_item_custom_metadata_by_run_v1_runs_run_id_items_external_id_custom_metadata_put**](PublicApi.md#put_item_custom_metadata_by_run_v1_runs_run_id_items_external_id_custom_metadata_put) | **PUT** /v1/runs/{run_id}/items/{external_id}/custom-metadata | Put Item Custom Metadata By Run [**put_run_custom_metadata_v1_runs_run_id_custom_metadata_put**](PublicApi.md#put_run_custom_metadata_v1_runs_run_id_custom_metadata_put) | **PUT** /v1/runs/{run_id}/custom-metadata | Put Run Custom Metadata [**read_application_by_id_v1_applications_application_id_get**](PublicApi.md#read_application_by_id_v1_applications_application_id_get) | **GET** /v1/applications/{application_id} | Read Application By Id @@ -644,6 +648,243 @@ 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) +# **get_version_document** +> VersionDocumentResponse get_version_document(application_id, version, name) + +Get version document metadata + +Return metadata for a single public document attached to an application version. + +### Example + +* OAuth Authentication (OAuth2AuthorizationCodeBearer): + +```python +import aignx.codegen +from aignx.codegen.models.version_document_response import VersionDocumentResponse +from aignx.codegen.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api +# See configuration.py for a list of all supported configuration parameters. +configuration = aignx.codegen.Configuration( + host = "/api" +) + +# 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. + +configuration.access_token = os.environ["ACCESS_TOKEN"] + +# Enter a context with an instance of the API client +with aignx.codegen.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = aignx.codegen.PublicApi(api_client) + application_id = 'application_id_example' # str | + version = 'version_example' # str | + name = 'name_example' # str | + + try: + # Get version document metadata + api_response = api_instance.get_version_document(application_id, version, name) + print("The response of PublicApi->get_version_document:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling PublicApi->get_version_document: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **application_id** | **str**| | + **version** | **str**| | + **name** | **str**| | + +### Return type + +[**VersionDocumentResponse**](VersionDocumentResponse.md) + +### Authorization + +[OAuth2AuthorizationCodeBearer](../README.md#OAuth2AuthorizationCodeBearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Successful Response | - | +**404** | Document not found, not public, or version not accessible | - | +**422** | Validation 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) + +# **get_version_document_content** +> get_version_document_content(application_id, version, name) + +Stream version document content (programmatic) + +307 redirect to a short-lived GCS signed URL for streaming document content. Unlike ``/file``, no ``Content-Disposition`` override is set — GCS serves the object body with its stored ``Content-Type``. Intended for programmatic clients that follow redirects and consume the content directly. Response carries ``Cache-Control: no-store``. + +### Example + +* OAuth Authentication (OAuth2AuthorizationCodeBearer): + +```python +import aignx.codegen +from aignx.codegen.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api +# See configuration.py for a list of all supported configuration parameters. +configuration = aignx.codegen.Configuration( + host = "/api" +) + +# 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. + +configuration.access_token = os.environ["ACCESS_TOKEN"] + +# Enter a context with an instance of the API client +with aignx.codegen.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = aignx.codegen.PublicApi(api_client) + application_id = 'application_id_example' # str | + version = 'version_example' # str | + name = 'name_example' # str | + + try: + # Stream version document content (programmatic) + api_instance.get_version_document_content(application_id, version, name) + except Exception as e: + print("Exception when calling PublicApi->get_version_document_content: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **application_id** | **str**| | + **version** | **str**| | + **name** | **str**| | + +### Return type + +void (empty response body) + +### Authorization + +[OAuth2AuthorizationCodeBearer](../README.md#OAuth2AuthorizationCodeBearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**307** | Temporary redirect to signed GCS URL; GCS serves the object with its stored Content-Type | - | +**404** | Document not found, not public, or version not accessible | - | +**422** | Validation 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) + +# **get_version_document_file** +> get_version_document_file(application_id, version, name) + +Download version document (browser) + +307 redirect to a short-lived GCS signed URL for downloading a document. The signed URL includes ``response-content-disposition=attachment; filename=\"\"`` so browsers prompt a save-as dialog rather than rendering inline. Response carries ``Cache-Control: no-store``. + +### Example + +* OAuth Authentication (OAuth2AuthorizationCodeBearer): + +```python +import aignx.codegen +from aignx.codegen.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api +# See configuration.py for a list of all supported configuration parameters. +configuration = aignx.codegen.Configuration( + host = "/api" +) + +# 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. + +configuration.access_token = os.environ["ACCESS_TOKEN"] + +# Enter a context with an instance of the API client +with aignx.codegen.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = aignx.codegen.PublicApi(api_client) + application_id = 'application_id_example' # str | + version = 'version_example' # str | + name = 'name_example' # str | + + try: + # Download version document (browser) + api_instance.get_version_document_file(application_id, version, name) + except Exception as e: + print("Exception when calling PublicApi->get_version_document_file: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **application_id** | **str**| | + **version** | **str**| | + **name** | **str**| | + +### Return type + +void (empty response body) + +### Authorization + +[OAuth2AuthorizationCodeBearer](../README.md#OAuth2AuthorizationCodeBearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**307** | Temporary redirect to signed GCS URL with Content-Disposition: attachment | - | +**404** | Document not found, not public, or version not accessible | - | +**422** | Validation 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) + # **list_applications_v1_applications_get** > List[ApplicationReadShortResponse] list_applications_v1_applications_get(page=page, page_size=page_size, sort=sort) @@ -911,6 +1152,85 @@ 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) +# **list_version_documents** +> List[VersionDocumentResponse] list_version_documents(application_id, version) + +List version documents + +List public documents attached to an application version. Returns only documents with ``visibility=public`` and ``status=uploaded``. + +### Example + +* OAuth Authentication (OAuth2AuthorizationCodeBearer): + +```python +import aignx.codegen +from aignx.codegen.models.version_document_response import VersionDocumentResponse +from aignx.codegen.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api +# See configuration.py for a list of all supported configuration parameters. +configuration = aignx.codegen.Configuration( + host = "/api" +) + +# 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. + +configuration.access_token = os.environ["ACCESS_TOKEN"] + +# Enter a context with an instance of the API client +with aignx.codegen.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = aignx.codegen.PublicApi(api_client) + application_id = 'application_id_example' # str | + version = 'version_example' # str | + + try: + # List version documents + api_response = api_instance.list_version_documents(application_id, version) + print("The response of PublicApi->list_version_documents:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling PublicApi->list_version_documents: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **application_id** | **str**| | + **version** | **str**| | + +### Return type + +[**List[VersionDocumentResponse]**](VersionDocumentResponse.md) + +### Authorization + +[OAuth2AuthorizationCodeBearer](../README.md#OAuth2AuthorizationCodeBearer) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Successful Response | - | +**404** | Application version not found or not accessible | - | +**422** | Validation 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) + # **put_item_custom_metadata_by_run_v1_runs_run_id_items_external_id_custom_metadata_put** > CustomMetadataUpdateResponse put_item_custom_metadata_by_run_v1_runs_run_id_items_external_id_custom_metadata_put(run_id, external_id, custom_metadata_update_request) diff --git a/requirements/SWR-APPLICATION-1-3.md b/requirements/SWR-APPLICATION-1-3.md new file mode 100644 index 000000000..2b16d270f --- /dev/null +++ b/requirements/SWR-APPLICATION-1-3.md @@ -0,0 +1,10 @@ +--- +itemId: SWR-APPLICATION-1-3 +itemTitle: Retrieve Application Version Release Documents +itemHasParent: SHR-APPLICATION-1 +itemType: Requirement +Requirement type: FUNCTIONAL +Layer: System (backend logic) +--- + +System shall list, describe, and download release documents attached to a given application version, exposing only documents with public visibility and uploaded status. diff --git a/specifications/SPEC-APPLICATION-SERVICE.md b/specifications/SPEC-APPLICATION-SERVICE.md index 918c7c820..6dd42cf16 100644 --- a/specifications/SPEC-APPLICATION-SERVICE.md +++ b/specifications/SPEC-APPLICATION-SERVICE.md @@ -2,11 +2,11 @@ itemId: SPEC-APPLICATION-SERVICE itemTitle: Application Module Specification itemType: Software Item Spec -itemFulfills: SWR-APPLICATION-1-1, SWR-APPLICATION-1-2, SWR-APPLICATION-2-3, SWR-APPLICATION-2-4, SHR-APPLICATION-3, SWR-APPLICATION-2-12, SWR-APPLICATION-2-11, SWR-APPLICATION-2-13, SWR-APPLICATION-2-14, SWR-APPLICATION-2-15, SWR-APPLICATION-2-16, SWR-APPLICATION-2-5, SWR-APPLICATION-2-7, SWR-APPLICATION-2-8, SWR-APPLICATION-2-9, SWR-APPLICATION-3-3 +itemFulfills: SWR-APPLICATION-1-1, SWR-APPLICATION-1-2, SWR-APPLICATION-1-3, SWR-APPLICATION-2-3, SWR-APPLICATION-2-4, SHR-APPLICATION-3, SWR-APPLICATION-2-12, SWR-APPLICATION-2-11, SWR-APPLICATION-2-13, SWR-APPLICATION-2-14, SWR-APPLICATION-2-15, SWR-APPLICATION-2-16, SWR-APPLICATION-2-5, SWR-APPLICATION-2-7, SWR-APPLICATION-2-8, SWR-APPLICATION-2-9, SWR-APPLICATION-3-3 Module: Application Layer: Domain Service -Version: 0.2.106 -Date: 2025-09-09 +Version: 0.2.107 +Date: 2026-04-29 --- ## 1. Description @@ -21,7 +21,7 @@ The module implements a domain service layer that orchestrates interactions betw The Application Module shall: -- **FR-01** **Application Discovery**: List and browse available applications with filtering capabilities and detailed information retrieval +- **FR-01** **Application Discovery**: List and browse available applications with filtering capabilities and detailed information retrieval, including listing, describing, and downloading public release documents (e.g. output schemas, model manuals) attached to application versions - **FR-02** **Data Preparation**: Automatically scan directories for whole slide images (WSI), extract comprehensive metadata, and validate file formats - **FR-03** **File Upload Management**: Provide secure, chunked file upload to cloud storage with progress tracking and integrity verification - **FR-04** **Run Lifecycle Management**: Submit, monitor, cancel, and delete application runs with real-time status updates @@ -410,11 +410,14 @@ uvx aignostics application [subcommand] [options] - `list`: List all available applications with filtering - `describe`: Get detailed information about a specific application - `dump-schemata`: Export application schemata +- `version document list`: List public release documents attached to an application version +- `version document describe`: Show metadata for a single public release document +- `version document download`: Download a public release document to a local path - `run execute`: Combined prepare, upload, and submit workflow - `run prepare`: Generate metadata from source directory - `run upload`: Upload files to cloud storage - `run submit`: Submit application run -- `run list [--for-organization ORG_ID]`: List application runs; supports listing all runs for an organization with `--for-organization` (only available to org admins) +- `run list`: List application runs - `run describe`: Get detailed run information - `run cancel`: Cancel running application - `run result download`: Download run results diff --git a/specifications/SPEC_PLATFORM_SERVICE.md b/specifications/SPEC_PLATFORM_SERVICE.md index 457b273fd..b71afafd0 100644 --- a/specifications/SPEC_PLATFORM_SERVICE.md +++ b/specifications/SPEC_PLATFORM_SERVICE.md @@ -2,11 +2,11 @@ itemId: SPEC-PLATFORM-SERVICE itemTitle: Platform Module Specification itemType: Software Item Spec -itemFulfills: SWR-APPLICATION-1-1, SWR-APPLICATION-1-2, SWR-APPLICATION-2-1, SWR-APPLICATION-2-5, SWR-APPLICATION-2-6, SWR-APPLICATION-2-7, SWR-APPLICATION-2-9, SWR-APPLICATION-2-14, SWR-APPLICATION-2-15, SWR-APPLICATION-2-16, SWR-APPLICATION-3-1, SWR-APPLICATION-3-2, SWR-APPLICATION-3-3 +itemFulfills: SWR-APPLICATION-1-1, SWR-APPLICATION-1-2, SWR-APPLICATION-1-3, SWR-APPLICATION-2-1, SWR-APPLICATION-2-5, SWR-APPLICATION-2-6, SWR-APPLICATION-2-7, SWR-APPLICATION-2-9, SWR-APPLICATION-2-14, SWR-APPLICATION-2-15, SWR-APPLICATION-2-16, SWR-APPLICATION-3-1, SWR-APPLICATION-3-2, SWR-APPLICATION-3-3 Module: Platform Layer: Platform Service -Version: 1.0.0 -Date: 2025-09-09 +Version: 1.1.0 +Date: 2026-04-29 --- ## 1. Description @@ -27,7 +27,7 @@ The Platform Module shall: - **[FR-06]** Handle authentication errors with retry mechanisms and fallback flows - **[FR-07]** Support proxy configurations and SSL certificate handling for enterprise environments - **[FR-08]** Provide health monitoring for both public and authenticated API endpoints -- **[FR-09]** Manage application and application version resources with listing and filtering capabilities +- **[FR-09]** Manage application, application version, and application version release document resources with listing, filtering, metadata retrieval, and file download capabilities (release documents follow the platform `307` redirect to short-lived GCS signed URLs and are filtered to public visibility and uploaded status by the public API) - **[FR-10]** Create and manage application runs with status monitoring and result retrieval - **[FR-11]** Download and verify file integrity using CRC32C checksums for run artifacts - **[FR-12]** Generate signed URLs for secure Google Cloud Storage access @@ -81,7 +81,8 @@ platform/ | `Applications` | Class | Application resource management | `list()`, `versions` accessor | | `ApplicationRun` | Class | Run lifecycle and result management | `details()`, `cancel()`, `results()`, `download_to_folder()`, `artifact()`, `get_artifact_download_url()`, `ensure_artifacts_downloaded()` | | `Artifact` | Class | Per-artifact handle for resolving fresh presigned download URLs via the `/api/v1/runs/{run_id}/artifacts/{artifact_id}/file` endpoint | `get_download_url()` | -| `Versions` | Class | Application version management | `list()`, `list_sorted()`, `latest()`, `details()` | +| `Versions` | Class | Application version management | `list()`, `list_sorted()`, `latest()`, `details()`, `documents()` | +| `Documents` | Class | Application version release document management | `list()`, `details()`, `download_to_path()`, `read_content()` | | `Runs` | Class | Application run management and creation | `create()`, `list()` / `list_data()`, `__call__()` | | `utils` | Module | Resource utility functions and pagination helpers | `paginate()` | @@ -168,6 +169,35 @@ UserInfo: required: [user, organization, role, token] ``` +**Application Version Document Schema:** + +```yaml +ApplicationVersionDocument: + type: object + properties: + id: + type: string + format: uuid + description: Stable identifier for the document + name: + type: string + description: Document filename, unique per application version (e.g. "output_description.pdf") + mime_type: + type: string + description: IANA media type stored alongside the object (e.g. "application/pdf") + visibility: + type: string + enum: [public] + description: Documents exposed via the public API are always public; internal documents are not surfaced + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + required: [id, name, mime_type, visibility, created_at, updated_at] +``` + ### 3.4 Data Flow ```mermaid @@ -275,6 +305,76 @@ class Versions: def details(self, application_version: ApplicationVersion | str) -> ApplicationVersion: """Retrieves details for a specific application version.""" + + def documents(self, application_id: str, application_version: VersionTuple | str | None) -> "Documents": + """Returns a Documents resource bound to the given application version. + Pass None to resolve the latest version automatically.""" +``` + +```python +class Documents: + """Resource class for retrieving release documents attached to an application version. + + Backed by ``GET /api/v1/applications/{application_id}/versions/{version}/documents`` + and the per-document ``/{name}``, ``/{name}/file``, and ``/{name}/content`` endpoints. + The public API exposes only documents with ``visibility=public`` and ``status=uploaded``. + """ + + def __init__(self, api: PublicApi, application_id: str, application_version: str) -> None: + """Initializes the Documents resource bound to an (application_id, version) pair.""" + + def list(self, nocache: bool = False) -> list[ApplicationVersionDocument]: + """List metadata for all public, uploaded release documents for the bound version. + + Args: + nocache: If True, bypass cache and force a fresh API call. + + Raises: + NotFoundException: When the application version does not exist or is not accessible. + """ + + def details(self, document_name: str, nocache: bool = False) -> ApplicationVersionDocument: + """Retrieves metadata for a single release document by name. + + Raises: + NotFoundException: When the document does not exist, is not public, or is not uploaded. + """ + + def download_to_path(self, document_name: str, destination: Path | str) -> Path: + """Downloads the document file to a local directory. + + Issues a single ``GET`` against the ``/file`` endpoint and follows the + platform ``307`` redirect to a short-lived GCS signed URL, streaming the + response body to disk. The bearer token is stripped on the cross-host hop + by ``requests`` and is therefore not forwarded to the storage backend. + Returns the absolute path to the written file. + + ``destination`` must be an existing directory; the file is written as + ``{destination}/{document_name}``. The requested document name is the + canonical filename and is used regardless of any ``Content-Disposition`` + served by the storage backend. + + Note: Document downloads do not carry a CRC32C checksum (unlike run artifacts); + integrity is bounded by HTTPS transport and the signed-URL lifetime. + + Raises: + ValueError: When ``destination`` is not an existing directory. + NotFoundException: When the document does not exist, is not public, or is not uploaded. + """ + + def read_content(self, document_name: str) -> bytes: + """Fetches the document's raw content into memory. + + Issues a single ``GET`` against the ``/content`` endpoint and follows the + platform ``307`` redirect to a short-lived GCS signed URL. Unlike ``/file``, + no ``Content-Disposition`` override is set — GCS serves the body with its + stored ``Content-Type`` and ``Cache-Control: no-store``. Intended for small + documents (JSON manifests, license text, etc.) where holding the bytes in + memory is appropriate; prefer ``download_to_path`` for large files. + + Raises: + NotFoundException: When the document does not exist, is not public, or is not uploaded. + """ ``` ```python diff --git a/src/aignostics/application/_cli.py b/src/aignostics/application/_cli.py index a7d4132d5..9ee527859 100644 --- a/src/aignostics/application/_cli.py +++ b/src/aignostics/application/_cli.py @@ -19,6 +19,7 @@ DEFAULT_GPU_TYPE, DEFAULT_MAX_GPUS_PER_SLIDE, DEFAULT_NODE_ACQUISITION_TIMEOUT_MINUTES, + Client, ForbiddenException, NotFoundException, RunState, @@ -129,6 +130,19 @@ result_app = typer.Typer() run_app.add_typer(result_app, name="result", help="Download or delete run results.") +version_app = typer.Typer() +cli.add_typer(version_app, name="version", help="Inspect application versions and their release documents.") + +document_app = typer.Typer() +version_app.add_typer( + document_app, + name="document", + help=( + "List, describe, and download public release documents attached to an " + "application version (e.g. output schemas, model manuals)." + ), +) + def _abort_if_system_unhealthy() -> None: health = asyncio.run(SystemService.health_static()) @@ -1523,3 +1537,165 @@ def result_delete( logger.exception(f"Failed to delete run with ID '{run_id}'") console.print(f"[bold red]Error:[/bold red] Failed to delete results for with ID '{run_id}': {e}") sys.exit(1) + + +@document_app.command("list") +def application_version_document_list( + application_id: Annotated[ + str, + typer.Argument(help="Id of application to list release documents for."), + ], + application_version: ApplicationVersionOption = None, + format: Annotated[ # noqa: A002 + str, + typer.Option(help="Output format: 'text' (default) or 'json'"), + ] = "text", +) -> None: + """List public release documents attached to an application version.""" + version_ref = f"{application_id}:{application_version}" if application_version else application_id + try: + documents = Client().applications.versions.documents(application_id, application_version) + items = documents.list() + except NotFoundException as e: + message = f"No release documents found: application version '{version_ref}' is unavailable." + logger.warning("{} ({})", message, e) # NOSONAR python:S1192: loguru positional format string is conventional + if format == "json": + print(json.dumps({"error": "not_found", "message": message}), file=sys.stderr) + else: + console.print(f"[warning]Warning:[/warning] {message}") + sys.exit(2) + except Exception as e: + logger.exception(f"Failed to list release documents for '{version_ref}'") + if format == "json": + print(json.dumps({"error": "failed", "message": str(e)}), file=sys.stderr) + else: + console.print(f"[error]Error:[/error] Failed to list release documents for '{version_ref}': {e}") + sys.exit(1) + + if format == "json": + payload = [doc.model_dump(mode="json") for doc in items] + print(json.dumps(payload, indent=2, default=str)) + return + + console.print(f"[bold]Release documents for {version_ref.replace(':', ' ')}[/bold]") + console.print("=" * 80) + if not items: + console.print("[dim]No public release documents are attached to this version.[/dim]") + return + for doc in items: + console.print(f"[bold]{doc.name}[/bold]") + console.print(f" Id: {doc.id}") + console.print(f" MIME type: {doc.mime_type}") + console.print(f" Created at: {doc.created_at.isoformat()}") + console.print(f" Updated at: {doc.updated_at.isoformat()}") + + +@document_app.command("describe") +def application_version_document_describe( + application_id: Annotated[ + str, + typer.Argument(help="Id of application to describe release documents for."), + ], + document_name: Annotated[str, typer.Argument(..., help="Document filename (e.g. 'output_description.pdf').")], + application_version: ApplicationVersionOption = None, + format: Annotated[ # noqa: A002 + str, + typer.Option(help="Output format: 'text' (default) or 'json'"), + ] = "text", +) -> None: + """Show metadata for a single public release document.""" + version_ref = f"{application_id}:{application_version}" if application_version else application_id + try: + documents = Client().applications.versions.documents(application_id, application_version) + except NotFoundException as e: + message = f"Application version '{version_ref}' is unavailable." + logger.warning("{} ({})", message, e) # NOSONAR python:S1192 + if format == "json": + print(json.dumps({"error": "not_found", "message": message}), file=sys.stderr) + else: + console.print(f"[warning]Warning:[/warning] {message}") + sys.exit(2) + try: + doc = documents.details(document_name) + except NotFoundException: + message = f"Document '{document_name}' not found for application version '{version_ref}'." + logger.warning(message) + if format == "json": + print(json.dumps({"error": "not_found", "message": message}), file=sys.stderr) + else: + console.print(f"[warning]Warning:[/warning] {message}") + sys.exit(2) + except Exception as e: + logger.exception(f"Failed to describe release document '{document_name}' for '{version_ref}'") + if format == "json": + print(json.dumps({"error": "failed", "message": str(e)}), file=sys.stderr) + else: + console.print( + f"[error]Error:[/error] Failed to describe release document '{document_name}' for '{version_ref}': {e}" + ) + sys.exit(1) + + if format == "json": + print(json.dumps(doc.model_dump(mode="json"), indent=2, default=str)) + return + + console.print(f"[bold]Release document '{doc.name}' on {version_ref.replace(':', ' ')}[/bold]") + console.print("=" * 80) + console.print(f"[bold]Id:[/bold] {doc.id}") + console.print(f"[bold]Name:[/bold] {doc.name}") + console.print(f"[bold]MIME type:[/bold] {doc.mime_type}") + console.print(f"[bold]Created at:[/bold] {doc.created_at.isoformat()}") + console.print(f"[bold]Updated at:[/bold] {doc.updated_at.isoformat()}") + + +@document_app.command("download") +def application_version_document_download( + application_id: Annotated[ + str, + typer.Argument(help="Id of application to download release documents for."), + ], + document_name: Annotated[str, typer.Argument(..., help="Document filename (e.g. 'output_description.pdf').")], + application_version: ApplicationVersionOption = None, + output: Annotated[ + Path, + typer.Option( + "--output", + help="Destination directory. Defaults to the current working directory.", + file_okay=False, + dir_okay=True, + writable=True, + resolve_path=True, + show_default="", + ), + ] = Path().cwd(), # noqa: B008 +) -> None: + """Download a public release document to a local path. + + The platform serves the document via a short-lived signed URL with + ``Content-Disposition: attachment``; the file is written using the document's name. + Document downloads do not carry a CRC32C checksum (unlike run artifacts); integrity + is bounded by HTTPS transport and the signed-URL lifetime. + """ + version_ref = f"{application_id}:{application_version}" if application_version else application_id + try: + documents = Client().applications.versions.documents(application_id, application_version) + except NotFoundException as e: + message = f"Application version '{version_ref}' is unavailable." + logger.warning("{} ({})", message, e) # NOSONAR python:S1192 + console.print(f"[warning]Warning:[/warning] {message}") + sys.exit(2) + try: + written = documents.download_to_path(document_name, output) + except NotFoundException: + message = f"Document '{document_name}' not found for application version '{version_ref}'." + logger.warning(message) + console.print(f"[warning]Warning:[/warning] {message}") + sys.exit(2) + except Exception as e: + logger.exception(f"Failed to download release document '{document_name}' for '{version_ref}'") + console.print( + f"[error]Error:[/error] Failed to download release document '{document_name}' for '{version_ref}': {e}" + ) + sys.exit(1) + + console.print(f"Downloaded '{document_name}' to {written}") diff --git a/src/aignostics/platform/__init__.py b/src/aignostics/platform/__init__.py index 1fcaf481c..fea6f14f4 100644 --- a/src/aignostics/platform/__init__.py +++ b/src/aignostics/platform/__init__.py @@ -96,6 +96,7 @@ get_mime_type_for_artifact, mime_type_to_file_ending, ) +from .resources.applications import ApplicationVersionDocument, Documents from .resources.runs import LIST_APPLICATION_RUNS_MAX_PAGE_SIZE, LIST_APPLICATION_RUNS_MIN_PAGE_SIZE, Artifact, Run __all__ = [ @@ -150,9 +151,11 @@ "Application", "ApplicationSummary", "ApplicationVersion", + "ApplicationVersionDocument", "Artifact", "ArtifactOutput", "Client", + "Documents", "ForbiddenException", "InputArtifact", "InputArtifactData", diff --git a/src/aignostics/platform/resources/applications.py b/src/aignostics/platform/resources/applications.py index f507ddf41..9805fce70 100644 --- a/src/aignostics/platform/resources/applications.py +++ b/src/aignostics/platform/resources/applications.py @@ -1,21 +1,30 @@ """Applications resource module for the Aignostics platform. This module provides classes for interacting with application resources in the Aignostics API. -It includes functionality for listing applications and managing application versions. +It includes functionality for listing applications, managing application versions, +and retrieving application version release documents. """ import builtins import typing as t +from datetime import datetime +from http import HTTPStatus +from io import BytesIO from operator import itemgetter +from pathlib import Path +from urllib.parse import quote +import requests import semver from aignx.codegen.api.public_api import PublicApi from aignx.codegen.exceptions import NotFoundException, ServiceException from aignx.codegen.models import ApplicationReadResponse as Application from aignx.codegen.models import ApplicationReadShortResponse as ApplicationSummary from aignx.codegen.models import ApplicationVersion as VersionTuple +from aignx.codegen.models import VersionDocumentResponse as VersionDocumentData from aignx.codegen.models import VersionReadResponse as ApplicationVersion from loguru import logger +from pydantic import BaseModel, ConfigDict from tenacity import ( RetryCallState, Retrying, @@ -26,11 +35,14 @@ from urllib3.exceptions import IncompleteRead, PoolError, ProtocolError, ProxyError from urllib3.exceptions import TimeoutError as Urllib3TimeoutError +from aignostics.platform._authentication import get_token from aignostics.platform._operation_cache import cached_operation from aignostics.platform._settings import settings from aignostics.platform.resources.utils import paginate from aignostics.utils import user_agent +_DOCUMENT_DOWNLOAD_CHUNK_SIZE = 1024 * 1024 # 1 MB + RETRYABLE_EXCEPTIONS = ( ServiceException, Urllib3TimeoutError, @@ -74,6 +86,36 @@ def __init__(self, api: PublicApi) -> None: """ self._api = api + def _get_application_version_validated( + self, application_id: str, application_version: VersionTuple | str | None + ) -> str: + """Validate and extract the version string from a VersionTuple or str. + + Args: + application_id (str): The ID of the application. + application_version (VersionTuple | str | None): The version to validate. + + Returns: + str: The validated version string. + + Raises: + ValueError: If the version is not a valid semver string. + NotFoundException: If the version is None and no versions are found for the application. + """ + # Handle version resolution and validation first (not retried) + if application_version is None: + application_version = self.latest(application=application_id) + if application_version is None: + message = f"No versions found for application '{application_id}'." + raise NotFoundException(message) + application_version = application_version.number + elif isinstance(application_version, VersionTuple): + application_version = application_version.number + elif application_version and not semver.Version.is_valid(application_version): + message = f"Invalid version format: '{application_version}' not compliant with semantic versioning." + raise ValueError(message) + return application_version + def list(self, application: Application | str, nocache: bool = False) -> builtins.list[VersionTuple]: """Find all versions for a specific application. @@ -135,18 +177,7 @@ def details( NotFoundException: If the application or version is not found. aignx.codegen.exceptions.ApiException: If the API request fails. """ - # Handle version resolution and validation first (not retried) - if application_version is None: - application_version = self.latest(application=application_id) - if application_version is None: - message = f"No versions found for application '{application_id}'." - raise NotFoundException(message) - application_version = application_version.number - elif isinstance(application_version, VersionTuple): - application_version = application_version.number - elif application_version and not semver.Version.is_valid(application_version): - message = f"Invalid version format: '{application_version}' not compliant with semantic versioning." - raise ValueError(message) + application_version = self._get_application_version_validated(application_id, application_version) # Make the API call with retry logic and caching @cached_operation(ttl=settings().application_version_cache_ttl, use_token=True) @@ -223,6 +254,411 @@ def latest(self, application: Application | str, nocache: bool = False) -> Versi sorted_versions = self.list_sorted(application=application, nocache=nocache) return sorted_versions[0] if sorted_versions else None + def documents(self, application_id: str, application_version: VersionTuple | str | None) -> "Documents": + """Returns a Documents resource bound to the given application version. + + Args: + application_id (str): The ID of the application (e.g. "heta"). + application_version (VersionTuple | str | None): The application version, either as a + VersionTuple, a semantic version string (e.g. "1.0.0"), or None to use the latest version. + + Returns: + Documents: A Documents resource bound to the (application_id, version) pair. + """ + application_version = self._get_application_version_validated(application_id, application_version) + + return Documents(self._api, application_id=application_id, application_version=application_version) + + +class ApplicationVersionDocument(BaseModel): + """Public release document attached to an application version. + + The Aignostics public API exposes only documents with ``visibility=public`` and + ``status=uploaded``. Internal-visibility documents are not surfaced. + """ + + id: str + name: str + mime_type: str + created_at: datetime + updated_at: datetime + + model_config = ConfigDict(populate_by_name=True, validate_assignment=True) + + @classmethod + def from_response(cls, data: VersionDocumentData) -> "ApplicationVersionDocument": + """Build an ApplicationVersionDocument from the codegen response model. + + Args: + data: The codegen ``VersionDocumentResponse`` returned by the API. + + Returns: + ApplicationVersionDocument: Wrapped, SDK-friendly Pydantic model. + """ + return cls( + id=data.id, + name=data.name, + mime_type=data.mime_type, + created_at=data.created_at, + updated_at=data.updated_at, + ) + + +class Documents: + """Resource class for retrieving release documents attached to an application version. + + Backed by ``GET /api/v1/applications/{application_id}/versions/{version}/documents`` + and the per-document ``/{name}``, ``/{name}/file``, and ``/{name}/content`` endpoints. + + The public API exposes only documents with ``visibility=public`` and + ``status=uploaded``. Internal-visibility documents are not surfaced. + + Document downloads do not carry a CRC32C checksum (unlike run artifacts); + integrity is bounded by HTTPS transport and the signed-URL lifetime. + """ + + def __init__(self, api: PublicApi, application_id: str, application_version: str | VersionTuple) -> None: + """Initializes the Documents resource bound to an application version. + + Args: + api (PublicApi): The configured API client. + application_id (str): The ID of the application (e.g. "heta"). + application_version (str | VersionTuple): The semantic version number (e.g. "1.0.0") or a VersionTuple. + """ + self._api = api + self.application_id = application_id + if isinstance(application_version, str): + self.application_version = application_version + else: + self.application_version = application_version.number + + def list(self, nocache: bool = False) -> builtins.list[ApplicationVersionDocument]: + """List metadata for all public, uploaded release documents for the bound version. + + Retries on network and server errors. Cached for the configured application-version TTL. + + Args: + nocache (bool): If True, skip reading from cache and fetch fresh data from the API. + The fresh result will still be cached for subsequent calls. Defaults to False. + + Returns: + list[ApplicationVersionDocument]: Metadata for each public, uploaded document. + + Raises: + NotFoundException: When the application version does not exist or is not accessible. + aignx.codegen.exceptions.ApiException: If the API request fails. + """ + + @cached_operation(ttl=settings().application_version_cache_ttl, use_token=True) + def list_with_retry(application_id: str, application_version: str) -> builtins.list[VersionDocumentData]: + return Retrying( + retry=retry_if_exception_type(exception_types=RETRYABLE_EXCEPTIONS), + stop=stop_after_attempt(settings().application_version_retry_attempts), + wait=wait_exponential_jitter( + initial=settings().application_version_retry_wait_min, + max=settings().application_version_retry_wait_max, + ), + before_sleep=_log_retry_attempt, + reraise=True, + )( + lambda: self._api.list_version_documents( + application_id=application_id, + version=application_version, + _request_timeout=settings().application_version_timeout, + _headers={"User-Agent": user_agent()}, + ) + ) + + documents = list_with_retry(self.application_id, self.application_version, nocache=nocache) # type: ignore[call-arg] # pyright: ignore[reportCallIssue] + return [ApplicationVersionDocument.from_response(doc) for doc in (documents or [])] + + def details(self, document_name: str, nocache: bool = False) -> ApplicationVersionDocument: + """Retrieve metadata for a single release document by name. + + Retries on network and server errors. Cached for the configured application-version TTL. + + Args: + document_name (str): The document filename (e.g. "output_description.pdf"). + nocache (bool): If True, skip reading from cache and fetch fresh data from the API. + The fresh result will still be cached for subsequent calls. Defaults to False. + + Returns: + ApplicationVersionDocument: The document metadata. + + Raises: + NotFoundException: When the document does not exist, is not public, or is not uploaded. + aignx.codegen.exceptions.ApiException: If the API request fails. + """ + + @cached_operation(ttl=settings().application_version_cache_ttl, use_token=True) + def details_with_retry( + application_id: str, application_version: str, document_name: str + ) -> VersionDocumentData: + return Retrying( + retry=retry_if_exception_type(exception_types=RETRYABLE_EXCEPTIONS), + stop=stop_after_attempt(settings().application_version_retry_attempts), + wait=wait_exponential_jitter( + initial=settings().application_version_retry_wait_min, + max=settings().application_version_retry_wait_max, + ), + before_sleep=_log_retry_attempt, + reraise=True, + )( + lambda: self._api.get_version_document( + application_id=application_id, + version=application_version, + name=document_name, + _request_timeout=settings().application_version_timeout, + _headers={"User-Agent": user_agent()}, + ) + ) + + # The cached_operation decorator injects a `nocache` keyword that pyright/mypy can't see. + data = details_with_retry(self.application_id, self.application_version, document_name, nocache=nocache) # type: ignore[call-arg] # pyright: ignore[reportCallIssue] + return ApplicationVersionDocument.from_response(data) + + def download_to_path(self, document_name: str, destination: Path | str) -> Path: + """Download a release document file to a local path. + + Calls ``GET /api/v1/applications/{application_id}/versions/{version}/documents/{name}/file``, + which returns a ``307`` redirect to a short-lived GCS signed URL serving the file + with ``Content-Disposition: attachment; filename="{name}"``. ``requests`` follows + the redirect automatically and strips the bearer ``Authorization`` header on the + cross-host hop, so the credential is not forwarded to GCS. + + If ``destination`` is a directory, the file is written as + ``{destination}/{document_name}``; the requested document name is the canonical + filename and is used regardless of any ``Content-Disposition`` served by the + storage backend. If ``destination`` is a file path, the file is written there + verbatim. Parent directories are created if they do not yet exist. + + Document downloads do not carry a CRC32C checksum (unlike run artifacts); + integrity is bounded by HTTPS transport and the signed-URL lifetime. + + Args: + document_name (str): The document filename. + destination (Path | str): Target directory to write into. + + Returns: + Path: The absolute path to the written file. + + Raises: + NotFoundException: When the document does not exist, is not public, or is not uploaded. + ServiceException: 5xx errors, request timeouts, or connection errors after retries. + requests.HTTPError: For other 4xx errors or signed-URL download failures. + """ + destination_path = self._resolve_destination_path(destination, document_name) + endpoint_url, token_provider, ssl_verify, proxy = self._prepare_document_request( + document_name=document_name, suffix="file" + ) + + def _stream_to_disk() -> None: + with destination_path.open("wb") as out_file: + self._stream_document( + url=endpoint_url, + write_chunk=out_file.write, + document_name=document_name, + token_provider=token_provider, + ssl_verify=ssl_verify, + proxy=proxy, + ) + + Retrying( + retry=retry_if_exception_type(exception_types=RETRYABLE_EXCEPTIONS), + stop=stop_after_attempt(settings().application_version_retry_attempts), + wait=wait_exponential_jitter( + initial=settings().application_version_retry_wait_min, + max=settings().application_version_retry_wait_max, + ), + before_sleep=_log_retry_attempt, + reraise=True, + )(_stream_to_disk) + return destination_path + + @staticmethod + def _resolve_destination_path(destination: Path | str, document_name: str) -> Path: + """Resolve the on-disk path to write a document to and ensure its parent exists. + + Returns: + Path: The absolute, parent-created destination path. + + Raises: + ValueError: If the destination is an existing file or a non-existent path + with an existing parent that is a file. + """ + destination_path = Path(destination) + if destination_path.is_file() or (destination_path.exists() and not destination_path.is_dir()): + msg = f"Destination '{destination}' is an existing file. Please provide a directory or a non-existent path." + raise ValueError(msg) + + destination_path /= document_name + destination_path = destination_path.resolve() + destination_path.parent.mkdir(parents=True, exist_ok=True) + return destination_path + + @staticmethod + def _build_document_endpoint_url( + host: str, application_id: str, version: str, document_name: str, suffix: str + ) -> str: + """Build a per-document endpoint URL with each path segment encoded individually. + + Per-segment encoding ensures reserved characters (spaces, '#', '?', '/', ...) inside + a document name cannot inject extra path segments or query strings into the URL. + + Args: + host: API host (without trailing slash). + application_id: Application ID. + version: Application version (semver string). + document_name: Document filename. + suffix: Endpoint variant — ``"file"`` for browser-attachment downloads or + ``"content"`` for programmatic raw-content streaming. + + Returns: + str: The fully-qualified ``/api/v1/applications/.../documents/.../{suffix}`` URL. + """ + encoded_application_id = quote(application_id, safe="") + encoded_version = quote(version, safe="") + encoded_document_name = quote(document_name, safe="") + return ( + f"{host}/api/v1/applications/{encoded_application_id}" + f"/versions/{encoded_version}/documents/{encoded_document_name}/{suffix}" + ) + + def _prepare_document_request( + self, document_name: str, suffix: str + ) -> tuple[str, t.Callable[[], str], bool | str, str | None]: + """Resolve the endpoint URL and the codegen client's transport settings for a document. + + Honors the codegen client's ``token_provider`` when set: ``Client.get_api_client()`` + wires it up with ``use_cache=cache_token``, so a user who instantiates + ``Client(cache_token=False)`` does not want us to read/write the token cache. + Falls back to ``get_token()`` only when the configuration was built outside of + ``Client`` (e.g. unit tests with bare ``PublicApi``). + + Returns: + tuple of (endpoint_url, token_provider, ssl_verify, proxy). + """ + configuration = self._api.api_client.configuration + endpoint_url = self._build_document_endpoint_url( + host=configuration.host.rstrip("/"), + application_id=self.application_id, + version=self.application_version, + document_name=document_name, + suffix=suffix, + ) + ssl_ca_cert = getattr(configuration, "ssl_ca_cert", None) + verify_ssl = getattr(configuration, "verify_ssl", True) + ssl_verify: bool | str = ssl_ca_cert or verify_ssl + token_provider = getattr(configuration, "token_provider", None) or get_token + proxy = getattr(configuration, "proxy", None) + return endpoint_url, token_provider, ssl_verify, proxy + + # Private helper; splitting params would require a thin DTO. + def _stream_document( # noqa: PLR0913, PLR0917 + self, + url: str, + write_chunk: t.Callable[[bytes], object], + document_name: str, + token_provider: t.Callable[[], str], + ssl_verify: bool | str, + proxy: str | None, + ) -> None: + """Stream a single document download into a caller-provided sink. + + ``write_chunk`` is invoked for each non-empty body chunk; the caller decides + where the bytes go (file on disk, in-memory buffer, ...). Return type is + ``object`` so both ``BinaryIO.write`` and ``BytesIO.write`` (which return + the number of bytes written) are accepted without a cast. + + Raises: + NotFoundException: When the platform returns 404 for the document. + ServiceException: For 5xx responses, request timeouts, or connection errors. + """ + try: + with requests.get( + url, + headers={ + "Authorization": f"Bearer {token_provider()}", + "User-Agent": user_agent(), + }, + allow_redirects=True, + timeout=settings().application_version_timeout, + proxies={"http": proxy, "https": proxy} if proxy else None, + verify=ssl_verify, + stream=True, + ) as response: + if response.status_code == HTTPStatus.NOT_FOUND: + raise NotFoundException( + status=HTTPStatus.NOT_FOUND.value, + reason=( + f"Document '{document_name}' not found for application " + f"'{self.application_id}' version '{self.application_version}'" + ), + ) + if response.status_code >= HTTPStatus.INTERNAL_SERVER_ERROR: + raise ServiceException(status=response.status_code, reason=response.reason) + response.raise_for_status() + for chunk in response.iter_content(chunk_size=_DOCUMENT_DOWNLOAD_CHUNK_SIZE): + if chunk: + write_chunk(chunk) + except requests.Timeout as e: + raise ServiceException(status=HTTPStatus.SERVICE_UNAVAILABLE.value, reason="Request timed out") from e + except requests.ConnectionError as e: + raise ServiceException(status=HTTPStatus.SERVICE_UNAVAILABLE.value, reason="Connection failed") from e + + def read_content(self, document_name: str) -> bytes: + """Fetch a release document's raw content into memory. + + Calls ``GET /api/v1/applications/{application_id}/versions/{version}/documents/{name}/content``, + which returns a ``307`` redirect to a short-lived GCS signed URL. Unlike ``/file``, + no ``Content-Disposition`` override is set — GCS serves the object body with its + stored ``Content-Type`` and ``Cache-Control: no-store``. + + Use this for small documents (JSON manifests, license text, etc.) where holding + the bytes in memory is appropriate. For large files, prefer ``download_to_path``, + which streams directly to disk. + + Document downloads do not carry a CRC32C checksum (unlike run artifacts); + integrity is bounded by HTTPS transport and the signed-URL lifetime. + + Args: + document_name (str): The document filename. + + Returns: + bytes: The raw document content. + + Raises: + NotFoundException: When the document does not exist, is not public, or is not uploaded. + ServiceException: 5xx errors, request timeouts, or connection errors after retries. + requests.HTTPError: For other 4xx errors or signed-URL download failures. + """ + endpoint_url, token_provider, ssl_verify, proxy = self._prepare_document_request( + document_name=document_name, suffix="content" + ) + + def _stream_to_buffer() -> bytes: + buffer = BytesIO() + self._stream_document( + url=endpoint_url, + write_chunk=buffer.write, + document_name=document_name, + token_provider=token_provider, + ssl_verify=ssl_verify, + proxy=proxy, + ) + return buffer.getvalue() + + return Retrying( + retry=retry_if_exception_type(exception_types=RETRYABLE_EXCEPTIONS), + stop=stop_after_attempt(settings().application_version_retry_attempts), + wait=wait_exponential_jitter( + initial=settings().application_version_retry_wait_min, + max=settings().application_version_retry_wait_max, + ), + before_sleep=_log_retry_attempt, + reraise=True, + )(_stream_to_buffer) + class Applications: """Resource class for managing applications. diff --git a/tests/aignostics/application/TC-APPLICATION-CLI-05.feature b/tests/aignostics/application/TC-APPLICATION-CLI-05.feature new file mode 100644 index 000000000..d6603a9b5 --- /dev/null +++ b/tests/aignostics/application/TC-APPLICATION-CLI-05.feature @@ -0,0 +1,43 @@ +Feature: Application Version Release Documents + + The system exposes release documents (output schemas, model manuals, etc.) + attached to an application version, allowing users to list document metadata, + describe a single document, and download document files. Only documents with + public visibility and uploaded status are exposed. + + @tests:SPEC-APPLICATION-SERVICE + @tests:SPEC-PLATFORM-SERVICE + @tests:SWR-APPLICATION-1-3 + @id:TC-APPLICATION-CLI-05-01 + Scenario: System lists release documents for an application version + Given the user has access to an application version with release documents attached + When the user requests the list of release documents for the application version + Then the system shall return metadata for documents with public visibility and uploaded status + + @tests:SPEC-APPLICATION-SERVICE + @tests:SPEC-PLATFORM-SERVICE + @tests:SWR-APPLICATION-1-3 + @id:TC-APPLICATION-CLI-05-02 + Scenario: System describes a single release document + Given the user has access to an application version with a public release document + When the user requests metadata for that document by name + Then the system shall return the document metadata including id, mime type, and timestamps + + @tests:SPEC-APPLICATION-SERVICE + @tests:SPEC-PLATFORM-SERVICE + @tests:SWR-APPLICATION-1-3 + @id:TC-APPLICATION-CLI-05-03 + Scenario: System rejects requests for non-existent or non-public release documents + Given the user has access to an application version + When the user requests metadata for a document that does not exist or is not public + Then the system shall raise a not-found error indicating the document is unavailable + + @tests:SPEC-APPLICATION-SERVICE + @tests:SPEC-PLATFORM-SERVICE + @tests:SWR-APPLICATION-1-3 + @id:TC-APPLICATION-CLI-05-04 + Scenario: System downloads a release document file to a local directory + Given the user has access to an application version with a public release document + When the user requests download of that document to a local directory + Then the system shall follow the platform redirect to the signed storage URL + And the system shall write the document file using the requested document name diff --git a/tests/aignostics/application/cli_test.py b/tests/aignostics/application/cli_test.py index 412e2e8dc..1b06abe42 100644 --- a/tests/aignostics/application/cli_test.py +++ b/tests/aignostics/application/cli_test.py @@ -39,6 +39,7 @@ ) MESSAGE_RUN_NOT_FOUND = "Warning: Run with ID '4711' not found" +API_REASON_NOT_FOUND = "Not Found" TEST_APPLICATION_DEADLINE_SECONDS = 60 * 45 # 45 minutes TEST_APPLICATION_DUE_DATE_SECONDS = 60 * 10 # 10 minutes @@ -48,6 +49,17 @@ RUN_CSV_FILENAME = "run.csv" +DOCUMENT_OUTPUT_DESCRIPTION_PDF = "output_description.pdf" +DOCUMENT_MODEL_CARD_PDF = "model_card.pdf" +DOCUMENT_MISSING_PDF = "missing.pdf" +APPLICATION_CLI_CLIENT_PATCH_TARGET = "aignostics.application._cli.Client" + +# Stub values reused across the document CLI tests. +DOCUMENT_TEST_FAILURE_MESSAGE = "kaboom" # canonical exception body for unexpected-failure paths +DOCUMENT_LATEST_VERSION_NUMBER = "1.0.0" +DOCUMENT_ERROR_CODE_NOT_FOUND = "not_found" # JSON-error contract: missing resource +DOCUMENT_ERROR_CODE_FAILED = "failed" # JSON-error contract: unexpected failure + # Full SPOT_0 CSV - single source of truth for all run submissions in this test file. CSV_CONTENT_SPOT0 = ( "external_id;checksum_base64_crc32c;resolution_mpp;width_px;height_px;" @@ -924,6 +936,7 @@ def test_cli_run_describe_json_includes_items(runner: CliRunner) -> None: termination_reason=ItemTerminationReason.SUCCEEDED, error_message=None, error_code=None, + input_artifacts=[], output_artifacts=[], ) @@ -1668,3 +1681,511 @@ def test_cli_json_format_and_cancel_by_filter_with_dry_run( # noqa: PLR0915, PL f"Run {idx} has unexpected termination reason: {described_run.get('termination_reason')}" ) logger.info("Run {} successfully canceled (state: TERMINATED, reason: CANCELED_BY_USER)", idx) + + +# ---------------------------------------------------------------------------------- +# Application version document CLI tests (TC-APPLICATION-CLI-05) +# ---------------------------------------------------------------------------------- + + +def _make_document_stub(name: str = DOCUMENT_OUTPUT_DESCRIPTION_PDF) -> MagicMock: + """Create a stub ApplicationVersionDocument with realistic field values.""" + stub = MagicMock() + stub.id = "11111111-1111-1111-1111-111111111111" + stub.name = name + stub.mime_type = "application/pdf" # NOSONAR python:S1192: standard MIME type literal is clearer than a constant + stub.created_at = datetime(2026, 1, 1, 12, 0, tzinfo=UTC) + stub.updated_at = datetime(2026, 1, 2, 12, 0, tzinfo=UTC) + stub.model_dump.return_value = { + "id": stub.id, + "name": stub.name, + "mime_type": stub.mime_type, + "created_at": stub.created_at.isoformat(), + "updated_at": stub.updated_at.isoformat(), + } + return stub + + +@pytest.mark.unit +def test_cli_application_version_document_list_success(runner: CliRunner, record_property) -> None: + """`application version document list` prints document metadata.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + fake_documents = MagicMock() + fake_documents.list.return_value = [ + _make_document_stub(DOCUMENT_OUTPUT_DESCRIPTION_PDF), + _make_document_stub(DOCUMENT_MODEL_CARD_PDF), + ] + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta"]) + + assert result.exit_code == 0 + output = normalize_output(result.output) + assert DOCUMENT_OUTPUT_DESCRIPTION_PDF in output + assert DOCUMENT_MODEL_CARD_PDF in output + assert "application/pdf" in output # NOSONAR python:S1192: standard MIME type literal is clearer than a constant + fake_client.applications.versions.documents.assert_called_once_with("heta", None) + + +@pytest.mark.unit +def test_cli_application_version_document_describe_success(runner: CliRunner, record_property) -> None: + """`application version document describe` prints metadata for a single document.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-02") + fake_documents = MagicMock() + fake_documents.details.return_value = _make_document_stub(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "describe", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--application-version", + DOCUMENT_LATEST_VERSION_NUMBER, + ], + ) + + assert result.exit_code == 0 + output = normalize_output(result.output) + assert DOCUMENT_OUTPUT_DESCRIPTION_PDF in output + assert "application/pdf" in output # NOSONAR python:S1192: standard MIME type literal is clearer than a constant + fake_client.applications.versions.documents.assert_called_once_with("heta", DOCUMENT_LATEST_VERSION_NUMBER) + fake_documents.details.assert_called_once_with(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + + +@pytest.mark.unit +def test_cli_application_version_document_describe_not_found(runner: CliRunner, record_property) -> None: + """`application version document describe` exits 2 with a clear message on 404.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_documents = MagicMock() + fake_documents.details.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + ["application", "version", "document", "describe", "heta", DOCUMENT_MISSING_PDF], + ) + + assert result.exit_code == 2 + output = normalize_output(result.output) + assert f"Document '{DOCUMENT_MISSING_PDF}' not found for application version 'heta'." in output + + +@pytest.mark.unit +def test_cli_application_version_document_download_success(runner: CliRunner, tmp_path: Path, record_property) -> None: + """`application version document download` writes the file and prints the destination.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-04") + fake_documents = MagicMock() + expected_path = tmp_path / DOCUMENT_OUTPUT_DESCRIPTION_PDF + fake_documents.download_to_path.return_value = expected_path + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "download", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--output", + str(tmp_path), + ], + ) + + assert result.exit_code == 0 + output = normalize_output(result.output) + assert str(expected_path) in output + fake_documents.download_to_path.assert_called_once() + args, _ = fake_documents.download_to_path.call_args + assert args[0] == DOCUMENT_OUTPUT_DESCRIPTION_PDF + + +@pytest.mark.unit +def test_cli_application_version_document_list_json_success(runner: CliRunner, record_property) -> None: + """`application version document list --format json` emits a JSON array of documents.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + fake_documents = MagicMock() + fake_documents.list.return_value = [ + _make_document_stub(DOCUMENT_OUTPUT_DESCRIPTION_PDF), + _make_document_stub(DOCUMENT_MODEL_CARD_PDF), + ] + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta", "--format", "json"]) + + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert isinstance(payload, list) + assert len(payload) == 2 + assert payload[0]["name"] == DOCUMENT_OUTPUT_DESCRIPTION_PDF + assert payload[1]["name"] == DOCUMENT_MODEL_CARD_PDF + assert ( + payload[0]["mime_type"] == "application/pdf" + ) # NOSONAR python:S1192: standard MIME type literal is clearer than a constant + + +@pytest.mark.unit +def test_cli_application_version_document_list_json_empty(runner: CliRunner, record_property) -> None: + """`application version document list --format json` emits an empty array when none attached.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + fake_documents = MagicMock() + fake_documents.list.return_value = [] + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta", "--format", "json"]) + + assert result.exit_code == 0 + assert json.loads(result.stdout) == [] + + +@pytest.mark.unit +def test_cli_application_version_document_list_resolve_not_found_text(runner: CliRunner, record_property) -> None: + """`application version document list` exits 2 when the application version cannot be resolved.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_client = MagicMock() + fake_client.applications.versions.documents.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta"]) + + assert result.exit_code == 2 + output = normalize_output(result.output) + assert "No release documents found" in output + assert "heta" in output + + +@pytest.mark.unit +def test_cli_application_version_document_list_resolve_not_found_json(runner: CliRunner, record_property) -> None: + """`application version document list --format json` emits structured error on 404.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_client = MagicMock() + fake_client.applications.versions.documents.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta", "--format", "json"]) + + assert result.exit_code == 2 + payload = json.loads(result.stderr) + assert payload["error"] == DOCUMENT_ERROR_CODE_NOT_FOUND + assert "heta" in payload["message"] + + +@pytest.mark.unit +def test_cli_application_version_document_list_failed_text(runner: CliRunner, record_property) -> None: + """`application version document list` exits 1 with an error message on unexpected failure.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + fake_documents = MagicMock() + fake_documents.list.side_effect = RuntimeError(DOCUMENT_TEST_FAILURE_MESSAGE) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta"]) + + assert result.exit_code == 1 + output = normalize_output(result.output) + assert "Failed to list release documents for 'heta'" in output + assert DOCUMENT_TEST_FAILURE_MESSAGE in output + + +@pytest.mark.unit +def test_cli_application_version_document_list_failed_json(runner: CliRunner, record_property) -> None: + """`application version document list --format json` emits structured error on failure.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-01") + fake_documents = MagicMock() + fake_documents.list.side_effect = RuntimeError(DOCUMENT_TEST_FAILURE_MESSAGE) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke(cli, ["application", "version", "document", "list", "heta", "--format", "json"]) + + assert result.exit_code == 1 + payload = json.loads(result.stderr) + assert payload["error"] == DOCUMENT_ERROR_CODE_FAILED + assert DOCUMENT_TEST_FAILURE_MESSAGE in payload["message"] + + +@pytest.mark.unit +def test_cli_application_version_document_describe_json_success(runner: CliRunner, record_property) -> None: + """`application version document describe --format json` emits a single JSON object.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-02") + fake_documents = MagicMock() + fake_documents.details.return_value = _make_document_stub(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "describe", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--application-version", + DOCUMENT_LATEST_VERSION_NUMBER, + "--format", + "json", + ], + ) + + assert result.exit_code == 0 + payload = json.loads(result.stdout) + assert payload["name"] == DOCUMENT_OUTPUT_DESCRIPTION_PDF + assert ( + payload["mime_type"] == "application/pdf" + ) # NOSONAR python:S1192: standard MIME type literal is clearer than a constant + + +@pytest.mark.unit +def test_cli_application_version_document_describe_resolve_not_found_text(runner: CliRunner, record_property) -> None: + """`describe` exits 2 when the application version cannot be resolved (text format).""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_client = MagicMock() + fake_client.applications.versions.documents.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + ["application", "version", "document", "describe", "heta", DOCUMENT_OUTPUT_DESCRIPTION_PDF], + ) + + assert result.exit_code == 2 + output = normalize_output(result.output) + assert "Application version 'heta' is unavailable." in output + + +@pytest.mark.unit +def test_cli_application_version_document_describe_resolve_not_found_json(runner: CliRunner, record_property) -> None: + """`describe --format json` emits structured error when version cannot be resolved.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_client = MagicMock() + fake_client.applications.versions.documents.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "describe", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--format", + "json", + ], + ) + + assert result.exit_code == 2 + payload = json.loads(result.stderr) + assert payload["error"] == DOCUMENT_ERROR_CODE_NOT_FOUND + assert "heta" in payload["message"] + + +@pytest.mark.unit +def test_cli_application_version_document_describe_not_found_json(runner: CliRunner, record_property) -> None: + """`describe --format json` emits structured error when the document is missing.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_documents = MagicMock() + fake_documents.details.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "describe", + "heta", + DOCUMENT_MISSING_PDF, + "--format", + "json", + ], + ) + + assert result.exit_code == 2 + payload = json.loads(result.stderr) + assert payload["error"] == DOCUMENT_ERROR_CODE_NOT_FOUND + assert DOCUMENT_MISSING_PDF in payload["message"] + + +@pytest.mark.unit +def test_cli_application_version_document_describe_failed_text(runner: CliRunner, record_property) -> None: + """`describe` exits 1 with an error message on an unexpected failure (text format).""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + fake_documents = MagicMock() + fake_documents.details.side_effect = RuntimeError(DOCUMENT_TEST_FAILURE_MESSAGE) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + ["application", "version", "document", "describe", "heta", DOCUMENT_OUTPUT_DESCRIPTION_PDF], + ) + + assert result.exit_code == 1 + output = normalize_output(result.output) + assert "Failed to describe release document" in output + assert DOCUMENT_TEST_FAILURE_MESSAGE in output + + +@pytest.mark.unit +def test_cli_application_version_document_describe_failed_json(runner: CliRunner, record_property) -> None: + """`describe --format json` emits structured error on an unexpected failure.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-03") + fake_documents = MagicMock() + fake_documents.details.side_effect = RuntimeError(DOCUMENT_TEST_FAILURE_MESSAGE) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "describe", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--format", + "json", + ], + ) + + assert result.exit_code == 1 + payload = json.loads(result.stderr) + assert payload["error"] == DOCUMENT_ERROR_CODE_FAILED + assert DOCUMENT_TEST_FAILURE_MESSAGE in payload["message"] + + +@pytest.mark.unit +def test_cli_application_version_document_download_resolve_not_found( + runner: CliRunner, tmp_path: Path, record_property +) -> None: + """`download` exits 2 when the application version cannot be resolved.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-04") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_client = MagicMock() + fake_client.applications.versions.documents.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "download", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--output", + str(tmp_path), + ], + ) + + assert result.exit_code == 2 + output = normalize_output(result.output) + assert "Application version 'heta' is unavailable." in output + + +@pytest.mark.unit +def test_cli_application_version_document_download_not_found( + runner: CliRunner, tmp_path: Path, record_property +) -> None: + """`download` exits 2 with a clear message when the document does not exist.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-04") + from aignx.codegen.exceptions import NotFoundException as ApiNotFound + + fake_documents = MagicMock() + fake_documents.download_to_path.side_effect = ApiNotFound(status=404, reason=API_REASON_NOT_FOUND) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "download", + "heta", + DOCUMENT_MISSING_PDF, + "--output", + str(tmp_path), + ], + ) + + assert result.exit_code == 2 + output = normalize_output(result.output) + assert f"Document '{DOCUMENT_MISSING_PDF}' not found for application version 'heta'." in output + + +@pytest.mark.unit +def test_cli_application_version_document_download_failed(runner: CliRunner, tmp_path: Path, record_property) -> None: + """`download` exits 1 with an error message on an unexpected failure.""" + record_property("tested-item-id", "TC-APPLICATION-CLI-05-04") + fake_documents = MagicMock() + fake_documents.download_to_path.side_effect = RuntimeError(DOCUMENT_TEST_FAILURE_MESSAGE) + fake_client = MagicMock() + fake_client.applications.versions.documents.return_value = fake_documents + + with patch(APPLICATION_CLI_CLIENT_PATCH_TARGET, return_value=fake_client): + result = runner.invoke( + cli, + [ + "application", + "version", + "document", + "download", + "heta", + DOCUMENT_OUTPUT_DESCRIPTION_PDF, + "--output", + str(tmp_path), + ], + ) + + assert result.exit_code == 1 + output = normalize_output(result.output) + assert "Failed to download release document" in output + assert DOCUMENT_TEST_FAILURE_MESSAGE in output diff --git a/tests/aignostics/application/utils_test.py b/tests/aignostics/application/utils_test.py index 049b73d31..1b30a006c 100644 --- a/tests/aignostics/application/utils_test.py +++ b/tests/aignostics/application/utils_test.py @@ -138,6 +138,7 @@ def _make_item_result( # noqa: PLR0913 custom_metadata: dict[str, Any] | None = None, custom_metadata_checksum: str | None = None, terminated_at: datetime | None = None, + input_artifacts: list[Any] | None = None, output_artifacts: list[OutputArtifactElement] | None = None, ) -> ItemResult: return ItemResult( @@ -151,6 +152,7 @@ def _make_item_result( # noqa: PLR0913 custom_metadata=custom_metadata, custom_metadata_checksum=custom_metadata_checksum, terminated_at=terminated_at, + input_artifacts=input_artifacts if input_artifacts is not None else [], output_artifacts=output_artifacts if output_artifacts is not None else [], ) diff --git a/tests/aignostics/platform/resources/applications_test.py b/tests/aignostics/platform/resources/applications_test.py index 2cf1ab60c..6c7f31434 100644 --- a/tests/aignostics/platform/resources/applications_test.py +++ b/tests/aignostics/platform/resources/applications_test.py @@ -1,19 +1,38 @@ """Tests for the applications resource module. -This module contains unit tests for the Applications and Versions classes, -verifying their functionality for listing applications and application versions. +This module contains unit tests for the Applications, Versions, and Documents +classes, verifying their functionality for listing applications, application +versions, and application version release documents. """ -from unittest.mock import Mock +from datetime import UTC, datetime +from http import HTTPStatus +from pathlib import Path +from unittest.mock import MagicMock, Mock, patch import pytest from aignx.codegen.api.public_api import PublicApi +from aignx.codegen.exceptions import NotFoundException from aignx.codegen.models.application_read_response import ApplicationReadResponse - -from aignostics.platform.resources.applications import Applications, Versions +from aignx.codegen.models.version_document_response import VersionDocumentResponse +from aignx.codegen.models.version_document_visibility import VersionDocumentVisibility + +from aignostics.platform._operation_cache import operation_cache_clear +from aignostics.platform.resources.applications import ( + Applications, + ApplicationVersionDocument, + Documents, + Versions, +) from aignostics.platform.resources.utils import PAGE_SIZE API_ERROR = "API error" +API_REASON_NOT_FOUND = "Not Found" + +DOCUMENT_OUTPUT_DESCRIPTION_PDF = "output_description.pdf" +DOCUMENT_MISSING_PDF = "missing.pdf" +DOC_FILENAME_A = "a.pdf" +REQUESTS_GET_PATCH_TARGET = "aignostics.platform.resources.applications.requests.get" @pytest.fixture @@ -162,3 +181,242 @@ def test_versions_property_returns_versions_instance(applications) -> None: # Assert assert isinstance(versions, Versions) assert versions._api == applications._api + + +# ---------------------------------------------------------------------------------- +# Documents resource tests +# ---------------------------------------------------------------------------------- + + +def _make_doc(name: str = DOCUMENT_OUTPUT_DESCRIPTION_PDF) -> VersionDocumentResponse: + """Build a VersionDocumentResponse codegen model for tests.""" + return VersionDocumentResponse( + id="11111111-1111-1111-1111-111111111111", + name=name, + mime_type="application/pdf", + visibility=VersionDocumentVisibility.PUBLIC, + created_at=datetime(2026, 1, 1, 12, 0, tzinfo=UTC), + updated_at=datetime(2026, 1, 2, 12, 0, tzinfo=UTC), + ) + + +@pytest.fixture(autouse=True) +def _clear_operation_cache_before_each_test() -> None: + """Ensure the global operation cache does not leak between tests.""" + operation_cache_clear() + + +@pytest.fixture +def documents(mock_api: Mock) -> Documents: + """Create a Documents instance bound to a fixed (application, version) pair. + + The mock is augmented with a minimal ``api_client.configuration`` so + ``download_to_path`` can read host/proxy/SSL settings without hitting the + real codegen plumbing. + """ + configuration = MagicMock() + configuration.host = "https://platform.example.com" + configuration.proxy = None + configuration.ssl_ca_cert = None + configuration.verify_ssl = True + configuration.token_provider = lambda: "test-token" + mock_api.api_client = MagicMock() + mock_api.api_client.configuration = configuration + return Documents(mock_api, application_id="heta", application_version="1.0.0") + + +@pytest.mark.unit +def test_documents_list_returns_wrapped_models(documents: Documents, mock_api: Mock) -> None: + """Documents.list() returns ApplicationVersionDocument instances.""" + mock_api.list_version_documents.return_value = [ + _make_doc(DOC_FILENAME_A), + _make_doc("b.pdf"), + ] + + result = documents.list() + + assert len(result) == 2 + assert all(isinstance(item, ApplicationVersionDocument) for item in result) + assert {d.name for d in result} == {DOC_FILENAME_A, "b.pdf"} + mock_api.list_version_documents.assert_called_once() + call_kwargs = mock_api.list_version_documents.call_args.kwargs + assert call_kwargs["application_id"] == "heta" + assert call_kwargs["version"] == "1.0.0" + + +@pytest.mark.unit +def test_documents_list_returns_empty_list(documents: Documents, mock_api: Mock) -> None: + """Documents.list() handles an empty response.""" + mock_api.list_version_documents.return_value = [] + + result = documents.list() + + assert result == [] + + +@pytest.mark.unit +def test_documents_list_uses_cache_then_bypasses_with_nocache(documents: Documents, mock_api: Mock) -> None: + """list() caches results across calls; nocache=True forces a fresh call.""" + mock_api.list_version_documents.return_value = [_make_doc(DOC_FILENAME_A)] + + # First call hits the API and caches. + documents.list() + # Second call returns cached value. + documents.list() + assert mock_api.list_version_documents.call_count == 1 + + # nocache=True bypasses the cache and re-fetches. + documents.list(nocache=True) + assert mock_api.list_version_documents.call_count == 2 + + +@pytest.mark.unit +def test_documents_details_returns_wrapped_model(documents: Documents, mock_api: Mock) -> None: + """Documents.details() wraps the response in ApplicationVersionDocument.""" + mock_api.get_version_document.return_value = _make_doc(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + + result = documents.details(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + + assert isinstance(result, ApplicationVersionDocument) + assert result.name == DOCUMENT_OUTPUT_DESCRIPTION_PDF + assert result.mime_type == "application/pdf" + call_kwargs = mock_api.get_version_document.call_args.kwargs + assert call_kwargs["application_id"] == "heta" + assert call_kwargs["version"] == "1.0.0" + assert call_kwargs["name"] == DOCUMENT_OUTPUT_DESCRIPTION_PDF + + +@pytest.mark.unit +def test_documents_details_propagates_not_found(documents: Documents, mock_api: Mock) -> None: + """Documents.details() propagates a 404 NotFoundException from the codegen client.""" + mock_api.get_version_document.side_effect = NotFoundException(status=404, reason=API_REASON_NOT_FOUND) + + with pytest.raises(NotFoundException): + documents.details(DOCUMENT_MISSING_PDF) + + +@pytest.mark.unit +def test_documents_download_to_path_writes_file(documents: Documents, tmp_path: Path) -> None: + """download_to_path() follows the platform redirect and streams the body to disk.""" + body_response = MagicMock() + body_response.status_code = HTTPStatus.OK + body_response.iter_content.return_value = [b"hello ", b"world"] + body_response.raise_for_status = MagicMock() + body_response.__enter__.return_value = body_response + body_response.__exit__.return_value = False + + with patch( + REQUESTS_GET_PATCH_TARGET, + return_value=body_response, + ) as mock_get: + result = documents.download_to_path(DOCUMENT_OUTPUT_DESCRIPTION_PDF, tmp_path) + + assert result == (tmp_path / DOCUMENT_OUTPUT_DESCRIPTION_PDF).resolve() + assert result.read_bytes() == b"hello world" + # Single request to the platform endpoint, requests follows the 307 internally. + mock_get.assert_called_once() + called_url = mock_get.call_args.args[0] + assert called_url.endswith( + f"/api/v1/applications/heta/versions/1.0.0/documents/{DOCUMENT_OUTPUT_DESCRIPTION_PDF}/file" + ) + assert mock_get.call_args.kwargs["allow_redirects"] is True + + +@pytest.mark.unit +def test_documents_download_to_path_404_raises_not_found(documents: Documents, tmp_path: Path) -> None: + """A 404 from the documents endpoint is mapped to NotFoundException.""" + response = MagicMock() + response.status_code = HTTPStatus.NOT_FOUND + response.reason = API_REASON_NOT_FOUND + response.__enter__.return_value = response + response.__exit__.return_value = False + + with ( + patch(REQUESTS_GET_PATCH_TARGET, return_value=response), + pytest.raises(NotFoundException), + ): + documents.download_to_path(DOCUMENT_MISSING_PDF, tmp_path) + + +@pytest.mark.unit +def test_documents_download_to_path_rejects_non_directory(documents: Documents, tmp_path: Path) -> None: + """download_to_path() raises ValueError when destination is not an existing directory.""" + file_path = tmp_path / "some_file.pdf" + file_path.write_bytes(b"content") + + with pytest.raises(ValueError, match="must be a directory"): + documents.download_to_path(DOCUMENT_OUTPUT_DESCRIPTION_PDF, file_path) + + +@pytest.mark.unit +def test_documents_read_content_returns_bytes(documents: Documents) -> None: + """read_content() follows the /content redirect and returns the body as bytes.""" + body_response = MagicMock() + body_response.status_code = HTTPStatus.OK + body_response.iter_content.return_value = [b"hello ", b"world"] + body_response.raise_for_status = MagicMock() + body_response.__enter__.return_value = body_response + body_response.__exit__.return_value = False + + with patch( + REQUESTS_GET_PATCH_TARGET, + return_value=body_response, + ) as mock_get: + result = documents.read_content(DOCUMENT_OUTPUT_DESCRIPTION_PDF) + + assert result == b"hello world" + mock_get.assert_called_once() + called_url = mock_get.call_args.args[0] + assert called_url.endswith( + f"/api/v1/applications/heta/versions/1.0.0/documents/{DOCUMENT_OUTPUT_DESCRIPTION_PDF}/content" + ) + assert mock_get.call_args.kwargs["allow_redirects"] is True + + +@pytest.mark.unit +def test_documents_read_content_404_raises_not_found(documents: Documents) -> None: + """A 404 from the /content endpoint is mapped to NotFoundException.""" + response = MagicMock() + response.status_code = HTTPStatus.NOT_FOUND + response.reason = API_REASON_NOT_FOUND + response.__enter__.return_value = response + response.__exit__.return_value = False + + with ( + patch(REQUESTS_GET_PATCH_TARGET, return_value=response), + pytest.raises(NotFoundException), + ): + documents.read_content(DOCUMENT_MISSING_PDF) + + +@pytest.mark.unit +def test_versions_documents_returns_documents_resource(mock_api: Mock) -> None: + """Versions.documents() returns a Documents instance bound to the version pair.""" + versions = Versions(mock_api) + + docs = versions.documents("heta", "1.0.0") + + assert isinstance(docs, Documents) + assert docs.application_id == "heta" + assert docs.application_version == "1.0.0" + assert docs._api is mock_api + + +@pytest.mark.unit +def test_versions_documents_resolves_none_to_latest(mock_api: Mock) -> None: + """Versions.documents(None) resolves to the latest version number.""" + from unittest.mock import patch + + from aignostics.platform.resources.applications import Versions as _Versions + from aignostics.platform.resources.applications import VersionTuple + + latest = Mock(spec=VersionTuple) + latest.number = "2.3.1" + + versions = _Versions(mock_api) + with patch.object(versions, "latest", return_value=latest): + docs = versions.documents("heta", None) + + assert isinstance(docs, Documents) + assert docs.application_id == "heta" + assert docs.application_version == "2.3.1"