dominus-sdk-python 2.17.0__tar.gz → 2.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/PKG-INFO +11 -3
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/README.md +10 -2
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/__init__.py +1 -1
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/workflow.py +256 -6
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/PKG-INFO +11 -3
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/pyproject.toml +1 -1
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/tests/test_workflow_lifecycle.py +74 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/config/endpoints.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/errors.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/console_capture.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/core.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/sse.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/helpers/trace.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/__init__.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/admin.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/ai.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/artifacts.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/db.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/fastapi.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/jobs.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/open.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/__init__.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/audio_capture.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/oracle_websocket.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/session.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/types.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/vad_gate.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/portal.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/processor.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/secrets.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/secure.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/sync.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/start.py +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/SOURCES.txt +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/setup.cfg +0 -0
- {dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/tests/test_workflow_refs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.18.0
|
|
4
4
|
Summary: Python SDK for the Dominus Orchestrator Platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -49,7 +49,7 @@ Async Python SDK for CareBridge Dominus platform services. Routes calls through
|
|
|
49
49
|
- Server-side, asyncio-first Python SDK (3.9+)
|
|
50
50
|
- Namespace API with root-level shortcuts for common operations
|
|
51
51
|
- Targets production Cloudflare Workers (gateway, JWT, logs) and Cloud Run (orchestrator)
|
|
52
|
-
- Version: 2.
|
|
52
|
+
- Version: 2.18.0
|
|
53
53
|
|
|
54
54
|
## Quick Start
|
|
55
55
|
|
|
@@ -89,7 +89,15 @@ async for chunk in dominus.ai.stream_agent(
|
|
|
89
89
|
):
|
|
90
90
|
print(chunk.get("content", ""), end="", flush=True)
|
|
91
91
|
|
|
92
|
-
#
|
|
92
|
+
# Preferred Authority-backed one-call lifecycle
|
|
93
|
+
execution = await dominus.workflow.ensure(
|
|
94
|
+
"wf://carebridge/report-cycle",
|
|
95
|
+
subject="PCM47474562",
|
|
96
|
+
company="summit-radiology",
|
|
97
|
+
inputs={"report_snapshot": "ar://carebridge/summit-radiology/production/snapshot/report-1"},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Saved workflow lifecycle through workflow-manager when you need explicit artifacts
|
|
93
101
|
run = await dominus.workflow.create_run(
|
|
94
102
|
workflow_id="wf_saved_123",
|
|
95
103
|
context={"report_ref": {"report_id": "r-1", "accession": "a-1", "session_number": "2"}},
|
|
@@ -7,7 +7,7 @@ Async Python SDK for CareBridge Dominus platform services. Routes calls through
|
|
|
7
7
|
- Server-side, asyncio-first Python SDK (3.9+)
|
|
8
8
|
- Namespace API with root-level shortcuts for common operations
|
|
9
9
|
- Targets production Cloudflare Workers (gateway, JWT, logs) and Cloud Run (orchestrator)
|
|
10
|
-
- Version: 2.
|
|
10
|
+
- Version: 2.18.0
|
|
11
11
|
|
|
12
12
|
## Quick Start
|
|
13
13
|
|
|
@@ -47,7 +47,15 @@ async for chunk in dominus.ai.stream_agent(
|
|
|
47
47
|
):
|
|
48
48
|
print(chunk.get("content", ""), end="", flush=True)
|
|
49
49
|
|
|
50
|
-
#
|
|
50
|
+
# Preferred Authority-backed one-call lifecycle
|
|
51
|
+
execution = await dominus.workflow.ensure(
|
|
52
|
+
"wf://carebridge/report-cycle",
|
|
53
|
+
subject="PCM47474562",
|
|
54
|
+
company="summit-radiology",
|
|
55
|
+
inputs={"report_snapshot": "ar://carebridge/summit-radiology/production/snapshot/report-1"},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Saved workflow lifecycle through workflow-manager when you need explicit artifacts
|
|
51
59
|
run = await dominus.workflow.create_run(
|
|
52
60
|
workflow_id="wf_saved_123",
|
|
53
61
|
context={"report_ref": {"report_id": "r-1", "accession": "a-1", "session_number": "2"}},
|
|
@@ -34,6 +34,9 @@ Usage:
|
|
|
34
34
|
await dominus.workflow.validate_run(run["run_id"])
|
|
35
35
|
result = await dominus.workflow.start_run(run["run_id"], mode="async")
|
|
36
36
|
"""
|
|
37
|
+
import base64
|
|
38
|
+
import json
|
|
39
|
+
import uuid
|
|
37
40
|
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
|
38
41
|
from urllib.parse import urlencode
|
|
39
42
|
|
|
@@ -154,6 +157,90 @@ class WorkflowNamespace:
|
|
|
154
157
|
body["context"] = context
|
|
155
158
|
return body
|
|
156
159
|
|
|
160
|
+
@staticmethod
|
|
161
|
+
def _decode_authority_run_id(run_id: str) -> Optional[Dict[str, str]]:
|
|
162
|
+
normalized = str(run_id or "").strip()
|
|
163
|
+
if not normalized:
|
|
164
|
+
return None
|
|
165
|
+
try:
|
|
166
|
+
padding = "=" * ((4 - len(normalized) % 4) % 4)
|
|
167
|
+
decoded = base64.urlsafe_b64decode((normalized + padding).encode("utf-8")).decode("utf-8")
|
|
168
|
+
payload = json.loads(decoded)
|
|
169
|
+
except Exception:
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
required = ("project_id", "environment", "workflow_id", "instance_id")
|
|
173
|
+
if all(isinstance(payload.get(field), str) and str(payload.get(field)).strip() for field in required):
|
|
174
|
+
return {field: str(payload[field]).strip() for field in required}
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
def _is_authority_run_id(self, run_id: str) -> bool:
|
|
178
|
+
return self._decode_authority_run_id(run_id) is not None
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
def _authority_mutation_body(
|
|
182
|
+
body: Dict[str, Any],
|
|
183
|
+
*,
|
|
184
|
+
idempotency_key: Optional[str] = None,
|
|
185
|
+
initiator_type: Optional[str] = None,
|
|
186
|
+
initiator_id: Optional[str] = None,
|
|
187
|
+
) -> Dict[str, Any]:
|
|
188
|
+
result = dict(body)
|
|
189
|
+
if initiator_type:
|
|
190
|
+
result["initiator_type"] = initiator_type
|
|
191
|
+
if initiator_id:
|
|
192
|
+
result["initiator_id"] = initiator_id
|
|
193
|
+
result["idempotency_key"] = idempotency_key or uuid.uuid4().hex
|
|
194
|
+
return result
|
|
195
|
+
|
|
196
|
+
def _build_authority_ensure_body(
|
|
197
|
+
self,
|
|
198
|
+
workflow_id: str,
|
|
199
|
+
*,
|
|
200
|
+
workflow_ref: Optional[str] = None,
|
|
201
|
+
subject: Optional[str] = None,
|
|
202
|
+
company: Optional[str] = None,
|
|
203
|
+
inputs: Optional[Dict[str, Any]] = None,
|
|
204
|
+
context: Optional[Dict[str, Any]] = None,
|
|
205
|
+
bindings: Optional[Dict[str, Any]] = None,
|
|
206
|
+
instance_id: Optional[str] = None,
|
|
207
|
+
mode: str = "async",
|
|
208
|
+
target_project_id: Optional[str] = None,
|
|
209
|
+
target_environment: Optional[str] = None,
|
|
210
|
+
initiator_type: Optional[str] = None,
|
|
211
|
+
initiator_id: Optional[str] = None,
|
|
212
|
+
idempotency_key: Optional[str] = None,
|
|
213
|
+
) -> Dict[str, Any]:
|
|
214
|
+
body: Dict[str, Any] = {"mode": mode}
|
|
215
|
+
if workflow_ref:
|
|
216
|
+
body["workflow_ref"] = workflow_ref
|
|
217
|
+
elif self._is_workflow_ref(workflow_id):
|
|
218
|
+
body["workflow_ref"] = workflow_id
|
|
219
|
+
else:
|
|
220
|
+
body["workflow_id"] = workflow_id
|
|
221
|
+
if subject is not None:
|
|
222
|
+
body["subject"] = subject
|
|
223
|
+
if company is not None:
|
|
224
|
+
body["company"] = company
|
|
225
|
+
if inputs:
|
|
226
|
+
body["inputs"] = inputs
|
|
227
|
+
if context:
|
|
228
|
+
body["context"] = context
|
|
229
|
+
if bindings:
|
|
230
|
+
body["bindings"] = bindings
|
|
231
|
+
if instance_id:
|
|
232
|
+
body["instance_id"] = instance_id
|
|
233
|
+
if target_project_id:
|
|
234
|
+
body["target_project_id"] = target_project_id
|
|
235
|
+
if target_environment:
|
|
236
|
+
body["target_environment"] = target_environment
|
|
237
|
+
return self._authority_mutation_body(
|
|
238
|
+
body,
|
|
239
|
+
idempotency_key=idempotency_key,
|
|
240
|
+
initiator_type=initiator_type,
|
|
241
|
+
initiator_id=initiator_id,
|
|
242
|
+
)
|
|
243
|
+
|
|
157
244
|
async def _api(
|
|
158
245
|
self,
|
|
159
246
|
endpoint: str,
|
|
@@ -240,6 +327,16 @@ class WorkflowNamespace:
|
|
|
240
327
|
Returns:
|
|
241
328
|
Dict with workflow metadata and optionally content
|
|
242
329
|
"""
|
|
330
|
+
if not include_content and self._is_authority_run_id(workflow_id):
|
|
331
|
+
return await self.get_run_state(workflow_id)
|
|
332
|
+
endpoint = self._workflow_lookup_endpoint(workflow_id, include_content=include_content)
|
|
333
|
+
return await self._api(endpoint=endpoint, method="GET")
|
|
334
|
+
|
|
335
|
+
async def get_workflow(
|
|
336
|
+
self,
|
|
337
|
+
workflow_id: str,
|
|
338
|
+
include_content: bool = False,
|
|
339
|
+
) -> Dict[str, Any]:
|
|
243
340
|
endpoint = self._workflow_lookup_endpoint(workflow_id, include_content=include_content)
|
|
244
341
|
return await self._api(endpoint=endpoint, method="GET")
|
|
245
342
|
|
|
@@ -693,15 +790,56 @@ class WorkflowNamespace:
|
|
|
693
790
|
workflow_id: str,
|
|
694
791
|
*,
|
|
695
792
|
instance_id: Optional[str] = None,
|
|
696
|
-
group: str,
|
|
697
|
-
owner: str,
|
|
793
|
+
group: Optional[str] = None,
|
|
794
|
+
owner: Optional[str] = None,
|
|
698
795
|
environment: Optional[str] = None,
|
|
699
796
|
nudge_policy: Optional[Dict[str, Any]] = None,
|
|
700
797
|
bindings: Optional[Dict[str, Any]] = None,
|
|
701
798
|
mode: str = "blocking",
|
|
702
799
|
context: Optional[Dict[str, Any]] = None,
|
|
800
|
+
workflow_ref: Optional[str] = None,
|
|
801
|
+
subject: Optional[str] = None,
|
|
802
|
+
company: Optional[str] = None,
|
|
803
|
+
inputs: Optional[Dict[str, Any]] = None,
|
|
804
|
+
target_project_id: Optional[str] = None,
|
|
805
|
+
target_environment: Optional[str] = None,
|
|
806
|
+
initiator_type: Optional[str] = None,
|
|
807
|
+
initiator_id: Optional[str] = None,
|
|
808
|
+
idempotency_key: Optional[str] = None,
|
|
703
809
|
) -> Dict[str, Any]:
|
|
704
810
|
"""Ensure a workflow instance exists and optionally launch execution."""
|
|
811
|
+
if (
|
|
812
|
+
subject is not None
|
|
813
|
+
or company is not None
|
|
814
|
+
or inputs is not None
|
|
815
|
+
or workflow_ref is not None
|
|
816
|
+
or target_project_id is not None
|
|
817
|
+
or target_environment is not None
|
|
818
|
+
or initiator_type is not None
|
|
819
|
+
or initiator_id is not None
|
|
820
|
+
or idempotency_key is not None
|
|
821
|
+
or group is None
|
|
822
|
+
or owner is None
|
|
823
|
+
):
|
|
824
|
+
return await self._api(
|
|
825
|
+
endpoint="/api/authority/runs/ensure",
|
|
826
|
+
body=self._build_authority_ensure_body(
|
|
827
|
+
workflow_id,
|
|
828
|
+
workflow_ref=workflow_ref,
|
|
829
|
+
subject=subject,
|
|
830
|
+
company=company,
|
|
831
|
+
inputs=inputs,
|
|
832
|
+
context=context,
|
|
833
|
+
bindings=bindings,
|
|
834
|
+
instance_id=instance_id,
|
|
835
|
+
mode=mode,
|
|
836
|
+
target_project_id=target_project_id,
|
|
837
|
+
target_environment=target_environment,
|
|
838
|
+
initiator_type=initiator_type,
|
|
839
|
+
initiator_id=initiator_id,
|
|
840
|
+
idempotency_key=idempotency_key,
|
|
841
|
+
),
|
|
842
|
+
)
|
|
705
843
|
return await self.ensure_instance(
|
|
706
844
|
workflow_id,
|
|
707
845
|
instance_id=instance_id,
|
|
@@ -815,6 +953,50 @@ class WorkflowNamespace:
|
|
|
815
953
|
)
|
|
816
954
|
return result.get("instances", result) if isinstance(result, dict) else result
|
|
817
955
|
|
|
956
|
+
async def list_runs(
|
|
957
|
+
self,
|
|
958
|
+
*,
|
|
959
|
+
workflow_id: Optional[str] = None,
|
|
960
|
+
subject: Optional[str] = None,
|
|
961
|
+
company: Optional[str] = None,
|
|
962
|
+
status: Optional[str] = None,
|
|
963
|
+
limit: int = 50,
|
|
964
|
+
offset: int = 0,
|
|
965
|
+
target_project_id: Optional[str] = None,
|
|
966
|
+
target_environment: Optional[str] = None,
|
|
967
|
+
) -> List[Dict[str, Any]]:
|
|
968
|
+
params = [f"limit={limit}", f"offset={offset}"]
|
|
969
|
+
if workflow_id:
|
|
970
|
+
params.append(f"workflow_id={workflow_id}")
|
|
971
|
+
if subject:
|
|
972
|
+
params.append(f"owner={subject}")
|
|
973
|
+
if company:
|
|
974
|
+
params.append(f"group={company}")
|
|
975
|
+
if status:
|
|
976
|
+
params.append(f"status={status}")
|
|
977
|
+
if target_project_id:
|
|
978
|
+
params.append(f"target_project_id={target_project_id}")
|
|
979
|
+
if target_environment:
|
|
980
|
+
params.append(f"target_environment={target_environment}")
|
|
981
|
+
|
|
982
|
+
result = await self._api(
|
|
983
|
+
endpoint=f"/api/authority/runs?{'&'.join(params)}",
|
|
984
|
+
method="GET",
|
|
985
|
+
)
|
|
986
|
+
return result.get("runs", result) if isinstance(result, dict) else result
|
|
987
|
+
|
|
988
|
+
async def get_run_state(self, run_id: str) -> Dict[str, Any]:
|
|
989
|
+
return await self._api(
|
|
990
|
+
endpoint=f"/api/authority/runs/{run_id}",
|
|
991
|
+
method="GET",
|
|
992
|
+
)
|
|
993
|
+
|
|
994
|
+
async def get_run_timeline(self, run_id: str) -> Dict[str, Any]:
|
|
995
|
+
return await self._api(
|
|
996
|
+
endpoint=f"/api/authority/runs/{run_id}/timeline",
|
|
997
|
+
method="GET",
|
|
998
|
+
)
|
|
999
|
+
|
|
818
1000
|
async def get_instance_artifacts(self, workflow_id: str, instance_id: str) -> Dict[str, Any]:
|
|
819
1001
|
"""Get workflow instance artifact addresses."""
|
|
820
1002
|
from urllib.parse import quote
|
|
@@ -855,13 +1037,35 @@ class WorkflowNamespace:
|
|
|
855
1037
|
async def nudge(
|
|
856
1038
|
self,
|
|
857
1039
|
workflow_id: str,
|
|
858
|
-
instance_id: str,
|
|
1040
|
+
instance_id: Optional[str] = None,
|
|
859
1041
|
*,
|
|
860
1042
|
reason: str,
|
|
861
1043
|
trigger_artifact: Optional[str] = None,
|
|
862
1044
|
mode: str = "async",
|
|
1045
|
+
target_project_id: Optional[str] = None,
|
|
1046
|
+
target_environment: Optional[str] = None,
|
|
1047
|
+
initiator_type: Optional[str] = None,
|
|
1048
|
+
initiator_id: Optional[str] = None,
|
|
1049
|
+
idempotency_key: Optional[str] = None,
|
|
863
1050
|
) -> Dict[str, Any]:
|
|
864
1051
|
"""Nudge a workflow instance into a new execution."""
|
|
1052
|
+
if instance_id is None and self._is_authority_run_id(workflow_id):
|
|
1053
|
+
body: Dict[str, Any] = {"reason": reason, "mode": mode}
|
|
1054
|
+
if trigger_artifact:
|
|
1055
|
+
body["trigger_artifact"] = trigger_artifact
|
|
1056
|
+
if target_project_id:
|
|
1057
|
+
body["target_project_id"] = target_project_id
|
|
1058
|
+
if target_environment:
|
|
1059
|
+
body["target_environment"] = target_environment
|
|
1060
|
+
return await self._api(
|
|
1061
|
+
endpoint=f"/api/authority/runs/{workflow_id}/nudge",
|
|
1062
|
+
body=self._authority_mutation_body(
|
|
1063
|
+
body,
|
|
1064
|
+
idempotency_key=idempotency_key,
|
|
1065
|
+
initiator_type=initiator_type,
|
|
1066
|
+
initiator_id=initiator_id,
|
|
1067
|
+
),
|
|
1068
|
+
)
|
|
865
1069
|
return await self.nudge_instance(
|
|
866
1070
|
workflow_id,
|
|
867
1071
|
instance_id,
|
|
@@ -921,13 +1125,35 @@ class WorkflowNamespace:
|
|
|
921
1125
|
async def retry(
|
|
922
1126
|
self,
|
|
923
1127
|
workflow_id: str,
|
|
924
|
-
instance_id: str,
|
|
1128
|
+
instance_id: Optional[str] = None,
|
|
925
1129
|
*,
|
|
926
1130
|
reason: str = "retry",
|
|
927
1131
|
trigger_artifact: Optional[str] = None,
|
|
928
1132
|
mode: str = "async",
|
|
1133
|
+
target_project_id: Optional[str] = None,
|
|
1134
|
+
target_environment: Optional[str] = None,
|
|
1135
|
+
initiator_type: Optional[str] = None,
|
|
1136
|
+
initiator_id: Optional[str] = None,
|
|
1137
|
+
idempotency_key: Optional[str] = None,
|
|
929
1138
|
) -> Dict[str, Any]:
|
|
930
1139
|
"""Retry a workflow instance. Alias for nudge with a default retry reason."""
|
|
1140
|
+
if instance_id is None and self._is_authority_run_id(workflow_id):
|
|
1141
|
+
body: Dict[str, Any] = {"reason": reason, "mode": mode}
|
|
1142
|
+
if trigger_artifact:
|
|
1143
|
+
body["trigger_artifact"] = trigger_artifact
|
|
1144
|
+
if target_project_id:
|
|
1145
|
+
body["target_project_id"] = target_project_id
|
|
1146
|
+
if target_environment:
|
|
1147
|
+
body["target_environment"] = target_environment
|
|
1148
|
+
return await self._api(
|
|
1149
|
+
endpoint=f"/api/authority/runs/{workflow_id}/retry",
|
|
1150
|
+
body=self._authority_mutation_body(
|
|
1151
|
+
body,
|
|
1152
|
+
idempotency_key=idempotency_key,
|
|
1153
|
+
initiator_type=initiator_type,
|
|
1154
|
+
initiator_id=initiator_id,
|
|
1155
|
+
),
|
|
1156
|
+
)
|
|
931
1157
|
return await self.retry_instance(
|
|
932
1158
|
workflow_id,
|
|
933
1159
|
instance_id,
|
|
@@ -1130,8 +1356,32 @@ class WorkflowNamespace:
|
|
|
1130
1356
|
)
|
|
1131
1357
|
return result.get("events", result) if isinstance(result, dict) else result
|
|
1132
1358
|
|
|
1133
|
-
async def cancel(
|
|
1134
|
-
|
|
1359
|
+
async def cancel(
|
|
1360
|
+
self,
|
|
1361
|
+
execution_id: str,
|
|
1362
|
+
*,
|
|
1363
|
+
target_project_id: Optional[str] = None,
|
|
1364
|
+
target_environment: Optional[str] = None,
|
|
1365
|
+
initiator_type: Optional[str] = None,
|
|
1366
|
+
initiator_id: Optional[str] = None,
|
|
1367
|
+
idempotency_key: Optional[str] = None,
|
|
1368
|
+
) -> Dict[str, Any]:
|
|
1369
|
+
"""Cancel a saved-workflow execution or Authority-backed run."""
|
|
1370
|
+
if self._is_authority_run_id(execution_id):
|
|
1371
|
+
body: Dict[str, Any] = {}
|
|
1372
|
+
if target_project_id:
|
|
1373
|
+
body["target_project_id"] = target_project_id
|
|
1374
|
+
if target_environment:
|
|
1375
|
+
body["target_environment"] = target_environment
|
|
1376
|
+
return await self._api(
|
|
1377
|
+
endpoint=f"/api/authority/runs/{execution_id}/cancel",
|
|
1378
|
+
body=self._authority_mutation_body(
|
|
1379
|
+
body,
|
|
1380
|
+
idempotency_key=idempotency_key,
|
|
1381
|
+
initiator_type=initiator_type,
|
|
1382
|
+
initiator_id=initiator_id,
|
|
1383
|
+
),
|
|
1384
|
+
)
|
|
1135
1385
|
return await self._api(
|
|
1136
1386
|
endpoint=f"/api/workflow/executions/{execution_id}/cancel",
|
|
1137
1387
|
body={},
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.18.0
|
|
4
4
|
Summary: Python SDK for the Dominus Orchestrator Platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License: Proprietary
|
|
@@ -49,7 +49,7 @@ Async Python SDK for CareBridge Dominus platform services. Routes calls through
|
|
|
49
49
|
- Server-side, asyncio-first Python SDK (3.9+)
|
|
50
50
|
- Namespace API with root-level shortcuts for common operations
|
|
51
51
|
- Targets production Cloudflare Workers (gateway, JWT, logs) and Cloud Run (orchestrator)
|
|
52
|
-
- Version: 2.
|
|
52
|
+
- Version: 2.18.0
|
|
53
53
|
|
|
54
54
|
## Quick Start
|
|
55
55
|
|
|
@@ -89,7 +89,15 @@ async for chunk in dominus.ai.stream_agent(
|
|
|
89
89
|
):
|
|
90
90
|
print(chunk.get("content", ""), end="", flush=True)
|
|
91
91
|
|
|
92
|
-
#
|
|
92
|
+
# Preferred Authority-backed one-call lifecycle
|
|
93
|
+
execution = await dominus.workflow.ensure(
|
|
94
|
+
"wf://carebridge/report-cycle",
|
|
95
|
+
subject="PCM47474562",
|
|
96
|
+
company="summit-radiology",
|
|
97
|
+
inputs={"report_snapshot": "ar://carebridge/summit-radiology/production/snapshot/report-1"},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Saved workflow lifecycle through workflow-manager when you need explicit artifacts
|
|
93
101
|
run = await dominus.workflow.create_run(
|
|
94
102
|
workflow_id="wf_saved_123",
|
|
95
103
|
context={"report_ref": {"report_id": "r-1", "accession": "a-1", "session_number": "2"}},
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
|
+
import base64
|
|
3
|
+
import json
|
|
2
4
|
|
|
3
5
|
from dominus.namespaces.ai import WorkflowSubNamespace
|
|
4
6
|
from dominus.namespaces.workflow import WorkflowNamespace
|
|
@@ -53,6 +55,18 @@ class FakeClient:
|
|
|
53
55
|
yield chunk
|
|
54
56
|
|
|
55
57
|
|
|
58
|
+
def authority_run_id(**overrides):
|
|
59
|
+
payload = {
|
|
60
|
+
"project_id": "proj-1",
|
|
61
|
+
"environment": "production",
|
|
62
|
+
"workflow_id": "wf-instance",
|
|
63
|
+
"instance_id": "inst-1",
|
|
64
|
+
}
|
|
65
|
+
payload.update(overrides)
|
|
66
|
+
encoded = base64.urlsafe_b64encode(json.dumps(payload).encode("utf-8")).decode("utf-8")
|
|
67
|
+
return encoded.rstrip("=")
|
|
68
|
+
|
|
69
|
+
|
|
56
70
|
@pytest.mark.asyncio
|
|
57
71
|
async def test_ai_workflow_create_run_requires_inline_definition():
|
|
58
72
|
namespace = WorkflowSubNamespace(FakeClient())
|
|
@@ -253,6 +267,66 @@ async def test_saved_workflow_facade_lifecycle_contract_supports_processor_shape
|
|
|
253
267
|
assert streamed == [{"_event": "workflow_start"}]
|
|
254
268
|
|
|
255
269
|
|
|
270
|
+
@pytest.mark.asyncio
|
|
271
|
+
async def test_workflow_ensure_supports_authority_one_call_lifecycle():
|
|
272
|
+
client = FakeClient()
|
|
273
|
+
namespace = WorkflowNamespace(client)
|
|
274
|
+
|
|
275
|
+
await namespace.ensure(
|
|
276
|
+
"wf://carebridge/report-cycle",
|
|
277
|
+
subject="PCM47474562",
|
|
278
|
+
company="summit-radiology",
|
|
279
|
+
inputs={"report_snapshot": "ar://artifact"},
|
|
280
|
+
target_project_id="proj-1",
|
|
281
|
+
target_environment="production",
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
assert client.calls[0]["endpoint"] == "/api/authority/runs/ensure"
|
|
285
|
+
body = client.calls[0]["body"]
|
|
286
|
+
assert body["workflow_ref"] == "wf://carebridge/report-cycle"
|
|
287
|
+
assert body["subject"] == "PCM47474562"
|
|
288
|
+
assert body["company"] == "summit-radiology"
|
|
289
|
+
assert body["inputs"] == {"report_snapshot": "ar://artifact"}
|
|
290
|
+
assert body["target_project_id"] == "proj-1"
|
|
291
|
+
assert body["target_environment"] == "production"
|
|
292
|
+
assert isinstance(body["idempotency_key"], str) and body["idempotency_key"]
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
@pytest.mark.asyncio
|
|
296
|
+
async def test_workflow_get_detects_authority_run_ids():
|
|
297
|
+
client = FakeClient()
|
|
298
|
+
namespace = WorkflowNamespace(client)
|
|
299
|
+
run_id = authority_run_id()
|
|
300
|
+
|
|
301
|
+
await namespace.get(run_id)
|
|
302
|
+
|
|
303
|
+
assert client.calls[0]["endpoint"] == f"/api/authority/runs/{run_id}"
|
|
304
|
+
assert client.calls[0]["method"] == "GET"
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@pytest.mark.asyncio
|
|
308
|
+
async def test_workflow_retry_nudge_and_cancel_support_authority_run_ids():
|
|
309
|
+
client = FakeClient()
|
|
310
|
+
namespace = WorkflowNamespace(client)
|
|
311
|
+
run_id = authority_run_id()
|
|
312
|
+
|
|
313
|
+
await namespace.retry(run_id, reason="manual-retry")
|
|
314
|
+
await namespace.nudge(run_id, reason="new-input", trigger_artifact="artifact-1")
|
|
315
|
+
await namespace.cancel(run_id)
|
|
316
|
+
|
|
317
|
+
assert [call["endpoint"] for call in client.calls] == [
|
|
318
|
+
f"/api/authority/runs/{run_id}/retry",
|
|
319
|
+
f"/api/authority/runs/{run_id}/nudge",
|
|
320
|
+
f"/api/authority/runs/{run_id}/cancel",
|
|
321
|
+
]
|
|
322
|
+
assert client.calls[0]["body"]["reason"] == "manual-retry"
|
|
323
|
+
assert client.calls[1]["body"]["reason"] == "new-input"
|
|
324
|
+
assert client.calls[1]["body"]["trigger_artifact"] == "artifact-1"
|
|
325
|
+
assert isinstance(client.calls[0]["body"]["idempotency_key"], str)
|
|
326
|
+
assert isinstance(client.calls[1]["body"]["idempotency_key"], str)
|
|
327
|
+
assert isinstance(client.calls[2]["body"]["idempotency_key"], str)
|
|
328
|
+
|
|
329
|
+
|
|
256
330
|
@pytest.mark.asyncio
|
|
257
331
|
async def test_execute_pipeline_routes_to_native_pipeline_runner():
|
|
258
332
|
client = FakeClient()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/__init__.py
RENAMED
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/audio_capture.py
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/session.py
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus/namespaces/oracle/vad_gate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-2.17.0 → dominus_sdk_python-2.18.0}/dominus_sdk_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|