dominus-sdk-python 4.6.0__py3-none-any.whl → 4.6.2__py3-none-any.whl

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/__init__.py CHANGED
@@ -112,6 +112,7 @@ from .namespaces.processor import ProcessorNamespace
112
112
  from .namespaces.sync import SyncNamespace
113
113
  from .namespaces.authority import AuthorityNamespace
114
114
  from .namespaces.browser import BrowserNamespace
115
+ from .namespaces.recipes import RecipesNamespace
115
116
  from .namespaces.deployer import DeployerNamespace
116
117
  from .namespaces.warden import WardenNamespace
117
118
 
@@ -164,7 +165,7 @@ from .errors import (
164
165
  TimeoutError as DominusTimeoutError,
165
166
  )
166
167
 
167
- __version__ = "4.6.0"
168
+ __version__ = "4.6.2"
168
169
  __all__ = [
169
170
  # Main SDK instance
170
171
  "dominus",
@@ -215,6 +216,7 @@ __all__ = [
215
216
  "SyncNamespace",
216
217
  "AuthorityNamespace",
217
218
  "BrowserNamespace",
219
+ "RecipesNamespace",
218
220
  "DeployerNamespace",
219
221
  "WardenNamespace",
220
222
  # AI namespace for agent-runtime operations
@@ -16,6 +16,7 @@ from .processor import ProcessorNamespace
16
16
  from .sync import SyncNamespace
17
17
  from .authority import AuthorityNamespace
18
18
  from .browser import BrowserNamespace
19
+ from .recipes import RecipesNamespace
19
20
  from .deployer import DeployerNamespace
20
21
  from .warden import WardenNamespace
21
22
  from .ai import (
@@ -44,6 +45,7 @@ __all__ = [
44
45
  "SyncNamespace",
45
46
  "AuthorityNamespace",
46
47
  "BrowserNamespace",
48
+ "RecipesNamespace",
47
49
  "DeployerNamespace",
48
50
  "WardenNamespace",
49
51
  "AiNamespace",
@@ -77,7 +77,7 @@ class BrowserNamespace:
77
77
  async def ensure_run(
78
78
  self,
79
79
  *,
80
- target: Dict[str, Any],
80
+ target: Optional[Dict[str, Any]] = None,
81
81
  idempotency_key: Optional[str] = None,
82
82
  run_kind: Optional[str] = None,
83
83
  route_label: Optional[str] = None,
@@ -92,11 +92,29 @@ class BrowserNamespace:
92
92
  org_id: Optional[str] = None,
93
93
  app_slug: Optional[str] = None,
94
94
  env: Optional[str] = None,
95
+ recipe_ref: Optional[str] = None,
96
+ recipe: Optional[Any] = None,
97
+ recipe_inputs: Optional[Dict[str, Any]] = None,
95
98
  timeout: float = 30.0,
96
99
  ) -> Dict[str, Any]:
97
100
  """
98
101
  Ensure a browser run. ``POST /api/browser/runs/ensure``.
99
102
 
103
+ ``target`` shorthand, ``recipe_ref``, or inline ``recipe`` must be
104
+ present. When ``recipe_ref`` is set, the worker resolves the
105
+ recipe through the recipe-worker, parses it, resolves variables, and
106
+ runs it through the recipe executor — supporting multi-step flows
107
+ including clicks, fills, assertions, extracts, and stash-backed
108
+ credential fills.
109
+
110
+ ``recipe`` may be an inline YAML string or JSON object for one-off
111
+ runs. Stable/shared recipes should be published and referenced via
112
+ ``recipe_ref``. Target/assertion shorthand runs are synthesized into a
113
+ ``browser-recipe-v1`` recipe internally; there is no separate runner path.
114
+
115
+ ``recipe_inputs`` supplies scalar values consumed by ``recipe-input://``
116
+ variable refs declared in the recipe's vars map.
117
+
100
118
  Browser run metadata remains browser-worker runtime state. Artifact V2
101
119
  is used for sanitized `browser-run` result payloads and, when opted-in
102
120
  via ``capture_policy["storage_state"] = "always"`` plus
@@ -109,8 +127,8 @@ class BrowserNamespace:
109
127
  lookup, returns no storage_state on first call) or an explicit
110
128
  ``session_artifact_ref`` (hard-error if the ref does not exist).
111
129
  """
112
- if not target:
113
- raise ValueError("target is required")
130
+ if not target and not recipe_ref and recipe is None:
131
+ raise ValueError("target, recipe_ref, or recipe is required")
114
132
  body = _compact({
115
133
  "idempotency_key": idempotency_key,
116
134
  "run_kind": run_kind,
@@ -127,6 +145,9 @@ class BrowserNamespace:
127
145
  "org_id": org_id,
128
146
  "app_slug": app_slug,
129
147
  "env": env,
148
+ "recipe_ref": recipe_ref,
149
+ "recipe": recipe,
150
+ "recipe_inputs": recipe_inputs,
130
151
  })
131
152
  return await self._post("/api/browser/runs/ensure", body, timeout=timeout)
132
153
 
@@ -0,0 +1,188 @@
1
+ """
2
+ Recipes Namespace - kernel-tier recipe protocol.
3
+
4
+ Routes through ``/svc/recipe/*`` on the Dominus gateway. The recipe worker
5
+ owns the type registry, JSON-Schema-based publish validation, three-tier
6
+ resolution (project -> group -> platform), and B2-backed durable storage.
7
+
8
+ Recipe types currently registered:
9
+ - browser-recipe (owned by dominus-browser-worker; body version is browser-recipe-v1)
10
+
11
+ Refs follow ``recipe://{type}/{name}[@v{N}][?tier={tier}]``.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ from ..start import Dominus
19
+
20
+
21
+ def _compact(payload: Dict[str, Any]) -> Dict[str, Any]:
22
+ return {k: v for k, v in payload.items() if v is not None and v != ""}
23
+
24
+
25
+ class RecipesNamespace:
26
+ """
27
+ Recipe worker namespace.
28
+
29
+ Usage::
30
+
31
+ types = await dominus.recipes.list_types()
32
+ await dominus.recipes.publish(
33
+ type="browser-recipe",
34
+ tier="platform",
35
+ name="health-check",
36
+ body="version: browser-recipe-v1\\nsteps:\\n - kind: goto\\n url: https://x/\\n",
37
+ )
38
+ recipe = await dominus.recipes.get(type="browser-recipe", name="health-check")
39
+ """
40
+
41
+ def __init__(self, client: "Dominus"):
42
+ self._client = client
43
+
44
+ async def _post(self, endpoint: str, body: Optional[Dict[str, Any]] = None, *, timeout: float = 30.0) -> Dict[str, Any]:
45
+ return await self._client._request(
46
+ endpoint=endpoint,
47
+ method="POST",
48
+ body=body or {},
49
+ use_gateway=True,
50
+ timeout=timeout,
51
+ )
52
+
53
+ async def _get(self, endpoint: str, *, timeout: float = 30.0) -> Dict[str, Any]:
54
+ return await self._client._request(
55
+ endpoint=endpoint,
56
+ method="GET",
57
+ use_gateway=True,
58
+ timeout=timeout,
59
+ )
60
+
61
+ async def list_types(self, *, owning_worker: Optional[str] = None, timeout: float = 15.0) -> Dict[str, Any]:
62
+ """List registered recipe types. ``GET /api/recipe/types``."""
63
+ query = f"?owning_worker={owning_worker}" if owning_worker else ""
64
+ return await self._get(f"/api/recipe/types{query}", timeout=timeout)
65
+
66
+ async def get_type(self, name: str, *, timeout: float = 15.0) -> Dict[str, Any]:
67
+ """Fetch a registered recipe type's schema. ``GET /api/recipe/types/{name}``."""
68
+ return await self._get(f"/api/recipe/types/{name}", timeout=timeout)
69
+
70
+ async def publish(
71
+ self,
72
+ *,
73
+ type: str,
74
+ tier: str,
75
+ name: str,
76
+ body: str,
77
+ description: Optional[str] = None,
78
+ timeout: float = 30.0,
79
+ ) -> Dict[str, Any]:
80
+ """Publish a recipe. ``POST /api/recipe/recipes/publish``."""
81
+ return await self._post(
82
+ "/api/recipe/recipes/publish",
83
+ _compact({
84
+ "type": type,
85
+ "tier": tier,
86
+ "name": name,
87
+ "body": body,
88
+ "description": description,
89
+ }),
90
+ timeout=timeout,
91
+ )
92
+
93
+ async def validate(
94
+ self,
95
+ *,
96
+ type: str,
97
+ body: str,
98
+ timeout: float = 15.0,
99
+ ) -> Dict[str, Any]:
100
+ """Validate a recipe body against its type schema. ``POST /api/recipe/recipes/validate``."""
101
+ return await self._post(
102
+ "/api/recipe/recipes/validate",
103
+ {"type": type, "body": body},
104
+ timeout=timeout,
105
+ )
106
+
107
+ async def deprecate(
108
+ self,
109
+ *,
110
+ type: str,
111
+ tier: str,
112
+ name: str,
113
+ version: int,
114
+ reason: Optional[str] = None,
115
+ timeout: float = 30.0,
116
+ ) -> Dict[str, Any]:
117
+ """Mark the current head recipe version deprecated. ``POST /api/recipe/recipes/deprecate``."""
118
+ return await self._post(
119
+ "/api/recipe/recipes/deprecate",
120
+ _compact({
121
+ "type": type,
122
+ "tier": tier,
123
+ "name": name,
124
+ "version": version,
125
+ "reason": reason,
126
+ }),
127
+ timeout=timeout,
128
+ )
129
+
130
+ async def list(
131
+ self,
132
+ *,
133
+ type: Optional[str] = None,
134
+ tier: Optional[str] = None,
135
+ name_prefix: Optional[str] = None,
136
+ timeout: float = 15.0,
137
+ ) -> Dict[str, Any]:
138
+ """List recipes filtered by type/tier/name. ``GET /api/recipe/recipes/list``."""
139
+ params: List[str] = []
140
+ if type:
141
+ params.append(f"type={type}")
142
+ if tier:
143
+ params.append(f"tier={tier}")
144
+ if name_prefix:
145
+ params.append(f"name_prefix={name_prefix}")
146
+ query = ("?" + "&".join(params)) if params else ""
147
+ return await self._get(f"/api/recipe/recipes/list{query}", timeout=timeout)
148
+
149
+ async def get(
150
+ self,
151
+ *,
152
+ type: str,
153
+ name: str,
154
+ version: Optional[int] = None,
155
+ tier: Optional[str] = None,
156
+ timeout: float = 15.0,
157
+ ) -> Dict[str, Any]:
158
+ """Resolve a recipe through the three-tier chain. ``GET /api/recipe/recipes/{type}/{name}[@v{N}]``."""
159
+ path = f"/api/recipe/recipes/{type}/{name}"
160
+ if version is not None:
161
+ path += f"@v{version}"
162
+ if tier:
163
+ path += f"?tier={tier}"
164
+ return await self._get(path, timeout=timeout)
165
+
166
+ async def register_type(
167
+ self,
168
+ *,
169
+ name: str,
170
+ owning_worker: str,
171
+ schema_version: int,
172
+ json_schema: Dict[str, Any],
173
+ timeout: float = 15.0,
174
+ ) -> Dict[str, Any]:
175
+ """Register a recipe type. ``POST /api/recipe/types/register``.
176
+
177
+ Owning workers do this on cold start. Normal callers should not need it.
178
+ """
179
+ return await self._post(
180
+ "/api/recipe/types/register",
181
+ {
182
+ "name": name,
183
+ "owning_worker": owning_worker,
184
+ "schema_version": schema_version,
185
+ "json_schema": json_schema,
186
+ },
187
+ timeout=timeout,
188
+ )
dominus/start.py CHANGED
@@ -186,6 +186,10 @@ class Dominus:
186
186
  from .namespaces.stash import StashNamespace
187
187
  self.stash = StashNamespace(self)
188
188
 
189
+ # Recipe worker (kernel-tier; hosts browser-recipe today, workflow + envoy + others later)
190
+ from .namespaces.recipes import RecipesNamespace
191
+ self.recipes = RecipesNamespace(self)
192
+
189
193
  # Cache for JWT public key
190
194
  self._public_key_cache = None
191
195
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 4.6.0
3
+ Version: 4.6.2
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -1,6 +1,6 @@
1
- dominus/__init__.py,sha256=8bqI4GjEUi0cQnwbcGp70gr58Xkl19opz74SN7Xf-6M,6997
1
+ dominus/__init__.py,sha256=fXMmrG8nn-vuCCSCbWfUYjZTWuTgPPgSlBERSxiba5s,7070
2
2
  dominus/errors.py,sha256=NthcR-o1Q1nQsE3ZSHStcW_RdZ8LQ06mPDSenY1txgM,8547
3
- dominus/start.py,sha256=jE4MCN-svtD7zQ83ugQ0kPmfxK4qJquDNVwXPNGNiwM,49636
3
+ dominus/start.py,sha256=Dn6uN2z0KkiJmM8rOLU20JlslZ-xhOLQb2hcJOzHEYo,49839
4
4
  dominus/config/__init__.py,sha256=nvLLNh4dM_MCqcfF3XFS2NnVn44q0RYHEfAPP-2G5To,434
5
5
  dominus/config/endpoints.py,sha256=IFioVY3jQ5Mqy65L6rNbEXyPUfYTaXRQkfyGdKv33A8,4140
6
6
  dominus/helpers/__init__.py,sha256=cyoBvw1QJugtGt0gYitIz1yxOaMmBa-wMXqbh-fi4PU,61
@@ -11,13 +11,13 @@ dominus/helpers/core.py,sha256=stpagEgsRpsXFP9_L2M-gJVo3ioSsyZm7zr8zWIyfmA,37991
11
11
  dominus/helpers/crypto.py,sha256=R1yZittVykTQzGVJdb_uMQuF3Y1uGuQRJHZ1BTWT9lU,3014
12
12
  dominus/helpers/sse.py,sha256=8cuQbonEbroho8sZhZ8kmu_IQY2lD_xNLm7FLaREwgU,5325
13
13
  dominus/helpers/trace.py,sha256=i0dRYR4Y46LAnQr0Cm5htbyZ0VA4UQCLMx-q2CQQXSc,2686
14
- dominus/namespaces/__init__.py,sha256=KfN1xDiNffNu86H8SU9dLTP5Aykmw1FhADMLTp0Z_OY,1432
14
+ dominus/namespaces/__init__.py,sha256=4zOayF2IoRHPCVpm41vBF15eoVsScIXv_BVTLsjU3bU,1494
15
15
  dominus/namespaces/admin.py,sha256=qkGoteAJ6cqdNub4zL1mtyxAQtsM3-nUplRSgw2fMZY,1640
16
16
  dominus/namespaces/ai.py,sha256=Kr_eY-SkEfC-b1fhVVv40pXn_GHkxRzMGD47WoTgu9M,48555
17
17
  dominus/namespaces/artifacts.py,sha256=MgjkjSmUP_5XGTAFU2UQ1VU3Vju3kVuvDqxChosP2J0,22246
18
18
  dominus/namespaces/auth.py,sha256=YA61WjeRewatrz6BTPhRC95jDgYk3b2QDlH0xdGUceg,67795
19
19
  dominus/namespaces/authority.py,sha256=vfXNc6A-eAeOzSuyMpBmkWjUvFVXvuelrn3O9YcIY9E,76874
20
- dominus/namespaces/browser.py,sha256=_epZQbCQKUP66CnXJLvccZGJd5TVqMy8nGpscwrqTaE,7868
20
+ dominus/namespaces/browser.py,sha256=mFxQCvwFy5XmSVIXwwOP2B5WpDnm62U-n-nDlCVn_e8,9042
21
21
  dominus/namespaces/courier.py,sha256=7ZuwTWzVGBPTnqPV1VqPdme6PkPyhQOddwaI1wxrlE8,8324
22
22
  dominus/namespaces/db.py,sha256=dv4IZACziub7OE8i_4q_Z31uVYJglE12TFkFIbFnYjw,15157
23
23
  dominus/namespaces/ddl.py,sha256=NTpd3V3595qcBheUZfFq4tQiAZsyYH9O8GR9OZ_czK8,25844
@@ -29,6 +29,7 @@ dominus/namespaces/jobs.py,sha256=YdiTzajUWtpdhk_jJhOlF0EeFegaRQFiszGSsFLs-Dc,54
29
29
  dominus/namespaces/logs.py,sha256=uM3yDU2YsqEqOt9eg1I9JyHZdHrFxSQahbknTLhmw_U,22102
30
30
  dominus/namespaces/portal.py,sha256=vf0Vu_12yS4_fto7sVCau5vQtghml7Wh7J2-XJnO2zA,15595
31
31
  dominus/namespaces/processor.py,sha256=gk-vvWfBTU9LkV34OaB4VdftArhTE67tfhlUtY0YglI,2678
32
+ dominus/namespaces/recipes.py,sha256=xqvm-aKjLy4RrFZFUc_cvr0Q7QelHd7r0OowcU_yny4,6051
32
33
  dominus/namespaces/redis.py,sha256=1joYhewLGdN4-OCYJu5rvhsF5yORUUfVtBrgjzLKAzs,19337
33
34
  dominus/namespaces/secrets.py,sha256=od8AKgENwW6U-kVfIX3DSphXKeJA6XC-SxbGqsxhhUk,6253
34
35
  dominus/namespaces/secure.py,sha256=9idGY5R6k7b-JM1SAF_1Gt-YV5OempyxFBflgLJieLo,7168
@@ -37,7 +38,7 @@ dominus/namespaces/sync.py,sha256=mGwMNwc_iWoKgS94n1staPdsKBHNvliMG7omokl7Qmk,21
37
38
  dominus/namespaces/warden.py,sha256=ebbCeBJJwK9uALEj2aDbvWJ5HTlOXOpXJOwzokH1cso,1139
38
39
  dominus/namespaces/workflow.py,sha256=1LMzlYoVImtdpnuenJDtpx7dB2wdNVE3tSBFn-ZAyJA,47204
39
40
  dominus/services/__init__.py,sha256=LQl5sx6DHhX1xCN3MRoUgffxqwm3Mfm525hijyFods8,43
40
- dominus_sdk_python-4.6.0.dist-info/METADATA,sha256=kFXogTHvSh7G8RAQwkzJxS-Jdi5DngHczEhV7auxR1M,8900
41
- dominus_sdk_python-4.6.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
42
- dominus_sdk_python-4.6.0.dist-info/top_level.txt,sha256=515zxMIbX0DpheRbjvNqKIt_AFqdFjX41jtyp_SqLf4,8
43
- dominus_sdk_python-4.6.0.dist-info/RECORD,,
41
+ dominus_sdk_python-4.6.2.dist-info/METADATA,sha256=nfp-o802nj5qms1_1exjBlmGebXLKAwYiOSiHKO4_zM,8900
42
+ dominus_sdk_python-4.6.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
43
+ dominus_sdk_python-4.6.2.dist-info/top_level.txt,sha256=515zxMIbX0DpheRbjvNqKIt_AFqdFjX41jtyp_SqLf4,8
44
+ dominus_sdk_python-4.6.2.dist-info/RECORD,,