From e6a88769a15497812142a53cbd6f05df111a08ca Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Tue, 8 Sep 2026 18:21:53 +0000 Subject: [PATCH 1/2] =?UTF-8?q?##=20Python=20SDK=20Changes:=20*=20`open=5F?= =?UTF-8?q?router.chat.send()`:=20=20=20*=20=20`request.tools[].union(Bash?= =?UTF-8?q?ServerTool).parameters.sleep=5Fafter=5Fseconds`=20**Removed**?= =?UTF-8?q?=20(Breaking=20=E2=9A=A0=EF=B8=8F)=20*=20`open=5Frouter.presets?= =?UTF-8?q?.create=5Fpresets=5Fchat=5Fcompletions()`:=20=20=20*=20=20`requ?= =?UTF-8?q?est.tools[].union(BashServerTool).parameters.sleep=5Fafter=5Fse?= =?UTF-8?q?conds`=20**Removed**=20(Breaking=20=E2=9A=A0=EF=B8=8F)=20*=20`o?= =?UTF-8?q?pen=5Frouter.presets.create=5Fpresets=5Fmessages()`:=20=20=20*?= =?UTF-8?q?=20=20`request.tools[]`=20**Changed**=20(Breaking=20=E2=9A=A0?= =?UTF-8?q?=EF=B8=8F)=20*=20`open=5Frouter.presets.create=5Fpresets=5Fresp?= =?UTF-8?q?onses()`:=20=20=20*=20=20`request.input.union(Array<>)[].union(?= =?UTF-8?q?AdditionalToolsItem).tools[]`=20**Changed**=20(Breaking=20?= =?UTF-8?q?=E2=9A=A0=EF=B8=8F)=20*=20`open=5Frouter.responses.send()`:=20?= =?UTF-8?q?=20=20*=20=20`request.input.union(Array<>)[].union(AdditionalTo?= =?UTF-8?q?olsItem).tools[]`=20**Changed**=20(Breaking=20=E2=9A=A0?= =?UTF-8?q?=EF=B8=8F)=20*=20`open=5Frouter.beta.responses.send()`:=20=20?= =?UTF-8?q?=20*=20=20`request.input.union(Array<>)[].union(AdditionalTools?= =?UTF-8?q?Item).tools[]`=20**Changed**=20(Breaking=20=E2=9A=A0=EF=B8=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .speakeasy/gen.lock | 38 +++++++++---------- .speakeasy/gen.yaml | 2 +- .speakeasy/out.openapi.yaml | 8 ---- .speakeasy/workflow.lock | 10 ++--- RELEASES.md | 12 +++++- docs/components/bashservertoolconfig.mdx | 3 +- docs/components/shellservertoolconfig.mdx | 3 +- pyproject.toml | 2 +- src/openrouter/_version.py | 4 +- .../components/bashservertoolconfig.py | 7 +--- .../components/shellservertoolconfig.py | 7 +--- uv.lock | 2 +- 12 files changed, 44 insertions(+), 54 deletions(-) diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 0fbeb559..78d76c10 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,19 +1,19 @@ lockVersion: 2.0.0 id: c48cf606-fb42-4a45-9c23-8f0555307828 management: - docChecksum: 51317d2756ce999339fd2d538c1db6be + docChecksum: 94a606e4fdc9a39db85710ea7c054812 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.1.129 - configChecksum: 8d293c073227241bd7c2a45858e9fca8 + releaseVersion: 1.1.130 + configChecksum: 18754f09025e0a8ee1ce9a1a6cf90e92 repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: e59c67e2-c33b-4b95-89e5-9e15cff5be39 - pristine_commit_hash: f9ec0ed017057f7913142675293362b6a2634014 - pristine_tree_hash: b091f1520f1d0d33c606b09a2c09dd53099204b1 + generation_id: 9c89d85b-2779-4d67-b9b2-33cf024b7310 + pristine_commit_hash: 962b4135ea52e60255067f8ae403a579b51da444 + pristine_tree_hash: d30ab3f4c6e42d8684819e923f7389270d107ad3 features: python: acceptHeaders: 3.0.0 @@ -762,8 +762,8 @@ trackedFiles: pristine_git_object: 09464da84a2c1e57d9c6d7abda98254de075a858 docs/components/bashservertoolconfig.mdx: id: 7c7f1dd1cc47 - last_write_checksum: sha1:939c847b027debc63c242238aa04fb49a015cdbc - pristine_git_object: 647f6d85e9cb54cf55b8a2c49ba1b2131993067c + last_write_checksum: sha1:296aa58396515e086ba2a46fb2ce7443dd2de1a6 + pristine_git_object: 8fba79f13d99065293ea10ed77ce5a7c2699df61 docs/components/bashservertoolengine.mdx: id: d0779ee68ded last_write_checksum: sha1:68e15335058a5c91b1e3fc74efa5e5d3767ad0fa @@ -5034,8 +5034,8 @@ trackedFiles: pristine_git_object: 0f55c3798873d7c5583fd06187cb7a9566bcc5b9 docs/components/shellservertoolconfig.mdx: id: 5958cff854db - last_write_checksum: sha1:4da377fdef8d6369232b08f31bc31153f88c8b1c - pristine_git_object: 9cac9be94ab07f98b08c3f228c043084f1ff9f4e + last_write_checksum: sha1:98ed34113e175eb52e091d2bbda831e6d47e75d3 + pristine_git_object: c42fbf09d1760c9a7bd7f0f799b43225e904e446 docs/components/shellservertoolengine.mdx: id: afea02c824ea last_write_checksum: sha1:2c179cb81f553cad5ebf67e42230b011a4e01b7f @@ -7654,8 +7654,8 @@ trackedFiles: pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:66b44b692d06091eb187caa6e31059c198395fe4 - pristine_git_object: 92be9eccaf1845a1a8a82ae10d59e590b833833c + last_write_checksum: sha1:d0a69d983b8150286f8e665cbf679306f1c8777c + pristine_git_object: ae6084af66a7ff3564a49e3332473905e91c18ca scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -7682,8 +7682,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:1a83901600daf488fb6535c60e0727a4d3b31384 - pristine_git_object: 2b55e384f9439dc2dbcb574f150d0e7501396b88 + last_write_checksum: sha1:767ef0a13aba82997f57840653f824712d7899cc + pristine_git_object: 122cff3f7fffc5fbca169d1618e53b0b881cb3a0 src/openrouter/analytics.py: id: cb406b5aaabb last_write_checksum: sha1:1e0004d8d1d5d797e2b54cd1cabeb7f9489d08e9 @@ -8030,8 +8030,8 @@ trackedFiles: pristine_git_object: b2a50762374284e45d7850991774618c9367c488 src/openrouter/components/bashservertoolconfig.py: id: c8c5bf3fd9a8 - last_write_checksum: sha1:6bf63c136f1380c5ee822973bcc8726f3327af9f - pristine_git_object: 8162bbdc3ebd5a98ce49ad2815d7a7da4430e7ce + last_write_checksum: sha1:494def579d2eacd286ccde2092ada52d8260f42f + pristine_git_object: 11bfc127e887327756d014882af7c185ff85265c src/openrouter/components/bashservertoolengine.py: id: 4648c91620a8 last_write_checksum: sha1:a4bc825f816c6207d69d3ca51098d05d14b0d69a @@ -9858,8 +9858,8 @@ trackedFiles: pristine_git_object: 0778136a1b4e03775ab17f69f3536f06e98e0cf9 src/openrouter/components/shellservertoolconfig.py: id: eab9ca1aa376 - last_write_checksum: sha1:bb1f8a303a3192f0f667eaee467dba4ef134e4e1 - pristine_git_object: c587ab9fa76a37981f7fc58b418bce9050806077 + last_write_checksum: sha1:4e138b1016d156c56e7b8d0afb90b80057bd8c7e + pristine_git_object: 71e5e8e00c8ab4522e9c4101a20406aeef8162aa src/openrouter/components/shellservertoolengine.py: id: 8a1dda027cc3 last_write_checksum: sha1:d8dd2e5aa21fd779a52853a0c496ed7a16d99bc4 @@ -12890,4 +12890,4 @@ examples: "500": application/json: {"error": {"code": 500, "message": "Internal Server Error"}} examplesVersion: 1.0.2 -releaseNotes: "## Python SDK Changes:\n* `open_router.chat.send()`: \n * `request.messages[].union(developer).configuration_update` **Added**\n* `open_router.presets.create_presets_chat_completions()`: \n * `request.messages[].union(developer).configuration_update` **Added**\n" +releaseNotes: "## Python SDK Changes:\n* `open_router.chat.send()`: \n * `request.tools[].union(BashServerTool).parameters.sleep_after_seconds` **Removed** (Breaking ⚠️)\n* `open_router.presets.create_presets_chat_completions()`: \n * `request.tools[].union(BashServerTool).parameters.sleep_after_seconds` **Removed** (Breaking ⚠️)\n* `open_router.presets.create_presets_messages()`: \n * `request.tools[]` **Changed** (Breaking ⚠️)\n* `open_router.presets.create_presets_responses()`: \n * `request.input.union(Array<>)[].union(AdditionalToolsItem).tools[]` **Changed** (Breaking ⚠️)\n* `open_router.responses.send()`: \n * `request.input.union(Array<>)[].union(AdditionalToolsItem).tools[]` **Changed** (Breaking ⚠️)\n* `open_router.beta.responses.send()`: \n * `request.input.union(Array<>)[].union(AdditionalToolsItem).tools[]` **Changed** (Breaking ⚠️)\n" diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index c49cd0df..d64a68cf 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.1.129 + version: 1.1.130 additionalDependencies: dev: {} main: {} diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index d551e908..8c4f0f7a 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -4321,8 +4321,6 @@ components: $ref: '#/components/schemas/BashServerToolEngine' environment: $ref: '#/components/schemas/BashServerToolEnvironment' - sleep_after_seconds: - $ref: '#/components/schemas/SandboxSleepAfterSeconds' type: 'object' BashServerToolEngine: description: 'Which bash engine to use. "openrouter" runs commands server-side in the OpenRouter sandbox. "auto" (default) and "native" use native passthrough, returning the tool call to your application to run client-side; OpenRouter does not execute the commands.' @@ -23841,10 +23839,6 @@ components: example: 'direct' type: 'string' x-speakeasy-unknown-values: allow - SandboxSleepAfterSeconds: - description: 'How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours).' - example: 300 - type: 'integer' ScimGroup: example: created_at: '2025-08-24T10:30:00.000Z' @@ -24385,8 +24379,6 @@ components: $ref: '#/components/schemas/ShellServerToolEngine' environment: $ref: '#/components/schemas/ShellServerToolEnvironment' - sleep_after_seconds: - $ref: '#/components/schemas/SandboxSleepAfterSeconds' type: 'object' ShellServerToolEngine: description: 'Which shell engine to use. "openrouter" runs commands server-side in the OpenRouter sandbox. "auto" (default) keeps the provider''s native hosted shell when available (OpenAI); on other providers the call is routed to the OpenRouter sandbox.' diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 065c9b62..817db04d 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -2,8 +2,8 @@ speakeasyVersion: 1.787.0 sources: OpenRouter API: sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:9db5e05ed4848a20fd8987cee486fcdfe1acd368d310f639da6037ce96d69d59 - sourceBlobDigest: sha256:f1762809ed137577f30a052de14e0956d80b24e83aed70decaeb33b2a3807d35 + sourceRevisionDigest: sha256:b7e705d1623f8a82142b1433016d2cca57aa4fa110247f0fd6f046215ff35ecc + sourceBlobDigest: sha256:ee563a24ba28a20b3bcae87eb1ac1188dff4f39a5d28b1ae6912da86f2c8d729 tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:9db5e05ed4848a20fd8987cee486fcdfe1acd368d310f639da6037ce96d69d59 - sourceBlobDigest: sha256:f1762809ed137577f30a052de14e0956d80b24e83aed70decaeb33b2a3807d35 + sourceRevisionDigest: sha256:b7e705d1623f8a82142b1433016d2cca57aa4fa110247f0fd6f046215ff35ecc + sourceBlobDigest: sha256:ee563a24ba28a20b3bcae87eb1ac1188dff4f39a5d28b1ae6912da86f2c8d729 codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:3e8664557224a8582118d35af373f2d58378188425b2cc6dddf7f249d2645087 + codeSamplesRevisionDigest: sha256:c05ec8260b9666785b692d37b4cb53f68b2a69a14e2a24bc64007be60e4a9fdc workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index ba70ca3a..468b69a2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2079,4 +2079,14 @@ Based on: ### Generated - [python v1.1.129] . ### Releases -- [PyPI v1.1.129] https://pypi.org/project/openrouter/1.1.129 - . \ No newline at end of file +- [PyPI v1.1.129] https://pypi.org/project/openrouter/1.1.129 - . + +## 2026-09-08 18:20:09 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.1.130] . +### Releases +- [PyPI v1.1.130] https://pypi.org/project/openrouter/1.1.130 - . \ No newline at end of file diff --git a/docs/components/bashservertoolconfig.mdx b/docs/components/bashservertoolconfig.mdx index 647f6d85..8fba79f1 100644 --- a/docs/components/bashservertoolconfig.mdx +++ b/docs/components/bashservertoolconfig.mdx @@ -10,5 +10,4 @@ Configuration for the openrouter:bash server tool | Field | Type | Required | Description | Example | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `engine` | [Optional[components.BashServerToolEngine]](../components/bashservertoolengine.mdx) | :heavy_minus_sign: | Which bash engine to use. "openrouter" runs commands server-side in the OpenRouter sandbox. "auto" (default) and "native" use native passthrough, returning the tool call to your application to run client-side; OpenRouter does not execute the commands. | auto | -| `environment` | [Optional[components.BashServerToolEnvironment]](../components/bashservertoolenvironment.mdx) | :heavy_minus_sign: | Execution environment for the bash server tool. | \{
"type": "container_auto"
} | -| `sleep_after_seconds` | *Optional[int]* | :heavy_minus_sign: | How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours). | 300 | \ No newline at end of file +| `environment` | [Optional[components.BashServerToolEnvironment]](../components/bashservertoolenvironment.mdx) | :heavy_minus_sign: | Execution environment for the bash server tool. | \{
"type": "container_auto"
} | \ No newline at end of file diff --git a/docs/components/shellservertoolconfig.mdx b/docs/components/shellservertoolconfig.mdx index 9cac9be9..c42fbf09 100644 --- a/docs/components/shellservertoolconfig.mdx +++ b/docs/components/shellservertoolconfig.mdx @@ -10,5 +10,4 @@ Configuration for the openrouter:shell server tool | Field | Type | Required | Description | Example | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `engine` | [Optional[components.ShellServerToolEngine]](../components/shellservertoolengine.mdx) | :heavy_minus_sign: | Which shell engine to use. "openrouter" runs commands server-side in the OpenRouter sandbox. "auto" (default) keeps the provider's native hosted shell when available (OpenAI); on other providers the call is routed to the OpenRouter sandbox. | openrouter | -| `environment` | [Optional[components.ShellServerToolEnvironment]](../components/shellservertoolenvironment.mdx) | :heavy_minus_sign: | Server-side execution environment for the shell tool. Only container-backed environments are supported; "local" shells are not. | \{
"type": "container_auto"
} | -| `sleep_after_seconds` | *Optional[int]* | :heavy_minus_sign: | How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours). | 300 | \ No newline at end of file +| `environment` | [Optional[components.ShellServerToolEnvironment]](../components/shellservertoolenvironment.mdx) | :heavy_minus_sign: | Server-side execution environment for the shell tool. Only container-backed environments are supported; "local" shells are not. | \{
"type": "container_auto"
} | \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 92be9ecc..ae6084af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.1.129" +version = "1.1.130" description = "Official Python Client SDK for OpenRouter." authors = [{ name = "OpenRouter" },] readme = "README-PYPI.md" diff --git a/src/openrouter/_version.py b/src/openrouter/_version.py index 2b55e384..122cff3f 100644 --- a/src/openrouter/_version.py +++ b/src/openrouter/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "openrouter" -__version__: str = "1.1.129" +__version__: str = "1.1.130" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.1.129 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.1.130 2.914.0 1.0.0 openrouter" try: if __package__ is not None: diff --git a/src/openrouter/components/bashservertoolconfig.py b/src/openrouter/components/bashservertoolconfig.py index 8162bbdc..11bfc127 100644 --- a/src/openrouter/components/bashservertoolconfig.py +++ b/src/openrouter/components/bashservertoolconfig.py @@ -19,8 +19,6 @@ class BashServerToolConfigTypedDict(TypedDict): r"""Which bash engine to use. \"openrouter\" runs commands server-side in the OpenRouter sandbox. \"auto\" (default) and \"native\" use native passthrough, returning the tool call to your application to run client-side; OpenRouter does not execute the commands.""" environment: NotRequired[BashServerToolEnvironmentTypedDict] r"""Execution environment for the bash server tool.""" - sleep_after_seconds: NotRequired[int] - r"""How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours).""" class BashServerToolConfig(BaseModel): @@ -32,12 +30,9 @@ class BashServerToolConfig(BaseModel): environment: Optional[BashServerToolEnvironment] = None r"""Execution environment for the bash server tool.""" - sleep_after_seconds: Optional[int] = None - r"""How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours).""" - @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = set(["engine", "environment", "sleep_after_seconds"]) + optional_fields = set(["engine", "environment"]) serialized = handler(self) m = {} diff --git a/src/openrouter/components/shellservertoolconfig.py b/src/openrouter/components/shellservertoolconfig.py index c587ab9f..71e5e8e0 100644 --- a/src/openrouter/components/shellservertoolconfig.py +++ b/src/openrouter/components/shellservertoolconfig.py @@ -19,8 +19,6 @@ class ShellServerToolConfigTypedDict(TypedDict): r"""Which shell engine to use. \"openrouter\" runs commands server-side in the OpenRouter sandbox. \"auto\" (default) keeps the provider's native hosted shell when available (OpenAI); on other providers the call is routed to the OpenRouter sandbox.""" environment: NotRequired[ShellServerToolEnvironmentTypedDict] r"""Server-side execution environment for the shell tool. Only container-backed environments are supported; \"local\" shells are not.""" - sleep_after_seconds: NotRequired[int] - r"""How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours).""" class ShellServerToolConfig(BaseModel): @@ -32,12 +30,9 @@ class ShellServerToolConfig(BaseModel): environment: Optional[ShellServerToolEnvironment] = None r"""Server-side execution environment for the shell tool. Only container-backed environments are supported; \"local\" shells are not.""" - sleep_after_seconds: Optional[int] = None - r"""How long (in seconds) the container stays warm after its last command before sleeping, freeing its capacity slot. Idle-based: each command renews the timer. Defaults to 300 (5 minutes); capped at 14400 (4 hours).""" - @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = set(["engine", "environment", "sleep_after_seconds"]) + optional_fields = set(["engine", "environment"]) serialized = handler(self) m = {} diff --git a/uv.lock b/uv.lock index 03f442f5..e99eab38 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.1.129" +version = "1.1.130" source = { editable = "." } dependencies = [ { name = "httpcore" }, From bb62655a2ebb062b42d580c87ef66ae57d3aa850 Mon Sep 17 00:00:00 2001 From: "speakeasy-github[bot]" <128539517+speakeasy-github[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 18:22:01 +0000 Subject: [PATCH 2/2] empty commit to trigger [run-tests] workflow