uipath 2.0.63__tar.gz → 2.0.64__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of uipath might be problematic. Click here for more details.
- {uipath-2.0.63 → uipath-2.0.64}/PKG-INFO +1 -1
- {uipath-2.0.63 → uipath-2.0.64}/pyproject.toml +1 -1
- uipath-2.0.64/src/uipath/_cli/_runtime/_escalation.py +235 -0
- uipath-2.0.64/src/uipath/_cli/_runtime/_hitl.py +194 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_common.py +26 -0
- uipath-2.0.64/src/uipath/_cli/_utils/_tracing.py +52 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/jobs_service.py +53 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/tracing/_traced.py +66 -6
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/conftest.py +3 -1
- uipath-2.0.64/tests/cli/test_hitl.py +314 -0
- uipath-2.0.64/tests/cli/test_utils.py +119 -0
- {uipath-2.0.63 → uipath-2.0.64}/uv.lock +1 -1
- {uipath-2.0.63 → uipath-2.0.64}/.cursorrules +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.editorconfig +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.gitattributes +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/cd.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/ci.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/commitlint.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/lint.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/publish-dev.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/publish-docs.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/slack.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.github/workflows/test.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.gitignore +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.pre-commit-config.yaml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.python-version +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.vscode/extensions.json +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/.vscode/settings.json +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/CONTRIBUTING.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/LICENSE +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/README.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/CONTRIBUTING.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/FAQ.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/assets/env-preparation-failed-dark.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/assets/env-preparation-failed-light.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/assets/favicon.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/assets/logo-dark.svg +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/assets/logo-light.svg +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/cli/index.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/actions.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/cloud_env_var_dark.gif +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/cloud_env_var_light.gif +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/cloud_env_var_secret_dark.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/cloud_env_var_secret_light.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/copy_path_dark.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets/copy_path_light.png +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/assets.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/attachments.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/buckets.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/connections.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/context_grounding.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/environment_variables.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/getting_started.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/jobs.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/processes.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/queues.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/core/traced.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/hooks.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/javascripts/extra.js +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/langchain/chat_models.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/langchain/context_grounding.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/langchain/human_in_the_loop.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/overrides/main.html +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/overrides/partials/actions.html +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/overrides/partials/logo.html +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/release_policy.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/docs/stylesheets/extra.css +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/justfile +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/mkdocs.yml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/py.typed +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/README.md +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/_auth_server.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/_models.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/_oidc_utils.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/_portal_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/_utils.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/auth_config.json +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/index.html +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/localhost.crt +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_auth/localhost.key +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_runtime/_contracts.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_runtime/_logging.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_runtime/_runtime.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_templates/.psmdcp.template +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_templates/.rels.template +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_templates/[Content_Types].xml.template +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_templates/main.py.template +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_templates/package.nuspec.template +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_console.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_constants.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_folders.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_input_args.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_parse_ast.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/_utils/_processes.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_auth.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_deploy.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_init.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_invoke.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_new.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_pack.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_publish.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/cli_run.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/middlewares.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_cli/spinner.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_config.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_execution_context.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_folder_context.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/_base_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/actions_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/api_client.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/assets_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/attachments_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/buckets_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/connections_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/context_grounding_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/folder_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/llm_gateway_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/processes_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_services/queues_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_uipath.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_endpoint.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_infer_bindings.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_logs.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_read_overwrites.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_request_override.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_request_spec.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_url.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/_user_agent.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/_utils/constants.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/action_schema.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/actions.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/assets.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/attachment.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/buckets.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/connections.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/context_grounding.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/context_grounding_index.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/errors.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/exceptions.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/interrupt_models.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/job.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/llm_gateway.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/processes.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/models/queues.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/py.typed +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/telemetry/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/telemetry/_constants.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/telemetry/_track.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/tracing/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/tracing/_otel_exporters.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/src/uipath/tracing/_utils.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/__init__.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/mocks/bindings_script.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/mocks/pyproject.toml +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/mocks/simple_script.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/mocks/uipath-mock.json +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/mocks/uipath-simple-script-mock.json +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_init.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_invoke.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_new.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_pack.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_publish.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/test_run.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/utils/project_details.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/cli/utils/uipath_json.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/conftest.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/conftest.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_actions_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_api_client.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_assets_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_attachments_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_base_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_buckets_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_connections_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_context_grounding_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_folder_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_jobs_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_llm_integration.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_llm_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_processes_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_queues_service.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/services/test_uipath_llm_integration.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/test_bindings_inference.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/test_config.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/sdk/test_overwrites.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/tracing/test_otel_exporters.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/tracing/test_span_utils.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/tracing/test_traced.py +0 -0
- {uipath-2.0.63 → uipath-2.0.64}/tests/tracing/test_tracing_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uipath
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.64
|
|
4
4
|
Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
|
|
5
5
|
Project-URL: Homepage, https://uipath.com
|
|
6
6
|
Project-URL: Repository, https://github.com/UiPath/uipath-python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "uipath"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.64"
|
|
4
4
|
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
|
|
5
5
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, Optional, Union
|
|
5
|
+
|
|
6
|
+
from uipath import UiPath
|
|
7
|
+
from uipath.models.actions import Action
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Escalation:
|
|
13
|
+
"""Class to handle default escalation."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, config_path: Union[str, Path] = "uipath.json"):
|
|
16
|
+
"""Initialize the escalation with a config file path.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
config_path: Path to the configuration file (string or Path object)
|
|
20
|
+
"""
|
|
21
|
+
self.config_path = Path(config_path)
|
|
22
|
+
self._config = None
|
|
23
|
+
self._enabled = False
|
|
24
|
+
self._load_config()
|
|
25
|
+
|
|
26
|
+
def _load_config(self) -> None:
|
|
27
|
+
"""Load and validate the default escalation from the config file.
|
|
28
|
+
|
|
29
|
+
If the 'defaultEscalation' section exists, validates required fields.
|
|
30
|
+
Raises error if required fields are missing.
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
config_data = json.loads(self.config_path.read_text(encoding="utf-8"))
|
|
34
|
+
escalation_config = config_data.get("defaultEscalation")
|
|
35
|
+
|
|
36
|
+
if escalation_config:
|
|
37
|
+
required_fields = {"request", "title"}
|
|
38
|
+
missing_fields = [
|
|
39
|
+
field for field in required_fields if field not in escalation_config
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
if not any(key in escalation_config for key in ("appName", "appKey")):
|
|
43
|
+
missing_fields.append("appName or appKey")
|
|
44
|
+
|
|
45
|
+
if missing_fields:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f"Missing required fields in configuration: {', '.join(missing_fields)}"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self._config = escalation_config
|
|
51
|
+
self._enabled = True
|
|
52
|
+
logger.debug("Escalation configuration loaded successfully")
|
|
53
|
+
else:
|
|
54
|
+
self._enabled = False
|
|
55
|
+
|
|
56
|
+
except FileNotFoundError:
|
|
57
|
+
logger.debug(f"Config file not found: {self.config_path}")
|
|
58
|
+
self._enabled = False
|
|
59
|
+
|
|
60
|
+
except json.JSONDecodeError:
|
|
61
|
+
logger.warning(
|
|
62
|
+
f"Failed to parse config file {self.config_path}: Invalid JSON"
|
|
63
|
+
)
|
|
64
|
+
self._enabled = False
|
|
65
|
+
|
|
66
|
+
except ValueError as e:
|
|
67
|
+
logger.error(str(e))
|
|
68
|
+
raise
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Unexpected error loading config {self.config_path}: {e}")
|
|
72
|
+
self._enabled = False
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def enabled(self) -> bool:
|
|
76
|
+
"""Check if escalation is enabled.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
True if configuration is valid and loaded
|
|
80
|
+
"""
|
|
81
|
+
return self._enabled
|
|
82
|
+
|
|
83
|
+
def prepare_data(self, value: Any) -> Dict[str, Any]:
|
|
84
|
+
"""Prepare action data by replacing $VALUE placeholders with the provided value.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
value: The value to substitute into the template
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Prepared data dictionary with substitutions applied
|
|
91
|
+
"""
|
|
92
|
+
if not self.enabled or not self._config:
|
|
93
|
+
return {}
|
|
94
|
+
|
|
95
|
+
template = self._config.get("request", {})
|
|
96
|
+
|
|
97
|
+
if isinstance(value, str):
|
|
98
|
+
try:
|
|
99
|
+
value_obj = json.loads(value)
|
|
100
|
+
except json.JSONDecodeError:
|
|
101
|
+
value_obj = value
|
|
102
|
+
else:
|
|
103
|
+
value_obj = value
|
|
104
|
+
|
|
105
|
+
return self._substitute_values(template, value_obj)
|
|
106
|
+
|
|
107
|
+
def _substitute_values(
|
|
108
|
+
self, template: Dict[str, Any], value: Any
|
|
109
|
+
) -> Dict[str, Any]:
|
|
110
|
+
"""Replace template placeholders with actual values.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
template: Template dictionary containing placeholders
|
|
114
|
+
value: Values to substitute into the template
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Template with values substituted
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def process_value(template_value):
|
|
121
|
+
if isinstance(template_value, dict):
|
|
122
|
+
return {k: process_value(v) for k, v in template_value.items()}
|
|
123
|
+
elif isinstance(template_value, list):
|
|
124
|
+
return [process_value(item) for item in template_value]
|
|
125
|
+
elif isinstance(template_value, str):
|
|
126
|
+
if template_value == "$VALUE":
|
|
127
|
+
return value
|
|
128
|
+
elif template_value.startswith("$VALUE."):
|
|
129
|
+
return self._resolve_value_path(template_value, value)
|
|
130
|
+
|
|
131
|
+
return template_value
|
|
132
|
+
|
|
133
|
+
return process_value(template)
|
|
134
|
+
|
|
135
|
+
def _resolve_value_path(self, path_expr: str, value: Any) -> Any:
|
|
136
|
+
"""Resolve a dot-notation path expression against a value.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
path_expr: Path expression (e.g. "$VALUE.user.name")
|
|
140
|
+
value: Value object to extract data from
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Extracted value or None if path doesn't exist
|
|
144
|
+
"""
|
|
145
|
+
path_parts = path_expr.replace("$VALUE.", "").split(".")
|
|
146
|
+
current = value
|
|
147
|
+
|
|
148
|
+
for part in path_parts:
|
|
149
|
+
if not isinstance(current, dict) or part not in current:
|
|
150
|
+
return None
|
|
151
|
+
current = current.get(part)
|
|
152
|
+
|
|
153
|
+
return current
|
|
154
|
+
|
|
155
|
+
def extract_response_value(self, action_data: Dict[str, Any]) -> Any:
|
|
156
|
+
if not self._config:
|
|
157
|
+
return ""
|
|
158
|
+
|
|
159
|
+
response_template = self._config.get("response")
|
|
160
|
+
if not response_template:
|
|
161
|
+
return ""
|
|
162
|
+
|
|
163
|
+
for key, template_value in response_template.items():
|
|
164
|
+
if key in action_data:
|
|
165
|
+
extracted_value = None
|
|
166
|
+
|
|
167
|
+
if template_value == "$VALUE":
|
|
168
|
+
extracted_value = action_data[key]
|
|
169
|
+
elif isinstance(template_value, str) and template_value.startswith(
|
|
170
|
+
"$VALUE."
|
|
171
|
+
):
|
|
172
|
+
path_parts = template_value.replace("$VALUE.", "").split(".")
|
|
173
|
+
current = action_data[key]
|
|
174
|
+
|
|
175
|
+
valid_path = True
|
|
176
|
+
for part in path_parts:
|
|
177
|
+
if not isinstance(current, dict) or part not in current:
|
|
178
|
+
valid_path = False
|
|
179
|
+
break
|
|
180
|
+
current = current.get(part)
|
|
181
|
+
|
|
182
|
+
if valid_path:
|
|
183
|
+
extracted_value = current
|
|
184
|
+
|
|
185
|
+
if extracted_value is not None:
|
|
186
|
+
if isinstance(extracted_value, str):
|
|
187
|
+
if extracted_value.lower() == "true":
|
|
188
|
+
return True
|
|
189
|
+
elif extracted_value.lower() == "false":
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
if "." in extracted_value:
|
|
194
|
+
return float(extracted_value)
|
|
195
|
+
else:
|
|
196
|
+
return int(extracted_value)
|
|
197
|
+
except ValueError:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
return extracted_value
|
|
201
|
+
|
|
202
|
+
return action_data
|
|
203
|
+
|
|
204
|
+
async def create(self, value: Any) -> Optional[Action]:
|
|
205
|
+
"""Create an escalation Action with the prepared data.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
value: The dynamic value to be substituted into the template
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
The created Action object or None if creation fails
|
|
212
|
+
"""
|
|
213
|
+
if not self.enabled or not self._config:
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
action_data = self.prepare_data(value)
|
|
217
|
+
|
|
218
|
+
if not action_data:
|
|
219
|
+
logger.warning("Action creation skipped: empty data after preparation")
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
uipath = UiPath()
|
|
224
|
+
action = uipath.actions.create(
|
|
225
|
+
title=self._config.get("title", "Default escalation"),
|
|
226
|
+
app_name=self._config.get("appName"),
|
|
227
|
+
app_key=self._config.get("appKey"),
|
|
228
|
+
app_version=self._config.get("appVersion", 1),
|
|
229
|
+
data=action_data,
|
|
230
|
+
)
|
|
231
|
+
logger.info(f"Action created successfully: {action.key}")
|
|
232
|
+
return action
|
|
233
|
+
except Exception as e:
|
|
234
|
+
logger.error(f"Error creating action: {e}")
|
|
235
|
+
return None
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import uuid
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from functools import cached_property
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from uipath import UiPath
|
|
8
|
+
from uipath.models import CreateAction, InvokeProcess, WaitAction, WaitJob
|
|
9
|
+
|
|
10
|
+
from .._runtime._contracts import (
|
|
11
|
+
UiPathApiTrigger,
|
|
12
|
+
UiPathErrorCategory,
|
|
13
|
+
UiPathResumeTrigger,
|
|
14
|
+
UiPathResumeTriggerType,
|
|
15
|
+
UiPathRuntimeError,
|
|
16
|
+
UiPathRuntimeStatus,
|
|
17
|
+
)
|
|
18
|
+
from .._utils._common import serialize_object
|
|
19
|
+
from ._escalation import Escalation
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _try_convert_to_json_format(value: str) -> str:
|
|
23
|
+
try:
|
|
24
|
+
return json.loads(value)
|
|
25
|
+
except json.decoder.JSONDecodeError:
|
|
26
|
+
return value
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
default_escalation = Escalation()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class HitlReader:
|
|
33
|
+
@classmethod
|
|
34
|
+
async def read(cls, resume_trigger: UiPathResumeTrigger) -> Optional[str]:
|
|
35
|
+
uipath = UiPath()
|
|
36
|
+
match resume_trigger.trigger_type:
|
|
37
|
+
case UiPathResumeTriggerType.ACTION:
|
|
38
|
+
if resume_trigger.item_key:
|
|
39
|
+
action = await uipath.actions.retrieve_async(
|
|
40
|
+
resume_trigger.item_key,
|
|
41
|
+
app_folder_key=resume_trigger.folder_key,
|
|
42
|
+
app_folder_path=resume_trigger.folder_path,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
if default_escalation.enabled:
|
|
46
|
+
return default_escalation.extract_response_value(action.data)
|
|
47
|
+
|
|
48
|
+
return action.data
|
|
49
|
+
|
|
50
|
+
case UiPathResumeTriggerType.JOB:
|
|
51
|
+
if resume_trigger.item_key:
|
|
52
|
+
job = await uipath.jobs.retrieve_async(
|
|
53
|
+
resume_trigger.item_key,
|
|
54
|
+
folder_key=resume_trigger.folder_key,
|
|
55
|
+
folder_path=resume_trigger.folder_path,
|
|
56
|
+
)
|
|
57
|
+
if (
|
|
58
|
+
job.state
|
|
59
|
+
and not job.state.lower()
|
|
60
|
+
== UiPathRuntimeStatus.SUCCESSFUL.value.lower()
|
|
61
|
+
):
|
|
62
|
+
raise UiPathRuntimeError(
|
|
63
|
+
"INVOKED_PROCESS_FAILURE",
|
|
64
|
+
"Invoked process did not finish successfully.",
|
|
65
|
+
_try_convert_to_json_format(str(job.job_error or job.info)),
|
|
66
|
+
)
|
|
67
|
+
return job.output_arguments
|
|
68
|
+
|
|
69
|
+
case UiPathResumeTriggerType.API:
|
|
70
|
+
if resume_trigger.api_resume and resume_trigger.api_resume.inbox_id:
|
|
71
|
+
try:
|
|
72
|
+
return await uipath.jobs.retrieve_api_payload_async(
|
|
73
|
+
resume_trigger.api_resume.inbox_id
|
|
74
|
+
)
|
|
75
|
+
except Exception as e:
|
|
76
|
+
raise UiPathRuntimeError(
|
|
77
|
+
"API_CONNECTION_ERROR",
|
|
78
|
+
"Failed to get trigger payload",
|
|
79
|
+
f"Error fetching API trigger payload for inbox {resume_trigger.api_resume.inbox_id}: {str(e)}",
|
|
80
|
+
UiPathErrorCategory.SYSTEM,
|
|
81
|
+
) from e
|
|
82
|
+
case _:
|
|
83
|
+
raise UiPathRuntimeError(
|
|
84
|
+
"UNKNOWN_TRIGGER_TYPE",
|
|
85
|
+
"Unexpected trigger type received",
|
|
86
|
+
f"Trigger type :{type(resume_trigger.trigger_type)} is invalid",
|
|
87
|
+
UiPathErrorCategory.USER,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
raise UiPathRuntimeError(
|
|
91
|
+
"HITL_FEEDBACK_FAILURE",
|
|
92
|
+
"Failed to receive payload from HITL action",
|
|
93
|
+
detail="Failed to receive payload from HITL action",
|
|
94
|
+
category=UiPathErrorCategory.SYSTEM,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class HitlProcessor:
|
|
100
|
+
"""Processes events in a Human-(Robot/Agent)-In-The-Loop scenario."""
|
|
101
|
+
|
|
102
|
+
value: Any
|
|
103
|
+
|
|
104
|
+
@cached_property
|
|
105
|
+
def type(self) -> UiPathResumeTriggerType:
|
|
106
|
+
"""Returns the type of the interrupt value."""
|
|
107
|
+
if isinstance(self.value, CreateAction) or isinstance(self.value, WaitAction):
|
|
108
|
+
return UiPathResumeTriggerType.ACTION
|
|
109
|
+
if isinstance(self.value, InvokeProcess) or isinstance(self.value, WaitJob):
|
|
110
|
+
return UiPathResumeTriggerType.JOB
|
|
111
|
+
# default to API trigger
|
|
112
|
+
return UiPathResumeTriggerType.API
|
|
113
|
+
|
|
114
|
+
async def create_resume_trigger(self) -> UiPathResumeTrigger:
|
|
115
|
+
"""Returns the resume trigger."""
|
|
116
|
+
uipath = UiPath()
|
|
117
|
+
try:
|
|
118
|
+
hitl_input = self.value
|
|
119
|
+
resume_trigger = UiPathResumeTrigger(
|
|
120
|
+
trigger_type=self.type, payload=serialize_object(hitl_input)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# check for default escalation config
|
|
124
|
+
if default_escalation.enabled and isinstance(hitl_input, str):
|
|
125
|
+
resume_trigger.trigger_type = UiPathResumeTriggerType.ACTION
|
|
126
|
+
action = await default_escalation.create(hitl_input)
|
|
127
|
+
if not action:
|
|
128
|
+
raise Exception("Failed to create default escalation")
|
|
129
|
+
resume_trigger.item_key = action.key
|
|
130
|
+
return resume_trigger
|
|
131
|
+
|
|
132
|
+
match self.type:
|
|
133
|
+
case UiPathResumeTriggerType.ACTION:
|
|
134
|
+
resume_trigger.folder_path = hitl_input.app_folder_path
|
|
135
|
+
resume_trigger.folder_key = hitl_input.app_folder_key
|
|
136
|
+
if isinstance(hitl_input, WaitAction):
|
|
137
|
+
resume_trigger.item_key = hitl_input.action.key
|
|
138
|
+
elif isinstance(hitl_input, CreateAction):
|
|
139
|
+
action = await uipath.actions.create_async(
|
|
140
|
+
title=hitl_input.title,
|
|
141
|
+
app_name=hitl_input.app_name if hitl_input.app_name else "",
|
|
142
|
+
app_folder_path=hitl_input.app_folder_path
|
|
143
|
+
if hitl_input.app_folder_path
|
|
144
|
+
else "",
|
|
145
|
+
app_folder_key=hitl_input.app_folder_key
|
|
146
|
+
if hitl_input.app_folder_key
|
|
147
|
+
else "",
|
|
148
|
+
app_key=hitl_input.app_key if hitl_input.app_key else "",
|
|
149
|
+
app_version=hitl_input.app_version
|
|
150
|
+
if hitl_input.app_version
|
|
151
|
+
else 1,
|
|
152
|
+
assignee=hitl_input.assignee if hitl_input.assignee else "",
|
|
153
|
+
data=hitl_input.data,
|
|
154
|
+
)
|
|
155
|
+
if not action:
|
|
156
|
+
raise Exception("Failed to create action")
|
|
157
|
+
resume_trigger.item_key = action.key
|
|
158
|
+
|
|
159
|
+
case UiPathResumeTriggerType.JOB:
|
|
160
|
+
resume_trigger.folder_path = hitl_input.process_folder_path
|
|
161
|
+
resume_trigger.folder_key = hitl_input.process_folder_key
|
|
162
|
+
if isinstance(hitl_input, WaitJob):
|
|
163
|
+
resume_trigger.item_key = hitl_input.job.key
|
|
164
|
+
elif isinstance(hitl_input, InvokeProcess):
|
|
165
|
+
job = await uipath.processes.invoke_async(
|
|
166
|
+
name=hitl_input.name,
|
|
167
|
+
input_arguments=hitl_input.input_arguments,
|
|
168
|
+
folder_path=hitl_input.process_folder_path,
|
|
169
|
+
folder_key=hitl_input.process_folder_key,
|
|
170
|
+
)
|
|
171
|
+
if not job:
|
|
172
|
+
raise Exception("Failed to invoke process")
|
|
173
|
+
resume_trigger.item_key = job.key
|
|
174
|
+
|
|
175
|
+
case UiPathResumeTriggerType.API:
|
|
176
|
+
resume_trigger.api_resume = UiPathApiTrigger(
|
|
177
|
+
inbox_id=str(uuid.uuid4()), request=serialize_object(hitl_input)
|
|
178
|
+
)
|
|
179
|
+
case _:
|
|
180
|
+
raise UiPathRuntimeError(
|
|
181
|
+
"UNKNOWN_HITL_MODEL",
|
|
182
|
+
"Unexpected model received",
|
|
183
|
+
f"{type(hitl_input)} is not a valid Human(Robot/Agent)-In-The-Loop model",
|
|
184
|
+
UiPathErrorCategory.USER,
|
|
185
|
+
)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
raise UiPathRuntimeError(
|
|
188
|
+
"HITL_ACTION_CREATION_FAILED",
|
|
189
|
+
"Failed to create HITL action",
|
|
190
|
+
f"{str(e)}",
|
|
191
|
+
UiPathErrorCategory.SYSTEM,
|
|
192
|
+
) from e
|
|
193
|
+
|
|
194
|
+
return resume_trigger
|
|
@@ -43,3 +43,29 @@ def get_env_vars(spinner: Optional[Spinner] = None) -> list[str | None]:
|
|
|
43
43
|
click.get_current_context().exit(1)
|
|
44
44
|
|
|
45
45
|
return [base_url, token]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def serialize_object(obj):
|
|
49
|
+
"""Recursively serializes an object and all its nested components."""
|
|
50
|
+
# Handle Pydantic models
|
|
51
|
+
if hasattr(obj, "model_dump"):
|
|
52
|
+
return serialize_object(obj.model_dump(by_alias=True))
|
|
53
|
+
elif hasattr(obj, "dict"):
|
|
54
|
+
return serialize_object(obj.dict())
|
|
55
|
+
elif hasattr(obj, "to_dict"):
|
|
56
|
+
return serialize_object(obj.to_dict())
|
|
57
|
+
# Handle dictionaries
|
|
58
|
+
elif isinstance(obj, dict):
|
|
59
|
+
return {k: serialize_object(v) for k, v in obj.items()}
|
|
60
|
+
# Handle lists
|
|
61
|
+
elif isinstance(obj, list):
|
|
62
|
+
return [serialize_object(item) for item in obj]
|
|
63
|
+
# Handle other iterable objects (convert to dict first)
|
|
64
|
+
elif hasattr(obj, "__iter__") and not isinstance(obj, (str, bytes)):
|
|
65
|
+
try:
|
|
66
|
+
return serialize_object(dict(obj))
|
|
67
|
+
except (TypeError, ValueError):
|
|
68
|
+
return obj
|
|
69
|
+
# Return primitive types as is
|
|
70
|
+
else:
|
|
71
|
+
return obj
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
from zoneinfo import ZoneInfo
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IgnoreSpecificUrl(logging.Filter):
|
|
7
|
+
def __init__(self, url_to_ignore):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.url_to_ignore = url_to_ignore
|
|
10
|
+
|
|
11
|
+
def filter(self, record):
|
|
12
|
+
try:
|
|
13
|
+
if record.msg == 'HTTP Request: %s %s "%s %d %s"':
|
|
14
|
+
# Ignore the log if the URL matches the one we want to ignore
|
|
15
|
+
method = record.args[0]
|
|
16
|
+
url = record.args[1]
|
|
17
|
+
|
|
18
|
+
if method == "POST" and url.path.endswith(self.url_to_ignore):
|
|
19
|
+
# Check if the URL contains the specific path we want to ignore
|
|
20
|
+
return True
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
except Exception:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def setup_tracer_httpx_logging(url: str):
|
|
28
|
+
# Create a custom logger for httpx
|
|
29
|
+
# Add the custom filter to the root logger
|
|
30
|
+
logging.getLogger("httpx").addFilter(IgnoreSpecificUrl(url))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def simple_serialize_defaults(obj):
|
|
34
|
+
if hasattr(obj, "model_dump"):
|
|
35
|
+
return obj.model_dump(exclude_none=True, mode="json")
|
|
36
|
+
if hasattr(obj, "dict"):
|
|
37
|
+
return obj.dict()
|
|
38
|
+
if hasattr(obj, "to_dict"):
|
|
39
|
+
return obj.to_dict()
|
|
40
|
+
|
|
41
|
+
if isinstance(obj, (set, tuple)):
|
|
42
|
+
if hasattr(obj, "_asdict") and callable(obj._asdict):
|
|
43
|
+
return obj._asdict()
|
|
44
|
+
return list(obj)
|
|
45
|
+
|
|
46
|
+
if isinstance(obj, datetime.datetime):
|
|
47
|
+
return obj.isoformat()
|
|
48
|
+
|
|
49
|
+
if isinstance(obj, (datetime.timezone, ZoneInfo)):
|
|
50
|
+
return obj.tzname(None)
|
|
51
|
+
|
|
52
|
+
return str(obj)
|
|
@@ -272,6 +272,59 @@ class JobsService(FolderContext, BaseService):
|
|
|
272
272
|
response = response.json()
|
|
273
273
|
return self._extract_first_inbox_id(response)
|
|
274
274
|
|
|
275
|
+
def retrieve_api_payload(self, inbox_id: str) -> Any:
|
|
276
|
+
"""Fetch payload data for API triggers.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
inbox_id: The Id of the inbox to fetch the payload for.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
The value field from the API response payload.
|
|
283
|
+
"""
|
|
284
|
+
spec = self._retrieve_api_payload_spec(inbox_id=inbox_id)
|
|
285
|
+
|
|
286
|
+
response = self.request(
|
|
287
|
+
spec.method,
|
|
288
|
+
url=spec.endpoint,
|
|
289
|
+
headers=spec.headers,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
data = response.json()
|
|
293
|
+
return data.get("payload")
|
|
294
|
+
|
|
295
|
+
async def retrieve_api_payload_async(self, inbox_id: str) -> Any:
|
|
296
|
+
"""Asynchronously fetch payload data for API triggers.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
inbox_id: The Id of the inbox to fetch the payload for.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
The value field from the API response payload.
|
|
303
|
+
"""
|
|
304
|
+
spec = self._retrieve_api_payload_spec(inbox_id=inbox_id)
|
|
305
|
+
|
|
306
|
+
response = await self.request_async(
|
|
307
|
+
spec.method,
|
|
308
|
+
url=spec.endpoint,
|
|
309
|
+
headers=spec.headers,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
data = response.json()
|
|
313
|
+
return data.get("payload")
|
|
314
|
+
|
|
315
|
+
def _retrieve_api_payload_spec(
|
|
316
|
+
self,
|
|
317
|
+
*,
|
|
318
|
+
inbox_id: str,
|
|
319
|
+
) -> RequestSpec:
|
|
320
|
+
return RequestSpec(
|
|
321
|
+
method="GET",
|
|
322
|
+
endpoint=Endpoint(f"/orchestrator_/api/JobTriggers/GetPayload/{inbox_id}"),
|
|
323
|
+
headers={
|
|
324
|
+
**self.folder_headers,
|
|
325
|
+
},
|
|
326
|
+
)
|
|
327
|
+
|
|
275
328
|
def _extract_first_inbox_id(self, response: Any) -> str:
|
|
276
329
|
if len(response["value"]) > 0:
|
|
277
330
|
return response["value"][0]["ItemKey"]
|