harnesslayer 0.1.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.
Files changed (48) hide show
  1. harnesslayer-0.1.0/.gitignore +10 -0
  2. harnesslayer-0.1.0/.python-version +1 -0
  3. harnesslayer-0.1.0/PKG-INFO +87 -0
  4. harnesslayer-0.1.0/README.md +68 -0
  5. harnesslayer-0.1.0/pyproject.toml +36 -0
  6. harnesslayer-0.1.0/src/harnesslayer/__init__.py +15 -0
  7. harnesslayer-0.1.0/src/harnesslayer/_internal/__init__.py +1 -0
  8. harnesslayer-0.1.0/src/harnesslayer/_internal/constants.py +7 -0
  9. harnesslayer-0.1.0/src/harnesslayer/_internal/transport.py +103 -0
  10. harnesslayer-0.1.0/src/harnesslayer/_internal/utils.py +21 -0
  11. harnesslayer-0.1.0/src/harnesslayer/client.py +67 -0
  12. harnesslayer-0.1.0/src/harnesslayer/exceptions.py +14 -0
  13. harnesslayer-0.1.0/src/harnesslayer/models/__init__.py +1 -0
  14. harnesslayer-0.1.0/src/harnesslayer/models/access_group.py +32 -0
  15. harnesslayer-0.1.0/src/harnesslayer/models/app.py +124 -0
  16. harnesslayer-0.1.0/src/harnesslayer/models/channel.py +123 -0
  17. harnesslayer-0.1.0/src/harnesslayer/models/conflict.py +38 -0
  18. harnesslayer-0.1.0/src/harnesslayer/models/instance.py +51 -0
  19. harnesslayer-0.1.0/src/harnesslayer/models/profile.py +61 -0
  20. harnesslayer-0.1.0/src/harnesslayer/models/response.py +12 -0
  21. harnesslayer-0.1.0/src/harnesslayer/models/session.py +33 -0
  22. harnesslayer-0.1.0/src/harnesslayer/models/version.py +39 -0
  23. harnesslayer-0.1.0/src/harnesslayer/py.typed +1 -0
  24. harnesslayer-0.1.0/src/harnesslayer/resources/__init__.py +1 -0
  25. harnesslayer-0.1.0/src/harnesslayer/resources/_base.py +18 -0
  26. harnesslayer-0.1.0/src/harnesslayer/resources/access_group.py +137 -0
  27. harnesslayer-0.1.0/src/harnesslayer/resources/app.py +183 -0
  28. harnesslayer-0.1.0/src/harnesslayer/resources/channel.py +229 -0
  29. harnesslayer-0.1.0/src/harnesslayer/resources/conflict.py +56 -0
  30. harnesslayer-0.1.0/src/harnesslayer/resources/instance.py +55 -0
  31. harnesslayer-0.1.0/src/harnesslayer/resources/profile.py +87 -0
  32. harnesslayer-0.1.0/src/harnesslayer/resources/session.py +113 -0
  33. harnesslayer-0.1.0/src/harnesslayer/resources/state.py +316 -0
  34. harnesslayer-0.1.0/src/harnesslayer/resources/version.py +298 -0
  35. harnesslayer-0.1.0/src/harnesslayer/version.py +1 -0
  36. harnesslayer-0.1.0/tests/claude/.claude/agent.json +14 -0
  37. harnesslayer-0.1.0/tests/claude/.claude/environment.json +9 -0
  38. harnesslayer-0.1.0/tests/claude/quick_start_claude.py +81 -0
  39. harnesslayer-0.1.0/tests/openclaw/.openclaw/openclaw.json +94 -0
  40. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/AGENTS.md +212 -0
  41. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/BOOTSTRAP.md +55 -0
  42. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/HEARTBEAT.md +5 -0
  43. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/IDENTITY.md +23 -0
  44. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/SOUL.md +36 -0
  45. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/TOOLS.md +40 -0
  46. harnesslayer-0.1.0/tests/openclaw/.openclaw/workspace/USER.md +17 -0
  47. harnesslayer-0.1.0/tests/openclaw/quick_start_openclaw.py +18 -0
  48. harnesslayer-0.1.0/tests/test_app_init.py +79 -0
