From 994b43ca7b2a9eefb887acb85fbe192925132470 Mon Sep 17 00:00:00 2001
From: "onepin-pipeline-bot[bot]"
<290953255+onepin-pipeline-bot[bot]@users.noreply.github.com>
Date: Thu, 16 Jul 2026 05:47:51 +0000
Subject: [PATCH] feat: sync SDK to OnePin API v0.41.83
---
.spec-sha | 2 +-
src/onepin/.fern/metadata.json | 2 +-
src/onepin/__init__.py | 15 +
src/onepin/dictionary/client.py | 12 +-
src/onepin/dictionary/raw_client.py | 12 +-
src/onepin/dictionary/types/__init__.py | 24 +-
..._api_v1dictionary_get_request_language.py} | 0
...ies_api_v1dictionary_get_request_order.py} | 0
...ries_api_v1dictionary_get_request_sort.py} | 0
...onary_search_get_request_language_item.py} | 0
..._v1dictionary_search_get_request_order.py} | 0
...i_v1dictionary_search_get_request_sort.py} | 0
src/onepin/reference.md | 367 ++++++++++++------
src/onepin/types/__init__.py | 15 +
.../types/workflow_run_data_card_out.py | 6 +
.../workflow_run_data_card_out_status.py | 7 +
.../types/workflow_run_data_dropped_out.py | 20 +
.../workflow_run_data_dropped_verdict_out.py | 32 ++
src/onepin/types/workflow_run_data_out.py | 1 +
.../types/workflow_run_data_rejected_out.py | 24 ++
...workflow_run_overview_metric_annotation.py | 24 ++
.../types/workflow_run_overview_metric_out.py | 2 +
src/onepin/types/workflow_run_step_out.py | 2 +
src/onepin/uploads/client.py | 4 +-
src/onepin/uploads/raw_client.py | 4 +-
.../upload_confirm_request_context_type.py | 4 +-
src/onepin/usage/client.py | 10 +-
src/onepin/usage/raw_client.py | 10 +-
src/onepin/usage/types/__init__.py | 20 +-
...api_v1usage_activity_get_request_range.py} | 0
..._by_language_get_request_activity_view.py} | 0
..._v1usage_by_language_get_request_range.py} | 0
...sage_summary_get_request_activity_view.py} | 0
..._api_v1usage_summary_get_request_range.py} | 0
src/onepin/users/client.py | 2 +-
src/onepin/users/raw_client.py | 2 +-
src/onepin/users/types/__init__.py | 4 +-
..._v1users_me_templates_get_request_sort.py} | 0
src/onepin/voices/client.py | 2 +-
src/onepin/voices/raw_client.py | 2 +-
src/onepin/voices/types/__init__.py | 4 +-
...1voices_facets_get_request_source_item.py} | 0
src/onepin/workflows/client.py | 267 ++++++-------
src/onepin/workflows/raw_client.py | 355 +++++++++--------
src/onepin/workflows/runs/client.py | 186 ++++++++-
src/onepin/workflows/runs/raw_client.py | 218 ++++++++++-
46 files changed, 1178 insertions(+), 483 deletions(-)
rename src/onepin/dictionary/types/{list_dictionary_entries_api_v1_dictionary_get_request_language.py => list_dictionary_entries_api_v1dictionary_get_request_language.py} (100%)
rename src/onepin/dictionary/types/{list_dictionary_entries_api_v1_dictionary_get_request_order.py => list_dictionary_entries_api_v1dictionary_get_request_order.py} (100%)
rename src/onepin/dictionary/types/{list_dictionary_entries_api_v1_dictionary_get_request_sort.py => list_dictionary_entries_api_v1dictionary_get_request_sort.py} (100%)
rename src/onepin/dictionary/types/{search_dictionary_entries_api_v1_dictionary_search_get_request_language_item.py => search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py} (100%)
rename src/onepin/dictionary/types/{search_dictionary_entries_api_v1_dictionary_search_get_request_order.py => search_dictionary_entries_api_v1dictionary_search_get_request_order.py} (100%)
rename src/onepin/dictionary/types/{search_dictionary_entries_api_v1_dictionary_search_get_request_sort.py => search_dictionary_entries_api_v1dictionary_search_get_request_sort.py} (100%)
create mode 100644 src/onepin/types/workflow_run_data_card_out_status.py
create mode 100644 src/onepin/types/workflow_run_data_dropped_out.py
create mode 100644 src/onepin/types/workflow_run_data_dropped_verdict_out.py
create mode 100644 src/onepin/types/workflow_run_data_rejected_out.py
create mode 100644 src/onepin/types/workflow_run_overview_metric_annotation.py
rename src/onepin/usage/types/{usage_activity_api_v1_usage_activity_get_request_range.py => usage_activity_api_v1usage_activity_get_request_range.py} (100%)
rename src/onepin/usage/types/{usage_by_language_api_v1_usage_by_language_get_request_activity_view.py => usage_by_language_api_v1usage_by_language_get_request_activity_view.py} (100%)
rename src/onepin/usage/types/{usage_by_language_api_v1_usage_by_language_get_request_range.py => usage_by_language_api_v1usage_by_language_get_request_range.py} (100%)
rename src/onepin/usage/types/{usage_summary_api_v1_usage_summary_get_request_activity_view.py => usage_summary_api_v1usage_summary_get_request_activity_view.py} (100%)
rename src/onepin/usage/types/{usage_summary_api_v1_usage_summary_get_request_range.py => usage_summary_api_v1usage_summary_get_request_range.py} (100%)
rename src/onepin/users/types/{list_my_templates_api_v1_users_me_templates_get_request_sort.py => list_my_templates_api_v1users_me_templates_get_request_sort.py} (100%)
rename src/onepin/voices/types/{get_voice_facets_api_v1_voices_facets_get_request_source_item.py => get_voice_facets_api_v1voices_facets_get_request_source_item.py} (100%)
diff --git a/.spec-sha b/.spec-sha
index eccd7b1..52ea54b 100644
--- a/.spec-sha
+++ b/.spec-sha
@@ -1 +1 @@
-cddf1ca71c61a62e9e429206b74a6d064222b4ed
+28bf2af12a8765adb95381c7160cfc5b5e4ddd12
diff --git a/src/onepin/.fern/metadata.json b/src/onepin/.fern/metadata.json
index 6e675c6..4ded201 100644
--- a/src/onepin/.fern/metadata.json
+++ b/src/onepin/.fern/metadata.json
@@ -30,7 +30,7 @@
}
]
},
- "originGitCommit": "a3ee57d10e66cc74651c81add046845159caf420",
+ "originGitCommit": "968747c21f0b427963288a82817fbe21a736230b",
"originGitCommitIsDirty": false,
"invokedBy": "ci",
"ciProvider": "github"
diff --git a/src/onepin/__init__.py b/src/onepin/__init__.py
index 939df16..3fa3327 100644
--- a/src/onepin/__init__.py
+++ b/src/onepin/__init__.py
@@ -156,10 +156,14 @@
WorkflowRunDataAudioOut,
WorkflowRunDataAudioOutStatus,
WorkflowRunDataCardOut,
+ WorkflowRunDataCardOutStatus,
WorkflowRunDataCardOutWaveformStatus,
+ WorkflowRunDataDroppedOut,
+ WorkflowRunDataDroppedVerdictOut,
WorkflowRunDataOut,
WorkflowRunDataPartialOut,
WorkflowRunDataPartialOutStatus,
+ WorkflowRunDataRejectedOut,
WorkflowRunDataResponse,
WorkflowRunDataRowOut,
WorkflowRunDataRowOutAutoCorrectedStatus,
@@ -175,6 +179,7 @@
WorkflowRunOverviewAudioLanguageOut,
WorkflowRunOverviewCapabilitiesOut,
WorkflowRunOverviewFutureLinksOut,
+ WorkflowRunOverviewMetricAnnotation,
WorkflowRunOverviewMetricDisplay,
WorkflowRunOverviewMetricOut,
WorkflowRunOverviewMetricOutStatus,
@@ -432,10 +437,14 @@
"WorkflowRunDataAudioOut": ".types",
"WorkflowRunDataAudioOutStatus": ".types",
"WorkflowRunDataCardOut": ".types",
+ "WorkflowRunDataCardOutStatus": ".types",
"WorkflowRunDataCardOutWaveformStatus": ".types",
+ "WorkflowRunDataDroppedOut": ".types",
+ "WorkflowRunDataDroppedVerdictOut": ".types",
"WorkflowRunDataOut": ".types",
"WorkflowRunDataPartialOut": ".types",
"WorkflowRunDataPartialOutStatus": ".types",
+ "WorkflowRunDataRejectedOut": ".types",
"WorkflowRunDataResponse": ".types",
"WorkflowRunDataRowOut": ".types",
"WorkflowRunDataRowOutAutoCorrectedStatus": ".types",
@@ -451,6 +460,7 @@
"WorkflowRunOverviewAudioLanguageOut": ".types",
"WorkflowRunOverviewCapabilitiesOut": ".types",
"WorkflowRunOverviewFutureLinksOut": ".types",
+ "WorkflowRunOverviewMetricAnnotation": ".types",
"WorkflowRunOverviewMetricDisplay": ".types",
"WorkflowRunOverviewMetricOut": ".types",
"WorkflowRunOverviewMetricOutStatus": ".types",
@@ -698,10 +708,14 @@ def __dir__():
"WorkflowRunDataAudioOut",
"WorkflowRunDataAudioOutStatus",
"WorkflowRunDataCardOut",
+ "WorkflowRunDataCardOutStatus",
"WorkflowRunDataCardOutWaveformStatus",
+ "WorkflowRunDataDroppedOut",
+ "WorkflowRunDataDroppedVerdictOut",
"WorkflowRunDataOut",
"WorkflowRunDataPartialOut",
"WorkflowRunDataPartialOutStatus",
+ "WorkflowRunDataRejectedOut",
"WorkflowRunDataResponse",
"WorkflowRunDataRowOut",
"WorkflowRunDataRowOutAutoCorrectedStatus",
@@ -717,6 +731,7 @@ def __dir__():
"WorkflowRunOverviewAudioLanguageOut",
"WorkflowRunOverviewCapabilitiesOut",
"WorkflowRunOverviewFutureLinksOut",
+ "WorkflowRunOverviewMetricAnnotation",
"WorkflowRunOverviewMetricDisplay",
"WorkflowRunOverviewMetricOut",
"WorkflowRunOverviewMetricOutStatus",
diff --git a/src/onepin/dictionary/client.py b/src/onepin/dictionary/client.py
index fd2a1cf..564dafe 100644
--- a/src/onepin/dictionary/client.py
+++ b/src/onepin/dictionary/client.py
@@ -11,22 +11,22 @@
from ..types.api_response_pronunciation_suggestion import ApiResponsePronunciationSuggestion
from ..types.dictionary_method import DictionaryMethod
from .raw_client import AsyncRawDictionaryClient, RawDictionaryClient
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_language import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_language import (
ListDictionaryEntriesApiV1DictionaryGetRequestLanguage,
)
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_order import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_order import (
ListDictionaryEntriesApiV1DictionaryGetRequestOrder,
)
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_sort import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_sort import (
ListDictionaryEntriesApiV1DictionaryGetRequestSort,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_language_item import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_language_item import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_order import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_order import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestOrder,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_sort import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_sort import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestSort,
)
diff --git a/src/onepin/dictionary/raw_client.py b/src/onepin/dictionary/raw_client.py
index d7704de..be72790 100644
--- a/src/onepin/dictionary/raw_client.py
+++ b/src/onepin/dictionary/raw_client.py
@@ -17,22 +17,22 @@
from ..types.api_response_list_dictionary_language_out import ApiResponseListDictionaryLanguageOut
from ..types.api_response_pronunciation_suggestion import ApiResponsePronunciationSuggestion
from ..types.dictionary_method import DictionaryMethod
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_language import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_language import (
ListDictionaryEntriesApiV1DictionaryGetRequestLanguage,
)
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_order import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_order import (
ListDictionaryEntriesApiV1DictionaryGetRequestOrder,
)
-from .types.list_dictionary_entries_api_v1_dictionary_get_request_sort import (
+from .types.list_dictionary_entries_api_v1dictionary_get_request_sort import (
ListDictionaryEntriesApiV1DictionaryGetRequestSort,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_language_item import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_language_item import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_order import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_order import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestOrder,
)
-from .types.search_dictionary_entries_api_v1_dictionary_search_get_request_sort import (
+from .types.search_dictionary_entries_api_v1dictionary_search_get_request_sort import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestSort,
)
from pydantic import ValidationError
diff --git a/src/onepin/dictionary/types/__init__.py b/src/onepin/dictionary/types/__init__.py
index 27054ce..c0f2929 100644
--- a/src/onepin/dictionary/types/__init__.py
+++ b/src/onepin/dictionary/types/__init__.py
@@ -6,31 +6,31 @@
from importlib import import_module
if typing.TYPE_CHECKING:
- from .list_dictionary_entries_api_v1_dictionary_get_request_language import (
+ from .list_dictionary_entries_api_v1dictionary_get_request_language import (
ListDictionaryEntriesApiV1DictionaryGetRequestLanguage,
)
- from .list_dictionary_entries_api_v1_dictionary_get_request_order import (
+ from .list_dictionary_entries_api_v1dictionary_get_request_order import (
ListDictionaryEntriesApiV1DictionaryGetRequestOrder,
)
- from .list_dictionary_entries_api_v1_dictionary_get_request_sort import (
+ from .list_dictionary_entries_api_v1dictionary_get_request_sort import (
ListDictionaryEntriesApiV1DictionaryGetRequestSort,
)
- from .search_dictionary_entries_api_v1_dictionary_search_get_request_language_item import (
+ from .search_dictionary_entries_api_v1dictionary_search_get_request_language_item import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem,
)
- from .search_dictionary_entries_api_v1_dictionary_search_get_request_order import (
+ from .search_dictionary_entries_api_v1dictionary_search_get_request_order import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestOrder,
)
- from .search_dictionary_entries_api_v1_dictionary_search_get_request_sort import (
+ from .search_dictionary_entries_api_v1dictionary_search_get_request_sort import (
SearchDictionaryEntriesApiV1DictionarySearchGetRequestSort,
)
_dynamic_imports: typing.Dict[str, str] = {
- "ListDictionaryEntriesApiV1DictionaryGetRequestLanguage": ".list_dictionary_entries_api_v1_dictionary_get_request_language",
- "ListDictionaryEntriesApiV1DictionaryGetRequestOrder": ".list_dictionary_entries_api_v1_dictionary_get_request_order",
- "ListDictionaryEntriesApiV1DictionaryGetRequestSort": ".list_dictionary_entries_api_v1_dictionary_get_request_sort",
- "SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem": ".search_dictionary_entries_api_v1_dictionary_search_get_request_language_item",
- "SearchDictionaryEntriesApiV1DictionarySearchGetRequestOrder": ".search_dictionary_entries_api_v1_dictionary_search_get_request_order",
- "SearchDictionaryEntriesApiV1DictionarySearchGetRequestSort": ".search_dictionary_entries_api_v1_dictionary_search_get_request_sort",
+ "ListDictionaryEntriesApiV1DictionaryGetRequestLanguage": ".list_dictionary_entries_api_v1dictionary_get_request_language",
+ "ListDictionaryEntriesApiV1DictionaryGetRequestOrder": ".list_dictionary_entries_api_v1dictionary_get_request_order",
+ "ListDictionaryEntriesApiV1DictionaryGetRequestSort": ".list_dictionary_entries_api_v1dictionary_get_request_sort",
+ "SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem": ".search_dictionary_entries_api_v1dictionary_search_get_request_language_item",
+ "SearchDictionaryEntriesApiV1DictionarySearchGetRequestOrder": ".search_dictionary_entries_api_v1dictionary_search_get_request_order",
+ "SearchDictionaryEntriesApiV1DictionarySearchGetRequestSort": ".search_dictionary_entries_api_v1dictionary_search_get_request_sort",
}
diff --git a/src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_language.py b/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py
similarity index 100%
rename from src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_language.py
rename to src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py
diff --git a/src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_order.py b/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_order.py
similarity index 100%
rename from src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_order.py
rename to src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_order.py
diff --git a/src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_sort.py b/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_sort.py
similarity index 100%
rename from src/onepin/dictionary/types/list_dictionary_entries_api_v1_dictionary_get_request_sort.py
rename to src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_sort.py
diff --git a/src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_language_item.py b/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py
similarity index 100%
rename from src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_language_item.py
rename to src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py
diff --git a/src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_order.py b/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_order.py
similarity index 100%
rename from src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_order.py
rename to src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_order.py
diff --git a/src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_sort.py b/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_sort.py
similarity index 100%
rename from src/onepin/dictionary/types/search_dictionary_entries_api_v1_dictionary_search_get_request_sort.py
rename to src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_sort.py
diff --git a/src/onepin/reference.md b/src/onepin/reference.md
index d023b31..b2c9a79 100644
--- a/src/onepin/reference.md
+++ b/src/onepin/reference.md
@@ -4797,7 +4797,7 @@ client.uploads.confirm(
-
-**context_type:** `UploadConfirmRequestContextType` — Type of resource this upload is being attached to: `workflow` or `playground`.
+**context_type:** `UploadConfirmRequestContextType` — Type of resource this upload is being attached to: `workflow`, `playground`, or `assistant_session`.
@@ -6867,112 +6867,6 @@ client.workflows.runs_summary(
-
-
-
-
-client.workflows.get_run_steps(...) -> ApiResponseListWorkflowRunStepOut
-
--
-
-#### 📝 Description
-
-
--
-
-
--
-
-List per-node execution steps for a workflow run.
-
-Returns one entry per node execution attempt, ordered by execution sequence.
-Each step includes the node type, status, iteration number (for nodes that
-are retried), start/completion timestamps, and the node's `result` output.
-
-For audio output nodes, `result` is hydrated with short-lived `playback_url`
-values (valid for 15 minutes) so callers can stream audio directly without
-a separate download step.
-
-`node_display_name` is resolved from the run's definition snapshot, so it
-reflects the name the node had when the run executed. Repeated executions of
-the same node share that name and are distinguished by `iteration`.
-
-For a higher-level view with aggregated metrics (pass rates, audio duration
-by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
-script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
-
-
-
-
-
-#### 🔌 Usage
-
-
--
-
-
--
-
-```python
-from onepin import OnePinClient
-from onepin.environment import OnePinClientEnvironment
-
-client = OnePinClient(
- token="",
- environment=OnePinClientEnvironment.PROD,
-)
-
-client.workflows.get_run_steps(
- workflow_id="workflow_id",
- run_id="run_id",
-)
-
-```
-
-
-
-
-
-#### ⚙️ Parameters
-
-
--
-
-
--
-
-**workflow_id:** `str`
-
-
-
-
-
--
-
-**run_id:** `str`
-
-
-
-
-
--
-
-**workspace_id:** `typing.Optional[str]`
-
-
-
-
-
--
-
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
-
-
-
-
-
-
-
@@ -7101,7 +6995,8 @@ completes. It differs from the other run sub-resources as follows:
- `GET /runs/{run_id}` — full run record including the raw definition snapshot.
- `GET /runs/{run_id}/status` — volatile status fields only; for polling.
-- `GET /runs/{run_id}/steps` — flat per-node step log with audio playback URLs.
+- `GET /runs/{run_id}/steps` — lightweight per-node step log by default;
+ `include_result=true` includes results and audio playback URLs.
- `GET /runs/{run_id}/outputs` — one logical result per snapshot sink node.
- `GET /runs/{run_id}/data` — paginated script+audio rows for a data table.
- `GET /runs/{run_id}/overview` (this endpoint) — pre-aggregated metrics and
@@ -7208,6 +7103,8 @@ validation scores (word accuracy, naturalness), and short-lived audio
locale. Rows with no matching cards are still returned (with empty `cards`),
and `pagination.total` always reflects the search-filtered row count
regardless of `language`.
+- `include_dropped=true` adds rejected attempts to `cards` with
+ `status="dropped"`; the default response remains delivered/generated data only.
**Pagination:** `pagination.total` is scoped to the `search` filter only.
@@ -7288,6 +7185,14 @@ client.workflows.get_run_data(
-
+**include_dropped:** `typing.Optional[bool]` — Include validator-rejected audio cards reconstructed from unwired fail ports. Defaults to false so existing clients continue receiving delivered output only.
+
+
+
+
+
+-
+
**offset:** `typing.Optional[int]` — Zero-based pagination offset.
@@ -7423,6 +7328,112 @@ client.workflows.download_run(
+
+
+
+
+client.workflows.get_run_audio_url(...) -> ApiResponseDownloadUrlOut
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Mint a fresh playback URL for one audio output of a run.
+
+`audio_id` is the stable 16-hex output identifier embedded in run-data
+card ids and carried by assistant chat `audio` parts. Presigned playback
+URLs expire after 15 minutes; call this endpoint at play time to refresh
+the URL by id instead of caching it or re-fetching a whole run-data page.
+
+Returns 404 when the run has no s3-backed audio output with this id.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from onepin import OnePinClient
+from onepin.environment import OnePinClientEnvironment
+
+client = OnePinClient(
+ token="",
+ environment=OnePinClientEnvironment.PROD,
+)
+
+client.workflows.get_run_audio_url(
+ workflow_id="workflow_id",
+ run_id="run_id",
+ audio_id="audio_id",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**workflow_id:** `str`
+
+
+
+
+
+-
+
+**run_id:** `str`
+
+
+
+
+
+-
+
+**audio_id:** `str`
+
+
+
+
+
+-
+
+**workspace_id:** `typing.Optional[str]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -8101,7 +8112,8 @@ workflow definition has since been edited.
This is the heaviest run endpoint. For progress polling, use the lighter
`GET /runs/{run_id}/status` which omits the snapshot. For aggregated
visual metrics, use `GET /runs/{run_id}/overview`. For the per-node step
-log with audio playback URLs, use `GET /runs/{run_id}/steps`.
+log, use `GET /runs/{run_id}/steps`; opt into full results and audio
+playback URLs with `include_result=true`.
@@ -8281,6 +8293,137 @@ client.workflows.runs.status(
+
+
+
+
+client.workflows.runs.steps(...) -> ApiResponseListWorkflowRunStepOut
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+List per-node execution steps for a workflow run.
+
+Returns one entry per node execution attempt, ordered by execution sequence.
+By default, the response is lightweight: `result` is null, `has_result`
+reports whether a stored result exists, and `active_ports` is projected from
+the result without loading the full JSON payload.
+
+Set `include_result=true` to restore the full result payload. Audio results
+are then hydrated with short-lived `playback_url` values (valid for 15
+minutes). `node_type` and `node_id` filters combine with AND semantics.
+
+`node_display_name` is resolved from the run's definition snapshot, so it
+reflects the name the node had when the run executed. Repeated executions of
+the same node share that name and are distinguished by `iteration`.
+
+For a higher-level view with aggregated metrics (pass rates, audio duration
+by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
+script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from onepin import OnePinClient
+from onepin.environment import OnePinClientEnvironment
+
+client = OnePinClient(
+ token="",
+ environment=OnePinClientEnvironment.PROD,
+)
+
+client.workflows.runs.steps(
+ workflow_id="workflow_id",
+ run_id="run_id",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**workflow_id:** `str`
+
+
+
+
+
+-
+
+**run_id:** `str`
+
+
+
+
+
+-
+
+**include_result:** `typing.Optional[bool]` — Include the full step result payload and hydrate audio playback URLs.
+
+
+
+
+
+-
+
+**node_type:** `typing.Optional[NodeType]` — Filter steps by node type.
+
+
+
+
+
+-
+
+**node_id:** `typing.Optional[str]` — Filter steps by node ID.
+
+
+
+
+
+-
+
+**workspace_id:** `typing.Optional[str]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -8304,9 +8447,9 @@ In-flight work at the current node may be abandoned mid-execution. The
operation is idempotent: cancelling an already-cancelled run returns the
run unchanged without error.
-Only runs in `pending`, `running`, or `paused` status can be cancelled.
-Runs that have already reached a terminal state (`completed`, `failed`,
-`cancelled`) return 409.
+Runs already in a terminal state (`completed`, `failed`, or `cancelled`)
+are returned unchanged. Concurrent terminalization is also treated as an
+idempotent success; a still-active compare-and-swap loser returns 409.
Unlike `pause`, cancel is permanent — a cancelled run cannot be resumed.
Use `pause` if you intend to continue the run later.
diff --git a/src/onepin/types/__init__.py b/src/onepin/types/__init__.py
index 4884842..c2f5808 100644
--- a/src/onepin/types/__init__.py
+++ b/src/onepin/types/__init__.py
@@ -157,10 +157,14 @@
from .workflow_run_data_audio_out import WorkflowRunDataAudioOut
from .workflow_run_data_audio_out_status import WorkflowRunDataAudioOutStatus
from .workflow_run_data_card_out import WorkflowRunDataCardOut
+ from .workflow_run_data_card_out_status import WorkflowRunDataCardOutStatus
from .workflow_run_data_card_out_waveform_status import WorkflowRunDataCardOutWaveformStatus
+ from .workflow_run_data_dropped_out import WorkflowRunDataDroppedOut
+ from .workflow_run_data_dropped_verdict_out import WorkflowRunDataDroppedVerdictOut
from .workflow_run_data_out import WorkflowRunDataOut
from .workflow_run_data_partial_out import WorkflowRunDataPartialOut
from .workflow_run_data_partial_out_status import WorkflowRunDataPartialOutStatus
+ from .workflow_run_data_rejected_out import WorkflowRunDataRejectedOut
from .workflow_run_data_response import WorkflowRunDataResponse
from .workflow_run_data_row_out import WorkflowRunDataRowOut
from .workflow_run_data_row_out_auto_corrected_status import WorkflowRunDataRowOutAutoCorrectedStatus
@@ -176,6 +180,7 @@
from .workflow_run_overview_audio_language_out import WorkflowRunOverviewAudioLanguageOut
from .workflow_run_overview_capabilities_out import WorkflowRunOverviewCapabilitiesOut
from .workflow_run_overview_future_links_out import WorkflowRunOverviewFutureLinksOut
+ from .workflow_run_overview_metric_annotation import WorkflowRunOverviewMetricAnnotation
from .workflow_run_overview_metric_display import WorkflowRunOverviewMetricDisplay
from .workflow_run_overview_metric_out import WorkflowRunOverviewMetricOut
from .workflow_run_overview_metric_out_status import WorkflowRunOverviewMetricOutStatus
@@ -348,10 +353,14 @@
"WorkflowRunDataAudioOut": ".workflow_run_data_audio_out",
"WorkflowRunDataAudioOutStatus": ".workflow_run_data_audio_out_status",
"WorkflowRunDataCardOut": ".workflow_run_data_card_out",
+ "WorkflowRunDataCardOutStatus": ".workflow_run_data_card_out_status",
"WorkflowRunDataCardOutWaveformStatus": ".workflow_run_data_card_out_waveform_status",
+ "WorkflowRunDataDroppedOut": ".workflow_run_data_dropped_out",
+ "WorkflowRunDataDroppedVerdictOut": ".workflow_run_data_dropped_verdict_out",
"WorkflowRunDataOut": ".workflow_run_data_out",
"WorkflowRunDataPartialOut": ".workflow_run_data_partial_out",
"WorkflowRunDataPartialOutStatus": ".workflow_run_data_partial_out_status",
+ "WorkflowRunDataRejectedOut": ".workflow_run_data_rejected_out",
"WorkflowRunDataResponse": ".workflow_run_data_response",
"WorkflowRunDataRowOut": ".workflow_run_data_row_out",
"WorkflowRunDataRowOutAutoCorrectedStatus": ".workflow_run_data_row_out_auto_corrected_status",
@@ -367,6 +376,7 @@
"WorkflowRunOverviewAudioLanguageOut": ".workflow_run_overview_audio_language_out",
"WorkflowRunOverviewCapabilitiesOut": ".workflow_run_overview_capabilities_out",
"WorkflowRunOverviewFutureLinksOut": ".workflow_run_overview_future_links_out",
+ "WorkflowRunOverviewMetricAnnotation": ".workflow_run_overview_metric_annotation",
"WorkflowRunOverviewMetricDisplay": ".workflow_run_overview_metric_display",
"WorkflowRunOverviewMetricOut": ".workflow_run_overview_metric_out",
"WorkflowRunOverviewMetricOutStatus": ".workflow_run_overview_metric_out_status",
@@ -563,10 +573,14 @@ def __dir__():
"WorkflowRunDataAudioOut",
"WorkflowRunDataAudioOutStatus",
"WorkflowRunDataCardOut",
+ "WorkflowRunDataCardOutStatus",
"WorkflowRunDataCardOutWaveformStatus",
+ "WorkflowRunDataDroppedOut",
+ "WorkflowRunDataDroppedVerdictOut",
"WorkflowRunDataOut",
"WorkflowRunDataPartialOut",
"WorkflowRunDataPartialOutStatus",
+ "WorkflowRunDataRejectedOut",
"WorkflowRunDataResponse",
"WorkflowRunDataRowOut",
"WorkflowRunDataRowOutAutoCorrectedStatus",
@@ -582,6 +596,7 @@ def __dir__():
"WorkflowRunOverviewAudioLanguageOut",
"WorkflowRunOverviewCapabilitiesOut",
"WorkflowRunOverviewFutureLinksOut",
+ "WorkflowRunOverviewMetricAnnotation",
"WorkflowRunOverviewMetricDisplay",
"WorkflowRunOverviewMetricOut",
"WorkflowRunOverviewMetricOutStatus",
diff --git a/src/onepin/types/workflow_run_data_card_out.py b/src/onepin/types/workflow_run_data_card_out.py
index b4b9e16..57bed63 100644
--- a/src/onepin/types/workflow_run_data_card_out.py
+++ b/src/onepin/types/workflow_run_data_card_out.py
@@ -5,7 +5,10 @@
import pydantic
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .workflow_run_data_audio_out import WorkflowRunDataAudioOut
+from .workflow_run_data_card_out_status import WorkflowRunDataCardOutStatus
from .workflow_run_data_card_out_waveform_status import WorkflowRunDataCardOutWaveformStatus
+from .workflow_run_data_dropped_out import WorkflowRunDataDroppedOut
+from .workflow_run_data_rejected_out import WorkflowRunDataRejectedOut
from .workflow_run_data_validation_out import WorkflowRunDataValidationOut
from .workflow_run_data_voice_out import WorkflowRunDataVoiceOut
@@ -24,6 +27,9 @@ class WorkflowRunDataCardOut(UniversalBaseModel):
waveform_status: typing.Optional[WorkflowRunDataCardOutWaveformStatus] = None
waveform_reason: typing.Optional[str] = None
retry_count: typing.Optional[int] = None
+ status: typing.Optional[WorkflowRunDataCardOutStatus] = None
+ dropped: typing.Optional[WorkflowRunDataDroppedOut] = None
+ rejected: typing.Optional[WorkflowRunDataRejectedOut] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/workflow_run_data_card_out_status.py b/src/onepin/types/workflow_run_data_card_out_status.py
new file mode 100644
index 0000000..9ed2c35
--- /dev/null
+++ b/src/onepin/types/workflow_run_data_card_out_status.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+WorkflowRunDataCardOutStatus = typing.Union[
+ typing.Literal["delivered", "generated", "not_delivered", "dropped"], typing.Any
+]
diff --git a/src/onepin/types/workflow_run_data_dropped_out.py b/src/onepin/types/workflow_run_data_dropped_out.py
new file mode 100644
index 0000000..2617b5d
--- /dev/null
+++ b/src/onepin/types/workflow_run_data_dropped_out.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .workflow_run_data_dropped_verdict_out import WorkflowRunDataDroppedVerdictOut
+
+
+class WorkflowRunDataDroppedOut(UniversalBaseModel):
+ verdicts: typing.Optional[typing.List[WorkflowRunDataDroppedVerdictOut]] = None
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/onepin/types/workflow_run_data_dropped_verdict_out.py b/src/onepin/types/workflow_run_data_dropped_verdict_out.py
new file mode 100644
index 0000000..b418359
--- /dev/null
+++ b/src/onepin/types/workflow_run_data_dropped_verdict_out.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class WorkflowRunDataDroppedVerdictOut(UniversalBaseModel):
+ """
+ One failing validator's verdict on a dropped take.
+
+ A take can fail several parallel validators at once; ``validator_node_id``
+ disambiguates two validators of the same kind (e.g. two WER nodes with
+ different thresholds). ``threshold`` is the pass bar that actually gated
+ the line (schema defaults resolved); null only for invalid snapshots.
+ """
+
+ validator_node_id: str
+ validator_kind: str
+ validator_label: str
+ score: typing.Optional[float] = None
+ threshold: typing.Optional[float] = None
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/onepin/types/workflow_run_data_out.py b/src/onepin/types/workflow_run_data_out.py
index 0af36ff..7b22f18 100644
--- a/src/onepin/types/workflow_run_data_out.py
+++ b/src/onepin/types/workflow_run_data_out.py
@@ -14,6 +14,7 @@ class WorkflowRunDataOut(UniversalBaseModel):
run_status: str
rows: typing.Optional[typing.List[WorkflowRunDataRowOut]] = None
partial: WorkflowRunDataPartialOut
+ dropped_truncated: typing.Optional[bool] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/workflow_run_data_rejected_out.py b/src/onepin/types/workflow_run_data_rejected_out.py
new file mode 100644
index 0000000..c9ef385
--- /dev/null
+++ b/src/onepin/types/workflow_run_data_rejected_out.py
@@ -0,0 +1,24 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .workflow_run_data_dropped_verdict_out import WorkflowRunDataDroppedVerdictOut
+
+
+class WorkflowRunDataRejectedOut(UniversalBaseModel):
+ """
+ Per-take validator failures, independent of delivery disposition.
+ """
+
+ verdicts: typing.Optional[typing.List[WorkflowRunDataDroppedVerdictOut]] = None
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/onepin/types/workflow_run_overview_metric_annotation.py b/src/onepin/types/workflow_run_overview_metric_annotation.py
new file mode 100644
index 0000000..79f2601
--- /dev/null
+++ b/src/onepin/types/workflow_run_overview_metric_annotation.py
@@ -0,0 +1,24 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class WorkflowRunOverviewMetricAnnotation(UniversalBaseModel):
+ """
+ Small subtext under a metric value (e.g. `output_lines` → "2 dropped").
+ """
+
+ text: str
+ emphasis: typing.Optional[str] = None
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/onepin/types/workflow_run_overview_metric_out.py b/src/onepin/types/workflow_run_overview_metric_out.py
index 737df05..a2e7b73 100644
--- a/src/onepin/types/workflow_run_overview_metric_out.py
+++ b/src/onepin/types/workflow_run_overview_metric_out.py
@@ -4,6 +4,7 @@
import pydantic
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .workflow_run_overview_metric_annotation import WorkflowRunOverviewMetricAnnotation
from .workflow_run_overview_metric_display import WorkflowRunOverviewMetricDisplay
from .workflow_run_overview_metric_out_status import WorkflowRunOverviewMetricOutStatus
from .workflow_run_overview_metric_out_value import WorkflowRunOverviewMetricOutValue
@@ -18,6 +19,7 @@ class WorkflowRunOverviewMetricOut(UniversalBaseModel):
status: WorkflowRunOverviewMetricOutStatus
reason: typing.Optional[str] = None
display: WorkflowRunOverviewMetricDisplay
+ annotation: typing.Optional[WorkflowRunOverviewMetricAnnotation] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/workflow_run_step_out.py b/src/onepin/types/workflow_run_step_out.py
index 14da64c..19593a3 100644
--- a/src/onepin/types/workflow_run_step_out.py
+++ b/src/onepin/types/workflow_run_step_out.py
@@ -17,6 +17,8 @@ class WorkflowRunStepOut(UniversalBaseModel):
started_at: typing.Optional[dt.datetime] = None
completed_at: typing.Optional[dt.datetime] = None
result: typing.Optional[typing.Dict[str, typing.Any]] = None
+ has_result: typing.Optional[bool] = None
+ active_ports: typing.Optional[typing.List[str]] = None
error: typing.Optional[str] = None
if IS_PYDANTIC_V2:
diff --git a/src/onepin/uploads/client.py b/src/onepin/uploads/client.py
index ca8c311..d0a06a0 100644
--- a/src/onepin/uploads/client.py
+++ b/src/onepin/uploads/client.py
@@ -133,7 +133,7 @@ def confirm(
upload_id : str
context_type : UploadConfirmRequestContextType
- Type of resource this upload is being attached to: `workflow` or `playground`.
+ Type of resource this upload is being attached to: `workflow`, `playground`, or `assistant_session`.
context_id : str
ID of the resource to attach this upload to. Must be an existing resource of the given `context_type` that the caller has access to.
@@ -349,7 +349,7 @@ async def confirm(
upload_id : str
context_type : UploadConfirmRequestContextType
- Type of resource this upload is being attached to: `workflow` or `playground`.
+ Type of resource this upload is being attached to: `workflow`, `playground`, or `assistant_session`.
context_id : str
ID of the resource to attach this upload to. Must be an existing resource of the given `context_type` that the caller has access to.
diff --git a/src/onepin/uploads/raw_client.py b/src/onepin/uploads/raw_client.py
index 01b6a6a..0bc4135 100644
--- a/src/onepin/uploads/raw_client.py
+++ b/src/onepin/uploads/raw_client.py
@@ -156,7 +156,7 @@ def confirm(
upload_id : str
context_type : UploadConfirmRequestContextType
- Type of resource this upload is being attached to: `workflow` or `playground`.
+ Type of resource this upload is being attached to: `workflow`, `playground`, or `assistant_session`.
context_id : str
ID of the resource to attach this upload to. Must be an existing resource of the given `context_type` that the caller has access to.
@@ -426,7 +426,7 @@ async def confirm(
upload_id : str
context_type : UploadConfirmRequestContextType
- Type of resource this upload is being attached to: `workflow` or `playground`.
+ Type of resource this upload is being attached to: `workflow`, `playground`, or `assistant_session`.
context_id : str
ID of the resource to attach this upload to. Must be an existing resource of the given `context_type` that the caller has access to.
diff --git a/src/onepin/uploads/types/upload_confirm_request_context_type.py b/src/onepin/uploads/types/upload_confirm_request_context_type.py
index 182e6ce..c0fb534 100644
--- a/src/onepin/uploads/types/upload_confirm_request_context_type.py
+++ b/src/onepin/uploads/types/upload_confirm_request_context_type.py
@@ -2,4 +2,6 @@
import typing
-UploadConfirmRequestContextType = typing.Union[typing.Literal["workflow", "playground"], typing.Any]
+UploadConfirmRequestContextType = typing.Union[
+ typing.Literal["workflow", "playground", "assistant_session"], typing.Any
+]
diff --git a/src/onepin/usage/client.py b/src/onepin/usage/client.py
index ee636b5..7d217fd 100644
--- a/src/onepin/usage/client.py
+++ b/src/onepin/usage/client.py
@@ -9,17 +9,17 @@
from ..types.api_response_usage_summary_out import ApiResponseUsageSummaryOut
from ..types.usage_activity_action import UsageActivityAction
from .raw_client import AsyncRawUsageClient, RawUsageClient
-from .types.usage_activity_api_v1_usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
-from .types.usage_by_language_api_v1_usage_by_language_get_request_activity_view import (
+from .types.usage_activity_api_v1usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
+from .types.usage_by_language_api_v1usage_by_language_get_request_activity_view import (
UsageByLanguageApiV1UsageByLanguageGetRequestActivityView,
)
-from .types.usage_by_language_api_v1_usage_by_language_get_request_range import (
+from .types.usage_by_language_api_v1usage_by_language_get_request_range import (
UsageByLanguageApiV1UsageByLanguageGetRequestRange,
)
-from .types.usage_summary_api_v1_usage_summary_get_request_activity_view import (
+from .types.usage_summary_api_v1usage_summary_get_request_activity_view import (
UsageSummaryApiV1UsageSummaryGetRequestActivityView,
)
-from .types.usage_summary_api_v1_usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
+from .types.usage_summary_api_v1usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
class UsageClient:
diff --git a/src/onepin/usage/raw_client.py b/src/onepin/usage/raw_client.py
index fe0832e..009698b 100644
--- a/src/onepin/usage/raw_client.py
+++ b/src/onepin/usage/raw_client.py
@@ -14,17 +14,17 @@
from ..types.api_response_usage_by_language_out import ApiResponseUsageByLanguageOut
from ..types.api_response_usage_summary_out import ApiResponseUsageSummaryOut
from ..types.usage_activity_action import UsageActivityAction
-from .types.usage_activity_api_v1_usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
-from .types.usage_by_language_api_v1_usage_by_language_get_request_activity_view import (
+from .types.usage_activity_api_v1usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
+from .types.usage_by_language_api_v1usage_by_language_get_request_activity_view import (
UsageByLanguageApiV1UsageByLanguageGetRequestActivityView,
)
-from .types.usage_by_language_api_v1_usage_by_language_get_request_range import (
+from .types.usage_by_language_api_v1usage_by_language_get_request_range import (
UsageByLanguageApiV1UsageByLanguageGetRequestRange,
)
-from .types.usage_summary_api_v1_usage_summary_get_request_activity_view import (
+from .types.usage_summary_api_v1usage_summary_get_request_activity_view import (
UsageSummaryApiV1UsageSummaryGetRequestActivityView,
)
-from .types.usage_summary_api_v1_usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
+from .types.usage_summary_api_v1usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
from pydantic import ValidationError
diff --git a/src/onepin/usage/types/__init__.py b/src/onepin/usage/types/__init__.py
index 000f50b..53281f8 100644
--- a/src/onepin/usage/types/__init__.py
+++ b/src/onepin/usage/types/__init__.py
@@ -6,23 +6,23 @@
from importlib import import_module
if typing.TYPE_CHECKING:
- from .usage_activity_api_v1_usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
- from .usage_by_language_api_v1_usage_by_language_get_request_activity_view import (
+ from .usage_activity_api_v1usage_activity_get_request_range import UsageActivityApiV1UsageActivityGetRequestRange
+ from .usage_by_language_api_v1usage_by_language_get_request_activity_view import (
UsageByLanguageApiV1UsageByLanguageGetRequestActivityView,
)
- from .usage_by_language_api_v1_usage_by_language_get_request_range import (
+ from .usage_by_language_api_v1usage_by_language_get_request_range import (
UsageByLanguageApiV1UsageByLanguageGetRequestRange,
)
- from .usage_summary_api_v1_usage_summary_get_request_activity_view import (
+ from .usage_summary_api_v1usage_summary_get_request_activity_view import (
UsageSummaryApiV1UsageSummaryGetRequestActivityView,
)
- from .usage_summary_api_v1_usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
+ from .usage_summary_api_v1usage_summary_get_request_range import UsageSummaryApiV1UsageSummaryGetRequestRange
_dynamic_imports: typing.Dict[str, str] = {
- "UsageActivityApiV1UsageActivityGetRequestRange": ".usage_activity_api_v1_usage_activity_get_request_range",
- "UsageByLanguageApiV1UsageByLanguageGetRequestActivityView": ".usage_by_language_api_v1_usage_by_language_get_request_activity_view",
- "UsageByLanguageApiV1UsageByLanguageGetRequestRange": ".usage_by_language_api_v1_usage_by_language_get_request_range",
- "UsageSummaryApiV1UsageSummaryGetRequestActivityView": ".usage_summary_api_v1_usage_summary_get_request_activity_view",
- "UsageSummaryApiV1UsageSummaryGetRequestRange": ".usage_summary_api_v1_usage_summary_get_request_range",
+ "UsageActivityApiV1UsageActivityGetRequestRange": ".usage_activity_api_v1usage_activity_get_request_range",
+ "UsageByLanguageApiV1UsageByLanguageGetRequestActivityView": ".usage_by_language_api_v1usage_by_language_get_request_activity_view",
+ "UsageByLanguageApiV1UsageByLanguageGetRequestRange": ".usage_by_language_api_v1usage_by_language_get_request_range",
+ "UsageSummaryApiV1UsageSummaryGetRequestActivityView": ".usage_summary_api_v1usage_summary_get_request_activity_view",
+ "UsageSummaryApiV1UsageSummaryGetRequestRange": ".usage_summary_api_v1usage_summary_get_request_range",
}
diff --git a/src/onepin/usage/types/usage_activity_api_v1_usage_activity_get_request_range.py b/src/onepin/usage/types/usage_activity_api_v1usage_activity_get_request_range.py
similarity index 100%
rename from src/onepin/usage/types/usage_activity_api_v1_usage_activity_get_request_range.py
rename to src/onepin/usage/types/usage_activity_api_v1usage_activity_get_request_range.py
diff --git a/src/onepin/usage/types/usage_by_language_api_v1_usage_by_language_get_request_activity_view.py b/src/onepin/usage/types/usage_by_language_api_v1usage_by_language_get_request_activity_view.py
similarity index 100%
rename from src/onepin/usage/types/usage_by_language_api_v1_usage_by_language_get_request_activity_view.py
rename to src/onepin/usage/types/usage_by_language_api_v1usage_by_language_get_request_activity_view.py
diff --git a/src/onepin/usage/types/usage_by_language_api_v1_usage_by_language_get_request_range.py b/src/onepin/usage/types/usage_by_language_api_v1usage_by_language_get_request_range.py
similarity index 100%
rename from src/onepin/usage/types/usage_by_language_api_v1_usage_by_language_get_request_range.py
rename to src/onepin/usage/types/usage_by_language_api_v1usage_by_language_get_request_range.py
diff --git a/src/onepin/usage/types/usage_summary_api_v1_usage_summary_get_request_activity_view.py b/src/onepin/usage/types/usage_summary_api_v1usage_summary_get_request_activity_view.py
similarity index 100%
rename from src/onepin/usage/types/usage_summary_api_v1_usage_summary_get_request_activity_view.py
rename to src/onepin/usage/types/usage_summary_api_v1usage_summary_get_request_activity_view.py
diff --git a/src/onepin/usage/types/usage_summary_api_v1_usage_summary_get_request_range.py b/src/onepin/usage/types/usage_summary_api_v1usage_summary_get_request_range.py
similarity index 100%
rename from src/onepin/usage/types/usage_summary_api_v1_usage_summary_get_request_range.py
rename to src/onepin/usage/types/usage_summary_api_v1usage_summary_get_request_range.py
diff --git a/src/onepin/users/client.py b/src/onepin/users/client.py
index 488560b..4de6674 100644
--- a/src/onepin/users/client.py
+++ b/src/onepin/users/client.py
@@ -10,7 +10,7 @@
from ..types.api_response_plan_limits import ApiResponsePlanLimits
from ..types.template_category import TemplateCategory
from .raw_client import AsyncRawUsersClient, RawUsersClient
-from .types.list_my_templates_api_v1_users_me_templates_get_request_sort import (
+from .types.list_my_templates_api_v1users_me_templates_get_request_sort import (
ListMyTemplatesApiV1UsersMeTemplatesGetRequestSort,
)
diff --git a/src/onepin/users/raw_client.py b/src/onepin/users/raw_client.py
index 723eb45..6da6376 100644
--- a/src/onepin/users/raw_client.py
+++ b/src/onepin/users/raw_client.py
@@ -15,7 +15,7 @@
from ..types.api_response_email_notification_preferences_out import ApiResponseEmailNotificationPreferencesOut
from ..types.api_response_plan_limits import ApiResponsePlanLimits
from ..types.template_category import TemplateCategory
-from .types.list_my_templates_api_v1_users_me_templates_get_request_sort import (
+from .types.list_my_templates_api_v1users_me_templates_get_request_sort import (
ListMyTemplatesApiV1UsersMeTemplatesGetRequestSort,
)
from pydantic import ValidationError
diff --git a/src/onepin/users/types/__init__.py b/src/onepin/users/types/__init__.py
index a08a5f6..f7f5157 100644
--- a/src/onepin/users/types/__init__.py
+++ b/src/onepin/users/types/__init__.py
@@ -6,11 +6,11 @@
from importlib import import_module
if typing.TYPE_CHECKING:
- from .list_my_templates_api_v1_users_me_templates_get_request_sort import (
+ from .list_my_templates_api_v1users_me_templates_get_request_sort import (
ListMyTemplatesApiV1UsersMeTemplatesGetRequestSort,
)
_dynamic_imports: typing.Dict[str, str] = {
- "ListMyTemplatesApiV1UsersMeTemplatesGetRequestSort": ".list_my_templates_api_v1_users_me_templates_get_request_sort"
+ "ListMyTemplatesApiV1UsersMeTemplatesGetRequestSort": ".list_my_templates_api_v1users_me_templates_get_request_sort"
}
diff --git a/src/onepin/users/types/list_my_templates_api_v1_users_me_templates_get_request_sort.py b/src/onepin/users/types/list_my_templates_api_v1users_me_templates_get_request_sort.py
similarity index 100%
rename from src/onepin/users/types/list_my_templates_api_v1_users_me_templates_get_request_sort.py
rename to src/onepin/users/types/list_my_templates_api_v1users_me_templates_get_request_sort.py
diff --git a/src/onepin/voices/client.py b/src/onepin/voices/client.py
index ed265d3..36cfe30 100644
--- a/src/onepin/voices/client.py
+++ b/src/onepin/voices/client.py
@@ -14,7 +14,7 @@
from ..types.voice_category import VoiceCategory
from ..types.voice_gender import VoiceGender
from .raw_client import AsyncRawVoicesClient, RawVoicesClient
-from .types.get_voice_facets_api_v1_voices_facets_get_request_source_item import (
+from .types.get_voice_facets_api_v1voices_facets_get_request_source_item import (
GetVoiceFacetsApiV1VoicesFacetsGetRequestSourceItem,
)
from .types.list_voices_request_language_item import ListVoicesRequestLanguageItem
diff --git a/src/onepin/voices/raw_client.py b/src/onepin/voices/raw_client.py
index 7cab1e1..ce39276 100644
--- a/src/onepin/voices/raw_client.py
+++ b/src/onepin/voices/raw_client.py
@@ -20,7 +20,7 @@
from ..types.voice_age import VoiceAge
from ..types.voice_category import VoiceCategory
from ..types.voice_gender import VoiceGender
-from .types.get_voice_facets_api_v1_voices_facets_get_request_source_item import (
+from .types.get_voice_facets_api_v1voices_facets_get_request_source_item import (
GetVoiceFacetsApiV1VoicesFacetsGetRequestSourceItem,
)
from .types.list_voices_request_language_item import ListVoicesRequestLanguageItem
diff --git a/src/onepin/voices/types/__init__.py b/src/onepin/voices/types/__init__.py
index b1c9803..3c4972a 100644
--- a/src/onepin/voices/types/__init__.py
+++ b/src/onepin/voices/types/__init__.py
@@ -6,7 +6,7 @@
from importlib import import_module
if typing.TYPE_CHECKING:
- from .get_voice_facets_api_v1_voices_facets_get_request_source_item import (
+ from .get_voice_facets_api_v1voices_facets_get_request_source_item import (
GetVoiceFacetsApiV1VoicesFacetsGetRequestSourceItem,
)
from .list_voices_request_language_item import ListVoicesRequestLanguageItem
@@ -14,7 +14,7 @@
from .list_voices_request_sort_item import ListVoicesRequestSortItem
from .list_voices_request_source_item import ListVoicesRequestSourceItem
_dynamic_imports: typing.Dict[str, str] = {
- "GetVoiceFacetsApiV1VoicesFacetsGetRequestSourceItem": ".get_voice_facets_api_v1_voices_facets_get_request_source_item",
+ "GetVoiceFacetsApiV1VoicesFacetsGetRequestSourceItem": ".get_voice_facets_api_v1voices_facets_get_request_source_item",
"ListVoicesRequestLanguageItem": ".list_voices_request_language_item",
"ListVoicesRequestOrderItem": ".list_voices_request_order_item",
"ListVoicesRequestSortItem": ".list_voices_request_sort_item",
diff --git a/src/onepin/voices/types/get_voice_facets_api_v1_voices_facets_get_request_source_item.py b/src/onepin/voices/types/get_voice_facets_api_v1voices_facets_get_request_source_item.py
similarity index 100%
rename from src/onepin/voices/types/get_voice_facets_api_v1_voices_facets_get_request_source_item.py
rename to src/onepin/voices/types/get_voice_facets_api_v1voices_facets_get_request_source_item.py
diff --git a/src/onepin/workflows/client.py b/src/onepin/workflows/client.py
index 876fdb8..6343c95 100644
--- a/src/onepin/workflows/client.py
+++ b/src/onepin/workflows/client.py
@@ -12,7 +12,6 @@
from ..types.api_response_dict import ApiResponseDict
from ..types.api_response_download_url_out import ApiResponseDownloadUrlOut
from ..types.api_response_estimate_response import ApiResponseEstimateResponse
-from ..types.api_response_list_workflow_run_step_out import ApiResponseListWorkflowRunStepOut
from ..types.api_response_runs_summary_out import ApiResponseRunsSummaryOut
from ..types.api_response_workflow_name_availability_out import ApiResponseWorkflowNameAvailabilityOut
from ..types.api_response_workflow_out import ApiResponseWorkflowOut
@@ -705,66 +704,6 @@ def runs_summary(
)
return _response.data
- def get_run_steps(
- self,
- workflow_id: str,
- run_id: str,
- *,
- workspace_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ApiResponseListWorkflowRunStepOut:
- """
- List per-node execution steps for a workflow run.
-
- Returns one entry per node execution attempt, ordered by execution sequence.
- Each step includes the node type, status, iteration number (for nodes that
- are retried), start/completion timestamps, and the node's `result` output.
-
- For audio output nodes, `result` is hydrated with short-lived `playback_url`
- values (valid for 15 minutes) so callers can stream audio directly without
- a separate download step.
-
- `node_display_name` is resolved from the run's definition snapshot, so it
- reflects the name the node had when the run executed. Repeated executions of
- the same node share that name and are distinguished by `iteration`.
-
- For a higher-level view with aggregated metrics (pass rates, audio duration
- by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
- script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
-
- Parameters
- ----------
- workflow_id : str
-
- run_id : str
-
- workspace_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ApiResponseListWorkflowRunStepOut
- Successful Response
-
- Examples
- --------
- from onepin import OnePinClient
-
- client = OnePinClient(
- token="YOUR_TOKEN",
- )
- client.workflows.get_run_steps(
- workflow_id="workflow_id",
- run_id="run_id",
- )
- """
- _response = self._raw_client.get_run_steps(
- workflow_id, run_id, workspace_id=workspace_id, request_options=request_options
- )
- return _response.data
-
def get_run_outputs(
self,
workflow_id: str,
@@ -840,7 +779,8 @@ def get_run_overview(
- `GET /runs/{run_id}` — full run record including the raw definition snapshot.
- `GET /runs/{run_id}/status` — volatile status fields only; for polling.
- - `GET /runs/{run_id}/steps` — flat per-node step log with audio playback URLs.
+ - `GET /runs/{run_id}/steps` — lightweight per-node step log by default;
+ `include_result=true` includes results and audio playback URLs.
- `GET /runs/{run_id}/outputs` — one logical result per snapshot sink node.
- `GET /runs/{run_id}/data` — paginated script+audio rows for a data table.
- `GET /runs/{run_id}/overview` (this endpoint) — pre-aggregated metrics and
@@ -886,6 +826,7 @@ def get_run_data(
*,
search: typing.Optional[str] = None,
language: typing.Optional[str] = None,
+ include_dropped: typing.Optional[bool] = None,
offset: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
workspace_id: typing.Optional[str] = None,
@@ -905,6 +846,8 @@ def get_run_data(
locale. Rows with no matching cards are still returned (with empty `cards`),
and `pagination.total` always reflects the search-filtered row count
regardless of `language`.
+ - `include_dropped=true` adds rejected attempts to `cards` with
+ `status="dropped"`; the default response remains delivered/generated data only.
**Pagination:** `pagination.total` is scoped to the `search` filter only.
@@ -925,6 +868,9 @@ def get_run_data(
language : typing.Optional[str]
Exact full-locale code to filter cards within each row (e.g. `en-US`). `_` is normalized to `-`. Filtering is card-level only — rows remain visible even when all their cards are filtered out, and `pagination.total` is unaffected.
+ include_dropped : typing.Optional[bool]
+ Include validator-rejected audio cards reconstructed from unwired fail ports. Defaults to false so existing clients continue receiving delivered output only.
+
offset : typing.Optional[int]
Zero-based pagination offset.
@@ -958,6 +904,7 @@ def get_run_data(
run_id,
search=search,
language=language,
+ include_dropped=include_dropped,
offset=offset,
limit=limit,
workspace_id=workspace_id,
@@ -1022,6 +969,61 @@ def download_run(
)
return _response.data
+ def get_run_audio_url(
+ self,
+ workflow_id: str,
+ run_id: str,
+ audio_id: str,
+ *,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiResponseDownloadUrlOut:
+ """
+ Mint a fresh playback URL for one audio output of a run.
+
+ `audio_id` is the stable 16-hex output identifier embedded in run-data
+ card ids and carried by assistant chat `audio` parts. Presigned playback
+ URLs expire after 15 minutes; call this endpoint at play time to refresh
+ the URL by id instead of caching it or re-fetching a whole run-data page.
+
+ Returns 404 when the run has no s3-backed audio output with this id.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ audio_id : str
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiResponseDownloadUrlOut
+ Successful Response
+
+ Examples
+ --------
+ from onepin import OnePinClient
+
+ client = OnePinClient(
+ token="YOUR_TOKEN",
+ )
+ client.workflows.get_run_audio_url(
+ workflow_id="workflow_id",
+ run_id="run_id",
+ audio_id="audio_id",
+ )
+ """
+ _response = self._raw_client.get_run_audio_url(
+ workflow_id, run_id, audio_id, workspace_id=workspace_id, request_options=request_options
+ )
+ return _response.data
+
def download_run_node(
self,
workflow_id: str,
@@ -2006,74 +2008,6 @@ async def main() -> None:
)
return _response.data
- async def get_run_steps(
- self,
- workflow_id: str,
- run_id: str,
- *,
- workspace_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ApiResponseListWorkflowRunStepOut:
- """
- List per-node execution steps for a workflow run.
-
- Returns one entry per node execution attempt, ordered by execution sequence.
- Each step includes the node type, status, iteration number (for nodes that
- are retried), start/completion timestamps, and the node's `result` output.
-
- For audio output nodes, `result` is hydrated with short-lived `playback_url`
- values (valid for 15 minutes) so callers can stream audio directly without
- a separate download step.
-
- `node_display_name` is resolved from the run's definition snapshot, so it
- reflects the name the node had when the run executed. Repeated executions of
- the same node share that name and are distinguished by `iteration`.
-
- For a higher-level view with aggregated metrics (pass rates, audio duration
- by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
- script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
-
- Parameters
- ----------
- workflow_id : str
-
- run_id : str
-
- workspace_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ApiResponseListWorkflowRunStepOut
- Successful Response
-
- Examples
- --------
- import asyncio
-
- from onepin import AsyncOnePinClient
-
- client = AsyncOnePinClient(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.workflows.get_run_steps(
- workflow_id="workflow_id",
- run_id="run_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.get_run_steps(
- workflow_id, run_id, workspace_id=workspace_id, request_options=request_options
- )
- return _response.data
-
async def get_run_outputs(
self,
workflow_id: str,
@@ -2157,7 +2091,8 @@ async def get_run_overview(
- `GET /runs/{run_id}` — full run record including the raw definition snapshot.
- `GET /runs/{run_id}/status` — volatile status fields only; for polling.
- - `GET /runs/{run_id}/steps` — flat per-node step log with audio playback URLs.
+ - `GET /runs/{run_id}/steps` — lightweight per-node step log by default;
+ `include_result=true` includes results and audio playback URLs.
- `GET /runs/{run_id}/outputs` — one logical result per snapshot sink node.
- `GET /runs/{run_id}/data` — paginated script+audio rows for a data table.
- `GET /runs/{run_id}/overview` (this endpoint) — pre-aggregated metrics and
@@ -2211,6 +2146,7 @@ async def get_run_data(
*,
search: typing.Optional[str] = None,
language: typing.Optional[str] = None,
+ include_dropped: typing.Optional[bool] = None,
offset: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
workspace_id: typing.Optional[str] = None,
@@ -2230,6 +2166,8 @@ async def get_run_data(
locale. Rows with no matching cards are still returned (with empty `cards`),
and `pagination.total` always reflects the search-filtered row count
regardless of `language`.
+ - `include_dropped=true` adds rejected attempts to `cards` with
+ `status="dropped"`; the default response remains delivered/generated data only.
**Pagination:** `pagination.total` is scoped to the `search` filter only.
@@ -2250,6 +2188,9 @@ async def get_run_data(
language : typing.Optional[str]
Exact full-locale code to filter cards within each row (e.g. `en-US`). `_` is normalized to `-`. Filtering is card-level only — rows remain visible even when all their cards are filtered out, and `pagination.total` is unaffected.
+ include_dropped : typing.Optional[bool]
+ Include validator-rejected audio cards reconstructed from unwired fail ports. Defaults to false so existing clients continue receiving delivered output only.
+
offset : typing.Optional[int]
Zero-based pagination offset.
@@ -2291,6 +2232,7 @@ async def main() -> None:
run_id,
search=search,
language=language,
+ include_dropped=include_dropped,
offset=offset,
limit=limit,
workspace_id=workspace_id,
@@ -2363,6 +2305,69 @@ async def main() -> None:
)
return _response.data
+ async def get_run_audio_url(
+ self,
+ workflow_id: str,
+ run_id: str,
+ audio_id: str,
+ *,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiResponseDownloadUrlOut:
+ """
+ Mint a fresh playback URL for one audio output of a run.
+
+ `audio_id` is the stable 16-hex output identifier embedded in run-data
+ card ids and carried by assistant chat `audio` parts. Presigned playback
+ URLs expire after 15 minutes; call this endpoint at play time to refresh
+ the URL by id instead of caching it or re-fetching a whole run-data page.
+
+ Returns 404 when the run has no s3-backed audio output with this id.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ audio_id : str
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiResponseDownloadUrlOut
+ Successful Response
+
+ Examples
+ --------
+ import asyncio
+
+ from onepin import AsyncOnePinClient
+
+ client = AsyncOnePinClient(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.workflows.get_run_audio_url(
+ workflow_id="workflow_id",
+ run_id="run_id",
+ audio_id="audio_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_run_audio_url(
+ workflow_id, run_id, audio_id, workspace_id=workspace_id, request_options=request_options
+ )
+ return _response.data
+
async def download_run_node(
self,
workflow_id: str,
diff --git a/src/onepin/workflows/raw_client.py b/src/onepin/workflows/raw_client.py
index 22b75ba..376fade 100644
--- a/src/onepin/workflows/raw_client.py
+++ b/src/onepin/workflows/raw_client.py
@@ -21,7 +21,6 @@
from ..types.api_response_dict import ApiResponseDict
from ..types.api_response_download_url_out import ApiResponseDownloadUrlOut
from ..types.api_response_estimate_response import ApiResponseEstimateResponse
-from ..types.api_response_list_workflow_run_step_out import ApiResponseListWorkflowRunStepOut
from ..types.api_response_runs_summary_out import ApiResponseRunsSummaryOut
from ..types.api_response_workflow_name_availability_out import ApiResponseWorkflowNameAvailabilityOut
from ..types.api_response_workflow_out import ApiResponseWorkflowOut
@@ -969,87 +968,6 @@ def runs_summary(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def get_run_steps(
- self,
- workflow_id: str,
- run_id: str,
- *,
- workspace_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[ApiResponseListWorkflowRunStepOut]:
- """
- List per-node execution steps for a workflow run.
-
- Returns one entry per node execution attempt, ordered by execution sequence.
- Each step includes the node type, status, iteration number (for nodes that
- are retried), start/completion timestamps, and the node's `result` output.
-
- For audio output nodes, `result` is hydrated with short-lived `playback_url`
- values (valid for 15 minutes) so callers can stream audio directly without
- a separate download step.
-
- `node_display_name` is resolved from the run's definition snapshot, so it
- reflects the name the node had when the run executed. Repeated executions of
- the same node share that name and are distinguished by `iteration`.
-
- For a higher-level view with aggregated metrics (pass rates, audio duration
- by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
- script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
-
- Parameters
- ----------
- workflow_id : str
-
- run_id : str
-
- workspace_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[ApiResponseListWorkflowRunStepOut]
- Successful Response
- """
- _response = self._client_wrapper.httpx_client.request(
- f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/steps",
- method="GET",
- headers={
- "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- ApiResponseListWorkflowRunStepOut,
- parse_obj_as(
- type_=ApiResponseListWorkflowRunStepOut, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 422:
- raise UnprocessableEntityError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Any,
- parse_obj_as(
- type_=typing.Any, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- except ValidationError as e:
- raise ParsingError(
- status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
- )
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
def get_run_outputs(
self,
workflow_id: str,
@@ -1146,7 +1064,8 @@ def get_run_overview(
- `GET /runs/{run_id}` — full run record including the raw definition snapshot.
- `GET /runs/{run_id}/status` — volatile status fields only; for polling.
- - `GET /runs/{run_id}/steps` — flat per-node step log with audio playback URLs.
+ - `GET /runs/{run_id}/steps` — lightweight per-node step log by default;
+ `include_result=true` includes results and audio playback URLs.
- `GET /runs/{run_id}/outputs` — one logical result per snapshot sink node.
- `GET /runs/{run_id}/data` — paginated script+audio rows for a data table.
- `GET /runs/{run_id}/overview` (this endpoint) — pre-aggregated metrics and
@@ -1213,6 +1132,7 @@ def get_run_data(
*,
search: typing.Optional[str] = None,
language: typing.Optional[str] = None,
+ include_dropped: typing.Optional[bool] = None,
offset: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
workspace_id: typing.Optional[str] = None,
@@ -1232,6 +1152,8 @@ def get_run_data(
locale. Rows with no matching cards are still returned (with empty `cards`),
and `pagination.total` always reflects the search-filtered row count
regardless of `language`.
+ - `include_dropped=true` adds rejected attempts to `cards` with
+ `status="dropped"`; the default response remains delivered/generated data only.
**Pagination:** `pagination.total` is scoped to the `search` filter only.
@@ -1252,6 +1174,9 @@ def get_run_data(
language : typing.Optional[str]
Exact full-locale code to filter cards within each row (e.g. `en-US`). `_` is normalized to `-`. Filtering is card-level only — rows remain visible even when all their cards are filtered out, and `pagination.total` is unaffected.
+ include_dropped : typing.Optional[bool]
+ Include validator-rejected audio cards reconstructed from unwired fail ports. Defaults to false so existing clients continue receiving delivered output only.
+
offset : typing.Optional[int]
Zero-based pagination offset.
@@ -1274,6 +1199,7 @@ def get_run_data(
params={
"search": search,
"language": language,
+ "include_dropped": include_dropped,
"offset": offset,
"limit": limit,
},
@@ -1412,6 +1338,92 @@ def download_run(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+ def get_run_audio_url(
+ self,
+ workflow_id: str,
+ run_id: str,
+ audio_id: str,
+ *,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ApiResponseDownloadUrlOut]:
+ """
+ Mint a fresh playback URL for one audio output of a run.
+
+ `audio_id` is the stable 16-hex output identifier embedded in run-data
+ card ids and carried by assistant chat `audio` parts. Presigned playback
+ URLs expire after 15 minutes; call this endpoint at play time to refresh
+ the URL by id instead of caching it or re-fetching a whole run-data page.
+
+ Returns 404 when the run has no s3-backed audio output with this id.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ audio_id : str
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ApiResponseDownloadUrlOut]
+ Successful Response
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/audio/{encode_path_param(audio_id)}/url",
+ method="GET",
+ headers={
+ "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ApiResponseDownloadUrlOut,
+ parse_obj_as(
+ type_=ApiResponseDownloadUrlOut, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 422:
+ raise UnprocessableEntityError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
def download_run_node(
self,
workflow_id: str,
@@ -2663,87 +2675,6 @@ async def runs_summary(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def get_run_steps(
- self,
- workflow_id: str,
- run_id: str,
- *,
- workspace_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[ApiResponseListWorkflowRunStepOut]:
- """
- List per-node execution steps for a workflow run.
-
- Returns one entry per node execution attempt, ordered by execution sequence.
- Each step includes the node type, status, iteration number (for nodes that
- are retried), start/completion timestamps, and the node's `result` output.
-
- For audio output nodes, `result` is hydrated with short-lived `playback_url`
- values (valid for 15 minutes) so callers can stream audio directly without
- a separate download step.
-
- `node_display_name` is resolved from the run's definition snapshot, so it
- reflects the name the node had when the run executed. Repeated executions of
- the same node share that name and are distinguished by `iteration`.
-
- For a higher-level view with aggregated metrics (pass rates, audio duration
- by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
- script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
-
- Parameters
- ----------
- workflow_id : str
-
- run_id : str
-
- workspace_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[ApiResponseListWorkflowRunStepOut]
- Successful Response
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/steps",
- method="GET",
- headers={
- "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- ApiResponseListWorkflowRunStepOut,
- parse_obj_as(
- type_=ApiResponseListWorkflowRunStepOut, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 422:
- raise UnprocessableEntityError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Any,
- parse_obj_as(
- type_=typing.Any, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- except ValidationError as e:
- raise ParsingError(
- status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
- )
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
async def get_run_outputs(
self,
workflow_id: str,
@@ -2840,7 +2771,8 @@ async def get_run_overview(
- `GET /runs/{run_id}` — full run record including the raw definition snapshot.
- `GET /runs/{run_id}/status` — volatile status fields only; for polling.
- - `GET /runs/{run_id}/steps` — flat per-node step log with audio playback URLs.
+ - `GET /runs/{run_id}/steps` — lightweight per-node step log by default;
+ `include_result=true` includes results and audio playback URLs.
- `GET /runs/{run_id}/outputs` — one logical result per snapshot sink node.
- `GET /runs/{run_id}/data` — paginated script+audio rows for a data table.
- `GET /runs/{run_id}/overview` (this endpoint) — pre-aggregated metrics and
@@ -2907,6 +2839,7 @@ async def get_run_data(
*,
search: typing.Optional[str] = None,
language: typing.Optional[str] = None,
+ include_dropped: typing.Optional[bool] = None,
offset: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
workspace_id: typing.Optional[str] = None,
@@ -2926,6 +2859,8 @@ async def get_run_data(
locale. Rows with no matching cards are still returned (with empty `cards`),
and `pagination.total` always reflects the search-filtered row count
regardless of `language`.
+ - `include_dropped=true` adds rejected attempts to `cards` with
+ `status="dropped"`; the default response remains delivered/generated data only.
**Pagination:** `pagination.total` is scoped to the `search` filter only.
@@ -2946,6 +2881,9 @@ async def get_run_data(
language : typing.Optional[str]
Exact full-locale code to filter cards within each row (e.g. `en-US`). `_` is normalized to `-`. Filtering is card-level only — rows remain visible even when all their cards are filtered out, and `pagination.total` is unaffected.
+ include_dropped : typing.Optional[bool]
+ Include validator-rejected audio cards reconstructed from unwired fail ports. Defaults to false so existing clients continue receiving delivered output only.
+
offset : typing.Optional[int]
Zero-based pagination offset.
@@ -2968,6 +2906,7 @@ async def get_run_data(
params={
"search": search,
"language": language,
+ "include_dropped": include_dropped,
"offset": offset,
"limit": limit,
},
@@ -3106,6 +3045,92 @@ async def download_run(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+ async def get_run_audio_url(
+ self,
+ workflow_id: str,
+ run_id: str,
+ audio_id: str,
+ *,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ApiResponseDownloadUrlOut]:
+ """
+ Mint a fresh playback URL for one audio output of a run.
+
+ `audio_id` is the stable 16-hex output identifier embedded in run-data
+ card ids and carried by assistant chat `audio` parts. Presigned playback
+ URLs expire after 15 minutes; call this endpoint at play time to refresh
+ the URL by id instead of caching it or re-fetching a whole run-data page.
+
+ Returns 404 when the run has no s3-backed audio output with this id.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ audio_id : str
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ApiResponseDownloadUrlOut]
+ Successful Response
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/audio/{encode_path_param(audio_id)}/url",
+ method="GET",
+ headers={
+ "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ApiResponseDownloadUrlOut,
+ parse_obj_as(
+ type_=ApiResponseDownloadUrlOut, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 422:
+ raise UnprocessableEntityError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
async def download_run_node(
self,
workflow_id: str,
diff --git a/src/onepin/workflows/runs/client.py b/src/onepin/workflows/runs/client.py
index 4e36b4f..fe403b1 100644
--- a/src/onepin/workflows/runs/client.py
+++ b/src/onepin/workflows/runs/client.py
@@ -5,9 +5,11 @@
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ...core.request_options import RequestOptions
from ...types.api_counted_list_response_workflow_run_list_item import ApiCountedListResponseWorkflowRunListItem
+from ...types.api_response_list_workflow_run_step_out import ApiResponseListWorkflowRunStepOut
from ...types.api_response_workflow_run_detail_out import ApiResponseWorkflowRunDetailOut
from ...types.api_response_workflow_run_out import ApiResponseWorkflowRunOut
from ...types.api_response_workflow_run_status_out import ApiResponseWorkflowRunStatusOut
+from ...types.node_type import NodeType
from ...types.workflow_run_start_in import WorkflowRunStartIn
from .raw_client import AsyncRawRunsClient, RawRunsClient
from .types.list_runs_request_order import ListRunsRequestOrder
@@ -201,7 +203,8 @@ def get(
This is the heaviest run endpoint. For progress polling, use the lighter
`GET /runs/{run_id}/status` which omits the snapshot. For aggregated
visual metrics, use `GET /runs/{run_id}/overview`. For the per-node step
- log with audio playback URLs, use `GET /runs/{run_id}/steps`.
+ log, use `GET /runs/{run_id}/steps`; opt into full results and audio
+ playback URLs with `include_result=true`.
Parameters
----------
@@ -296,6 +299,85 @@ def status(
)
return _response.data
+ def steps(
+ self,
+ workflow_id: str,
+ run_id: str,
+ *,
+ include_result: typing.Optional[bool] = None,
+ node_type: typing.Optional[NodeType] = None,
+ node_id: typing.Optional[str] = None,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiResponseListWorkflowRunStepOut:
+ """
+ List per-node execution steps for a workflow run.
+
+ Returns one entry per node execution attempt, ordered by execution sequence.
+ By default, the response is lightweight: `result` is null, `has_result`
+ reports whether a stored result exists, and `active_ports` is projected from
+ the result without loading the full JSON payload.
+
+ Set `include_result=true` to restore the full result payload. Audio results
+ are then hydrated with short-lived `playback_url` values (valid for 15
+ minutes). `node_type` and `node_id` filters combine with AND semantics.
+
+ `node_display_name` is resolved from the run's definition snapshot, so it
+ reflects the name the node had when the run executed. Repeated executions of
+ the same node share that name and are distinguished by `iteration`.
+
+ For a higher-level view with aggregated metrics (pass rates, audio duration
+ by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
+ script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ include_result : typing.Optional[bool]
+ Include the full step result payload and hydrate audio playback URLs.
+
+ node_type : typing.Optional[NodeType]
+ Filter steps by node type.
+
+ node_id : typing.Optional[str]
+ Filter steps by node ID.
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiResponseListWorkflowRunStepOut
+ Successful Response
+
+ Examples
+ --------
+ from onepin import OnePinClient
+
+ client = OnePinClient(
+ token="YOUR_TOKEN",
+ )
+ client.workflows.runs.steps(
+ workflow_id="workflow_id",
+ run_id="run_id",
+ )
+ """
+ _response = self._raw_client.steps(
+ workflow_id,
+ run_id,
+ include_result=include_result,
+ node_type=node_type,
+ node_id=node_id,
+ workspace_id=workspace_id,
+ request_options=request_options,
+ )
+ return _response.data
+
def cancel(
self,
workflow_id: str,
@@ -312,9 +394,9 @@ def cancel(
operation is idempotent: cancelling an already-cancelled run returns the
run unchanged without error.
- Only runs in `pending`, `running`, or `paused` status can be cancelled.
- Runs that have already reached a terminal state (`completed`, `failed`,
- `cancelled`) return 409.
+ Runs already in a terminal state (`completed`, `failed`, or `cancelled`)
+ are returned unchanged. Concurrent terminalization is also treated as an
+ idempotent success; a still-active compare-and-swap loser returns 409.
Unlike `pause`, cancel is permanent — a cancelled run cannot be resumed.
Use `pause` if you intend to continue the run later.
@@ -553,7 +635,8 @@ async def get(
This is the heaviest run endpoint. For progress polling, use the lighter
`GET /runs/{run_id}/status` which omits the snapshot. For aggregated
visual metrics, use `GET /runs/{run_id}/overview`. For the per-node step
- log with audio playback URLs, use `GET /runs/{run_id}/steps`.
+ log, use `GET /runs/{run_id}/steps`; opt into full results and audio
+ playback URLs with `include_result=true`.
Parameters
----------
@@ -664,6 +747,93 @@ async def main() -> None:
)
return _response.data
+ async def steps(
+ self,
+ workflow_id: str,
+ run_id: str,
+ *,
+ include_result: typing.Optional[bool] = None,
+ node_type: typing.Optional[NodeType] = None,
+ node_id: typing.Optional[str] = None,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ApiResponseListWorkflowRunStepOut:
+ """
+ List per-node execution steps for a workflow run.
+
+ Returns one entry per node execution attempt, ordered by execution sequence.
+ By default, the response is lightweight: `result` is null, `has_result`
+ reports whether a stored result exists, and `active_ports` is projected from
+ the result without loading the full JSON payload.
+
+ Set `include_result=true` to restore the full result payload. Audio results
+ are then hydrated with short-lived `playback_url` values (valid for 15
+ minutes). `node_type` and `node_id` filters combine with AND semantics.
+
+ `node_display_name` is resolved from the run's definition snapshot, so it
+ reflects the name the node had when the run executed. Repeated executions of
+ the same node share that name and are distinguished by `iteration`.
+
+ For a higher-level view with aggregated metrics (pass rates, audio duration
+ by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
+ script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ include_result : typing.Optional[bool]
+ Include the full step result payload and hydrate audio playback URLs.
+
+ node_type : typing.Optional[NodeType]
+ Filter steps by node type.
+
+ node_id : typing.Optional[str]
+ Filter steps by node ID.
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ApiResponseListWorkflowRunStepOut
+ Successful Response
+
+ Examples
+ --------
+ import asyncio
+
+ from onepin import AsyncOnePinClient
+
+ client = AsyncOnePinClient(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.workflows.runs.steps(
+ workflow_id="workflow_id",
+ run_id="run_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.steps(
+ workflow_id,
+ run_id,
+ include_result=include_result,
+ node_type=node_type,
+ node_id=node_id,
+ workspace_id=workspace_id,
+ request_options=request_options,
+ )
+ return _response.data
+
async def cancel(
self,
workflow_id: str,
@@ -680,9 +850,9 @@ async def cancel(
operation is idempotent: cancelling an already-cancelled run returns the
run unchanged without error.
- Only runs in `pending`, `running`, or `paused` status can be cancelled.
- Runs that have already reached a terminal state (`completed`, `failed`,
- `cancelled`) return 409.
+ Runs already in a terminal state (`completed`, `failed`, or `cancelled`)
+ are returned unchanged. Concurrent terminalization is also treated as an
+ idempotent success; a still-active compare-and-swap loser returns 409.
Unlike `pause`, cancel is permanent — a cancelled run cannot be resumed.
Use `pause` if you intend to continue the run later.
diff --git a/src/onepin/workflows/runs/raw_client.py b/src/onepin/workflows/runs/raw_client.py
index b848485..aed4559 100644
--- a/src/onepin/workflows/runs/raw_client.py
+++ b/src/onepin/workflows/runs/raw_client.py
@@ -13,9 +13,11 @@
from ...core.serialization import convert_and_respect_annotation_metadata
from ...errors.unprocessable_entity_error import UnprocessableEntityError
from ...types.api_counted_list_response_workflow_run_list_item import ApiCountedListResponseWorkflowRunListItem
+from ...types.api_response_list_workflow_run_step_out import ApiResponseListWorkflowRunStepOut
from ...types.api_response_workflow_run_detail_out import ApiResponseWorkflowRunDetailOut
from ...types.api_response_workflow_run_out import ApiResponseWorkflowRunOut
from ...types.api_response_workflow_run_status_out import ApiResponseWorkflowRunStatusOut
+from ...types.node_type import NodeType
from ...types.workflow_run_start_in import WorkflowRunStartIn
from .types.list_runs_request_order import ListRunsRequestOrder
from .types.list_runs_request_sort import ListRunsRequestSort
@@ -246,7 +248,8 @@ def get(
This is the heaviest run endpoint. For progress polling, use the lighter
`GET /runs/{run_id}/status` which omits the snapshot. For aggregated
visual metrics, use `GET /runs/{run_id}/overview`. For the per-node step
- log with audio playback URLs, use `GET /runs/{run_id}/steps`.
+ log, use `GET /runs/{run_id}/steps`; opt into full results and audio
+ playback URLs with `include_result=true`.
Parameters
----------
@@ -383,6 +386,105 @@ def status(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+ def steps(
+ self,
+ workflow_id: str,
+ run_id: str,
+ *,
+ include_result: typing.Optional[bool] = None,
+ node_type: typing.Optional[NodeType] = None,
+ node_id: typing.Optional[str] = None,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ApiResponseListWorkflowRunStepOut]:
+ """
+ List per-node execution steps for a workflow run.
+
+ Returns one entry per node execution attempt, ordered by execution sequence.
+ By default, the response is lightweight: `result` is null, `has_result`
+ reports whether a stored result exists, and `active_ports` is projected from
+ the result without loading the full JSON payload.
+
+ Set `include_result=true` to restore the full result payload. Audio results
+ are then hydrated with short-lived `playback_url` values (valid for 15
+ minutes). `node_type` and `node_id` filters combine with AND semantics.
+
+ `node_display_name` is resolved from the run's definition snapshot, so it
+ reflects the name the node had when the run executed. Repeated executions of
+ the same node share that name and are distinguished by `iteration`.
+
+ For a higher-level view with aggregated metrics (pass rates, audio duration
+ by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
+ script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ include_result : typing.Optional[bool]
+ Include the full step result payload and hydrate audio playback URLs.
+
+ node_type : typing.Optional[NodeType]
+ Filter steps by node type.
+
+ node_id : typing.Optional[str]
+ Filter steps by node ID.
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ApiResponseListWorkflowRunStepOut]
+ Successful Response
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/steps",
+ method="GET",
+ params={
+ "include_result": include_result,
+ "node_type": node_type,
+ "node_id": node_id,
+ },
+ headers={
+ "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ApiResponseListWorkflowRunStepOut,
+ parse_obj_as(
+ type_=ApiResponseListWorkflowRunStepOut, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 422:
+ raise UnprocessableEntityError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
def cancel(
self,
workflow_id: str,
@@ -399,9 +501,9 @@ def cancel(
operation is idempotent: cancelling an already-cancelled run returns the
run unchanged without error.
- Only runs in `pending`, `running`, or `paused` status can be cancelled.
- Runs that have already reached a terminal state (`completed`, `failed`,
- `cancelled`) return 409.
+ Runs already in a terminal state (`completed`, `failed`, or `cancelled`)
+ are returned unchanged. Concurrent terminalization is also treated as an
+ idempotent success; a still-active compare-and-swap loser returns 409.
Unlike `pause`, cancel is permanent — a cancelled run cannot be resumed.
Use `pause` if you intend to continue the run later.
@@ -682,7 +784,8 @@ async def get(
This is the heaviest run endpoint. For progress polling, use the lighter
`GET /runs/{run_id}/status` which omits the snapshot. For aggregated
visual metrics, use `GET /runs/{run_id}/overview`. For the per-node step
- log with audio playback URLs, use `GET /runs/{run_id}/steps`.
+ log, use `GET /runs/{run_id}/steps`; opt into full results and audio
+ playback URLs with `include_result=true`.
Parameters
----------
@@ -819,6 +922,105 @@ async def status(
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+ async def steps(
+ self,
+ workflow_id: str,
+ run_id: str,
+ *,
+ include_result: typing.Optional[bool] = None,
+ node_type: typing.Optional[NodeType] = None,
+ node_id: typing.Optional[str] = None,
+ workspace_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ApiResponseListWorkflowRunStepOut]:
+ """
+ List per-node execution steps for a workflow run.
+
+ Returns one entry per node execution attempt, ordered by execution sequence.
+ By default, the response is lightweight: `result` is null, `has_result`
+ reports whether a stored result exists, and `active_ports` is projected from
+ the result without loading the full JSON payload.
+
+ Set `include_result=true` to restore the full result payload. Audio results
+ are then hydrated with short-lived `playback_url` values (valid for 15
+ minutes). `node_type` and `node_id` filters combine with AND semantics.
+
+ `node_display_name` is resolved from the run's definition snapshot, so it
+ reflects the name the node had when the run executed. Repeated executions of
+ the same node share that name and are distinguished by `iteration`.
+
+ For a higher-level view with aggregated metrics (pass rates, audio duration
+ by language), use `GET /runs/{run_id}/overview`. For paginated, grouped
+ script+audio rows suitable for a data table, use `GET /runs/{run_id}/data`.
+
+ Parameters
+ ----------
+ workflow_id : str
+
+ run_id : str
+
+ include_result : typing.Optional[bool]
+ Include the full step result payload and hydrate audio playback URLs.
+
+ node_type : typing.Optional[NodeType]
+ Filter steps by node type.
+
+ node_id : typing.Optional[str]
+ Filter steps by node ID.
+
+ workspace_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ApiResponseListWorkflowRunStepOut]
+ Successful Response
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"api/v1/workflows/{encode_path_param(workflow_id)}/runs/{encode_path_param(run_id)}/steps",
+ method="GET",
+ params={
+ "include_result": include_result,
+ "node_type": node_type,
+ "node_id": node_id,
+ },
+ headers={
+ "X-Workspace-Id": str(workspace_id) if workspace_id is not None else None,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ApiResponseListWorkflowRunStepOut,
+ parse_obj_as(
+ type_=ApiResponseListWorkflowRunStepOut, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 422:
+ raise UnprocessableEntityError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
async def cancel(
self,
workflow_id: str,
@@ -835,9 +1037,9 @@ async def cancel(
operation is idempotent: cancelling an already-cancelled run returns the
run unchanged without error.
- Only runs in `pending`, `running`, or `paused` status can be cancelled.
- Runs that have already reached a terminal state (`completed`, `failed`,
- `cancelled`) return 409.
+ Runs already in a terminal state (`completed`, `failed`, or `cancelled`)
+ are returned unchanged. Concurrent terminalization is also treated as an
+ idempotent success; a still-active compare-and-swap loser returns 409.
Unlike `pause`, cancel is permanent — a cancelled run cannot be resumed.
Use `pause` if you intend to continue the run later.