@@ -0,0 +1,10 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: harnesslayer
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the Harnesslayer API.
5
+ Project-URL: Homepage, https://www.harnesslayer.ai/
6
+ Author: Harnesslayer
7
+ Keywords: api-client,harnesslayer,sdk
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: httpx<1.0,>=0.27
18
+ Description-Content-Type: text/markdown
19
+
20
+ ## Harnesslayer - Python
21
+
22
+ Python SDK for the Harnesslayer API.
23
+
24
+ ### Install
25
+
26
+ ```bash
27
+ pip install harnesslayer
28
+ ```
29
+
30
+ ### Quick Start
31
+
32
+ ```python
33
+ from harnesslayer import Harnesslayer
34
+
35
+ client = Harnesslayer(api_key="your-api-key")
36
+
37
+ app = client.app.init("typedef-app",
38
+ type="claude",
39
+ version_path=".claude"
40
+ )
41
+
42
+ channel = app.channel.init("my-api",
43
+ type="api"
44
+ )
45
+
46
+ stream = channel.run(
47
+ session_id="my-custom-session-id",
48
+ user_id="stephen@pickaxe.co",
49
+ input="hello world"
50
+ )
51
+
52
+ for event in stream:
53
+ if event.done:
54
+ break
55
+
56
+ print(event)
57
+
58
+ ```
59
+
60
+ ### Using A Context Manager
61
+
62
+ ```python
63
+ from harnesslayer import Harnesslayer
64
+
65
+ with Harnesslayer(api_key="your-api-key") as client:
66
+ app = client.app.init("typedef-app",
67
+ type="claude",
68
+ version_path=".claude"
69
+ )
70
+
71
+ channel = app.channel.init("my-api",
72
+ type="api"
73
+ )
74
+
75
+ stream = channel.run(
76
+ session_id="my-custom-session-id",
77
+ user_id="stephen@pickaxe.co",
78
+ input="hello world"
79
+ )
80
+
81
+ for event in stream:
82
+ if event.done:
83
+ break
84
+
85
+ print(event)
86
+
87
+ ```
@@ -0,0 +1,68 @@
1
+ ## Harnesslayer - Python
2
+
3
+ Python SDK for the Harnesslayer API.
4
+
5
+ ### Install
6
+
7
+ ```bash
8
+ pip install harnesslayer
9
+ ```
10
+
11
+ ### Quick Start
12
+
13
+ ```python
14
+ from harnesslayer import Harnesslayer
15
+
16
+ client = Harnesslayer(api_key="your-api-key")
17
+
18
+ app = client.app.init("typedef-app",
19
+ type="claude",
20
+ version_path=".claude"
21
+ )
22
+
23
+ channel = app.channel.init("my-api",
24
+ type="api"
25
+ )
26
+
27
+ stream = channel.run(
28
+ session_id="my-custom-session-id",
29
+ user_id="stephen@pickaxe.co",
30
+ input="hello world"
31
+ )
32
+
33
+ for event in stream:
34
+ if event.done:
35
+ break
36
+
37
+ print(event)
38
+
39
+ ```
40
+
41
+ ### Using A Context Manager
42
+
43
+ ```python
44
+ from harnesslayer import Harnesslayer
45
+
46
+ with Harnesslayer(api_key="your-api-key") as client:
47
+ app = client.app.init("typedef-app",
48
+ type="claude",
49
+ version_path=".claude"
50
+ )
51
+
52
+ channel = app.channel.init("my-api",
53
+ type="api"
54
+ )
55
+
56
+ stream = channel.run(
57
+ session_id="my-custom-session-id",
58
+ user_id="stephen@pickaxe.co",
59
+ input="hello world"
60
+ )
61
+
62
+ for event in stream:
63
+ if event.done:
64
+ break
65
+
66
+ print(event)
67
+
68
+ ```
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "harnesslayer"
7
+ dynamic = ["version"]
8
+ description = "Python SDK for the Harnesslayer API."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "httpx>=0.27,<1.0",
13
+ ]
14
+ authors = [
15
+ { name = "Harnesslayer" },
16
+ ]
17
+ keywords = ["harnesslayer", "sdk", "api-client"]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Intended Audience :: Developers",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://www.harnesslayer.ai/"
31
+
32
+ [tool.hatch.version]
33
+ path = "src/harnesslayer/version.py"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["src/harnesslayer"]
@@ -0,0 +1,15 @@
1
+ from .client import Harnesslayer
2
+ from .exceptions import (
3
+ HarnesslayerAPIError,
4
+ HarnesslayerError,
5
+ HarnesslayerHTTPError,
6
+ HarnesslayerResponseError,
7
+ )
8
+
9
+ __all__ = [
10
+ "Harnesslayer",
11
+ "HarnesslayerError",
12
+ "HarnesslayerHTTPError",
13
+ "HarnesslayerResponseError",
14
+ "HarnesslayerAPIError",
15
+ ]
@@ -0,0 +1 @@
1
+ """Internal Harnesslayer SDK implementation details."""
@@ -0,0 +1,7 @@
1
+ DEFAULT_API_BASE_URL = "https://api.harnesslayer.ai"
2
+
3
+ GCS_BUCKET_NAME = "harnesslayer"
4
+
5
+ AVAILABLE_APP_TYPES = ("claude", "openclaw")
6
+
7
+ AVAILABLE_CHANNEL_TYPES = ("api", "imessage")
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal, cast
4
+ import httpx
5
+
6
+ from .utils import logger
7
+ from ..exceptions import (
8
+ HarnesslayerAPIError,
9
+ HarnesslayerHTTPError,
10
+ HarnesslayerResponseError
11
+ )
12
+
13
+ Method = Literal["GET", "POST", "PUT", "PATCH", "DELETE"]
14
+
15
+ class Transport:
16
+ def __init__(
17
+ self,
18
+ *,
19
+ base_url: str,
20
+ api_key: str,
21
+ timeout: float,
22
+ user_agent: str,
23
+ http_client: httpx.Client | None = None,
24
+ ) -> None:
25
+ self.timeout = timeout
26
+ self._headers = {
27
+ "Authorization": f"Bearer {api_key}",
28
+ "Content-Type": "application/json",
29
+ "Accept": "application/json",
30
+ "User-Agent": user_agent,
31
+ }
32
+ self._owns_http_client = http_client is None
33
+ self._http = http_client or httpx.Client(
34
+ base_url=base_url,
35
+ timeout=timeout,
36
+ headers=self._headers,
37
+ )
38
+
39
+ @property
40
+ def headers(self) -> dict[str, str]:
41
+ return self._headers.copy()
42
+
43
+ def close(self) -> None:
44
+ if self._owns_http_client:
45
+ self._http.close()
46
+
47
+ @staticmethod
48
+ def _parse_response(response: httpx.Response) -> dict[str, Any]:
49
+ try:
50
+ decoded = response.json()
51
+ except ValueError as exc:
52
+ raise HarnesslayerResponseError(
53
+ f"Harnesslayer API returned non-JSON response (status={response.status_code})"
54
+ ) from exc
55
+
56
+ if not isinstance(decoded, dict):
57
+ raise HarnesslayerResponseError(
58
+ "Harnesslayer API returned an unexpected response payload"
59
+ )
60
+
61
+ return cast(dict[str, Any], decoded)
62
+
63
+ def request(
64
+ self,
65
+ method: Method,
66
+ path: str,
67
+ payload: dict[str, Any] | None = None,
68
+ ) -> dict[str, Any]:
69
+ payload = payload or {}
70
+
71
+ try:
72
+ kwargs: dict[str, Any] = {
73
+ "method": method,
74
+ "url": path.lstrip("/"),
75
+ "headers": self._headers,
76
+ }
77
+ if method == "GET":
78
+ kwargs["params"] = payload
79
+ else:
80
+ kwargs["json"] = payload
81
+
82
+ response = self._http.request(**kwargs)
83
+ except httpx.HTTPError as exc:
84
+ raise HarnesslayerHTTPError(f"HTTP request failed: {exc}") from exc
85
+
86
+ data = self._parse_response(response)
87
+
88
+ logger.debug(
89
+ "Received response from Harnesslayer API (status=%d, data=%s)",
90
+ response.status_code,
91
+ data,
92
+ )
93
+
94
+ if response.status_code >= 400:
95
+ raise HarnesslayerAPIError(
96
+ f"Harnesslayer API returned error status {response.status_code}: {data}"
97
+ )
98
+
99
+ if data.get("success") is False:
100
+ message = str(data.get("error") or data.get("message") or "Request failed")
101
+ raise HarnesslayerAPIError(f"Harnesslayer API error: {message}")
102
+
103
+ return data
@@ -0,0 +1,21 @@
1
+ import logging
2
+ import json
3
+
4
+ logger = logging.getLogger("harnesslayer")
5
+ logger.setLevel(logging.WARNING)
6
+ logger.addHandler(logging.NullHandler())
7
+
8
+ logging.basicConfig(
9
+ format="[%(funcName)s][%(asctime)s]: %(levelname)s %(message)s",
10
+ datefmt="%m/%d/%Y %H:%M:%S",
11
+ )
12
+
13
+ def set_debug(enabled: bool) -> None:
14
+ logger.setLevel(logging.INFO if enabled else logging.WARNING)
15
+
16
+ def safe_parse_json(raw: str):
17
+ try:
18
+ return json.loads(raw)
19
+ except Exception as e:
20
+ logger.error("Failed to parse JSON: %s", e)
21
+ return None
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal
4
+
5
+ import httpx
6
+
7
+ from ._internal.constants import DEFAULT_API_BASE_URL
8
+ from ._internal.utils import logger, set_debug
9
+ from ._internal.transport import Method, Transport
10
+ from .resources.app import HarnesslayerApp
11
+ from .version import __version__
12
+
13
+ class Harnesslayer:
14
+ def __init__(
15
+ self,
16
+ api_key: str,
17
+ *,
18
+ version: Literal["v1"] = "v1",
19
+ timeout: float = 30.0,
20
+ debug: bool = False,
21
+ http_client: httpx.Client | None = None,
22
+ ) -> None:
23
+ self.debug = debug
24
+ set_debug(self.debug)
25
+
26
+ logger.info("Initializing Harnesslayer client with provided API key")
27
+
28
+ trimmed_key = api_key.strip()
29
+ if not trimmed_key:
30
+ raise ValueError("api_key must be provided")
31
+ if not trimmed_key.startswith("dk-"):
32
+ raise ValueError("Invalid Harnesslayer API key")
33
+
34
+ self.api_key = trimmed_key
35
+ self.version = version
36
+ self.timeout = timeout
37
+ self.base_url = f"{DEFAULT_API_BASE_URL}/{self.version}"
38
+
39
+ self._transport = Transport(
40
+ base_url=self.base_url,
41
+ api_key=self.api_key,
42
+ timeout=self.timeout,
43
+ user_agent=f"Harnesslayer-python/{__version__}",
44
+ http_client=http_client,
45
+ )
46
+
47
+ def close(self) -> None:
48
+ self._transport.close()
49
+
50
+ def __enter__(self) -> "Harnesslayer":
51
+ return self
52
+
53
+ def __exit__(self, *_: object) -> None:
54
+ self.close()
55
+
56
+ def _request(
57
+ self,
58
+ method: Method,
59
+ path: str,
60
+ payload: dict[str, Any] | None = None,
61
+ ) -> dict[str, Any]:
62
+ return self._transport.request(method, path, payload)
63
+
64
+ @property
65
+ def app(self) -> HarnesslayerApp:
66
+ return HarnesslayerApp(self)
67
+
@@ -0,0 +1,14 @@
1
+ class HarnesslayerError(Exception):
2
+ """Base exception for the Harnesslayer SDK."""
3
+
4
+
5
+ class HarnesslayerHTTPError(HarnesslayerError):
6
+ """Raised when the underlying HTTP request fails."""
7
+
8
+
9
+ class HarnesslayerResponseError(HarnesslayerError):
10
+ """Raised when an API response cannot be parsed as expected."""
11
+
12
+
13
+ class HarnesslayerAPIError(HarnesslayerError):
14
+ """Raised when the Harnesslayer API returns an error."""
@@ -0,0 +1 @@
1
+ """Harnesslayer SDK models."""
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any, Literal, Mapping
6
+
7
+ AccessGroupLimitReset = Literal["daily", "monthly", "yearly"]
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class HarnesslayerAccessGroupModel:
12
+ id: str
13
+ appId: str
14
+ name: str
15
+ limit: int
16
+ limitReset: AccessGroupLimitReset
17
+ limitMessage: str
18
+ createdAt: datetime
19
+ updatedAt: datetime
20
+
21
+ @classmethod
22
+ def _from_api(cls, payload: Mapping[str, Any]) -> "HarnesslayerAccessGroupModel":
23
+ return cls(
24
+ id=payload["id"],
25
+ appId=payload["appId"],
26
+ name=payload["name"],
27
+ limit=payload["limit"],
28
+ limitReset=payload["limitReset"],
29
+ limitMessage=payload["limitMessage"],
30
+ createdAt=datetime.fromisoformat(payload["createdAt"]),
31
+ updatedAt=datetime.fromisoformat(payload["updatedAt"]),
32
+ )
@@ -0,0 +1,124 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Literal,
9
+ Mapping,
10
+ Optional,
11
+ TypedDict,
12
+ Union,
13
+ Required,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from ..resources.access_group import HarnesslayerAccessGroup
18
+ from ..resources.version import HarnesslayerVersion
19
+ from ..resources.channel import HarnesslayerChannel
20
+ from ..resources.session import HarnesslayerSession
21
+ from ..resources.profile import HarnesslayerProfile
22
+ from ..resources.instance import HarnesslayerInstance
23
+ from ..resources.conflict import HarnesslayerConflict
24
+
25
+ ApplicationType = Literal["claude", "openclaw"]
26
+
27
+ class AppInitLimit(TypedDict):
28
+ name: Optional[str]
29
+ amount: Required[int]
30
+ interval: Required[Literal["daily", "weekly", "monthly"]]
31
+ message: Optional[str]
32
+
33
+ class AppInitCredentialMCPOAuthNoneParam(TypedDict):
34
+ type: Required[Literal["none"]]
35
+
36
+ class AppInitCredentialMCPOAuthBasicParam(TypedDict):
37
+ type: Required[Literal["client_secret_basic"]]
38
+ client_secret: Required[str]
39
+
40
+ class AppInitCredentialMCPOAuthPostParam(TypedDict):
41
+ type: Required[Literal["client_secret_post"]]
42
+ client_secret: Required[str]
43
+
44
+ class AppInitCredentialMCPOAuthRefresh(TypedDict):
45
+ client_id: Required[str]
46
+ refresh_token: Required[str]
47
+ token_endpoint: Required[str]
48
+ token_endpoint_auth: Required[Union[
49
+ AppInitCredentialMCPOAuthNoneParam,
50
+ AppInitCredentialMCPOAuthBasicParam,
51
+ AppInitCredentialMCPOAuthPostParam,
52
+ ]]
53
+ resource: Optional[str]
54
+ scope: Optional[str]
55
+
56
+ class AppInitCredentialMCPOAuth(TypedDict):
57
+ access_token: Required[str]
58
+ mcp_server_url: Required[str]
59
+ type: Required[Literal["mcp_oauth"]]
60
+ expires_at: Optional[datetime]
61
+ refresh: Optional[AppInitCredentialMCPOAuthRefresh]
62
+
63
+ class AppInitCredentialMCPStaticBearer(TypedDict):
64
+ token: Required[str]
65
+ mcp_server_url: Required[str]
66
+ type: Required[Literal["mcp_oauth"]]
67
+
68
+ AppInitCredential = Union[AppInitCredentialMCPOAuth, AppInitCredentialMCPStaticBearer]
69
+
70
+ @dataclass(frozen=True, slots=True)
71
+ class HarnesslayerAppModel:
72
+ id: str
73
+ orgId: str
74
+ type: ApplicationType
75
+ name: str
76
+ slug: str
77
+ vaultId: str
78
+ defaultAccessGroupId: str
79
+ headVersionId: Optional[str]
80
+ metadata: Optional[dict[str, str]]
81
+ createdAt: datetime
82
+ updatedAt: datetime
83
+
84
+ version: HarnesslayerVersion
85
+ channel: HarnesslayerChannel
86
+ session: HarnesslayerSession
87
+ access_group: HarnesslayerAccessGroup
88
+ profile: HarnesslayerProfile
89
+ instance: HarnesslayerInstance
90
+ conflict: HarnesslayerConflict
91
+
92
+ @classmethod
93
+ def _from_api(
94
+ cls,
95
+ payload: Mapping[str, Any],
96
+ version: HarnesslayerVersion,
97
+ channel: HarnesslayerChannel,
98
+ session: HarnesslayerSession,
99
+ access_group: HarnesslayerAccessGroup,
100
+ profile: HarnesslayerProfile,
101
+ instance: HarnesslayerInstance,
102
+ conflict: HarnesslayerConflict,
103
+ ) -> "HarnesslayerAppModel":
104
+ return cls(
105
+ id=payload["id"],
106
+ orgId=payload["orgId"],
107
+ type=payload["type"],
108
+ name=payload["name"],
109
+ slug=payload["slug"],
110
+ vaultId=payload["vaultId"],
111
+ defaultAccessGroupId=payload["defaultAccessGroupId"],
112
+ headVersionId=payload.get("headVersionId"),
113
+ metadata=payload.get("metadata"),
114
+ createdAt=datetime.fromisoformat(payload["createdAt"]),
115
+ updatedAt=datetime.fromisoformat(payload["updatedAt"]),
116
+
117
+ version=version,
118
+ channel=channel,
119
+ session=session,
120
+ access_group=access_group,
121
+ profile=profile,
122
+ instance=instance,
123
+ conflict=conflict,
124
+ )