f40-sdk 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 (102) hide show
  1. f40_sdk-0.1.0/LICENSE +21 -0
  2. f40_sdk-0.1.0/PKG-INFO +64 -0
  3. f40_sdk-0.1.0/README.md +29 -0
  4. f40_sdk-0.1.0/pyproject.toml +80 -0
  5. f40_sdk-0.1.0/setup.cfg +4 -0
  6. f40_sdk-0.1.0/src/f40_sdk/__init__.py +48 -0
  7. f40_sdk-0.1.0/src/f40_sdk/clients/__init__.py +19 -0
  8. f40_sdk-0.1.0/src/f40_sdk/clients/ai_agents.py +61 -0
  9. f40_sdk-0.1.0/src/f40_sdk/clients/auth_manager.py +440 -0
  10. f40_sdk-0.1.0/src/f40_sdk/clients/base.py +316 -0
  11. f40_sdk-0.1.0/src/f40_sdk/clients/cmms.py +69 -0
  12. f40_sdk-0.1.0/src/f40_sdk/clients/data_manager.py +1487 -0
  13. f40_sdk-0.1.0/src/f40_sdk/clients/models.py +90 -0
  14. f40_sdk-0.1.0/src/f40_sdk/clients/wilson.py +141 -0
  15. f40_sdk-0.1.0/src/f40_sdk/gunicorn.py +213 -0
  16. f40_sdk-0.1.0/src/f40_sdk/mat/__init__.py +49 -0
  17. f40_sdk-0.1.0/src/f40_sdk/mat/configs/__init__.py +6 -0
  18. f40_sdk-0.1.0/src/f40_sdk/mat/configs/app_config.py +73 -0
  19. f40_sdk-0.1.0/src/f40_sdk/mat/configs/profiles.py +1122 -0
  20. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/__init__.py +18 -0
  21. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/_common.py +13 -0
  22. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/conversions.py +65 -0
  23. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/deep_merge.py +34 -0
  24. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/feature_flags.py +80 -0
  25. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/handler.py +82 -0
  26. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/icon_utils.py +56 -0
  27. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/languages.py +28 -0
  28. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/module_settings.py +251 -0
  29. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/registries.py +141 -0
  30. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/sidenav.py +303 -0
  31. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/toolbar_options.py +26 -0
  32. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_app_config/translations_utils.py +54 -0
  33. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/__init__.py +16 -0
  34. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/components_health.py +29 -0
  35. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/handler.py +276 -0
  36. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/__init__.py +38 -0
  37. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/advanced_changeover.py +48 -0
  38. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/aggregations.py +83 -0
  39. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/cmms.py +32 -0
  40. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/consumables.py +78 -0
  41. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/cycle_traceability.py +109 -0
  42. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/flags.py +6 -0
  43. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/homepage.py +233 -0
  44. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/kpis.py +125 -0
  45. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/mappings.py +29 -0
  46. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/monitoring_states.py +29 -0
  47. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/prices.py +36 -0
  48. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/production_config.py +46 -0
  49. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/scrap_columns.py +14 -0
  50. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/sidenav_visibility.py +30 -0
  51. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/sub_assets.py +16 -0
  52. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/tables.py +142 -0
  53. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/time_state_categories.py +47 -0
  54. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/time_states.py +37 -0
  55. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/mappers/units.py +15 -0
  56. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/overlay.py +26 -0
  57. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/source.py +81 -0
  58. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/__init__.py +12 -0
  59. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/deep_merge.py +26 -0
  60. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/icon.py +13 -0
  61. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/kpi_expansion.py +56 -0
  62. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/sub_machines_infos.py +17 -0
  63. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_profile/utils/subassets.py +20 -0
  64. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_variables/__init__.py +18 -0
  65. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_variables/handler.py +147 -0
  66. f40_sdk-0.1.0/src/f40_sdk/mat/configs/toml_variables/mappers.py +375 -0
  67. f40_sdk-0.1.0/src/f40_sdk/mat/configs/translations.py +179 -0
  68. f40_sdk-0.1.0/src/f40_sdk/mat/configs/variables.py +56 -0
  69. f40_sdk-0.1.0/src/f40_sdk/mat/console.py +498 -0
  70. f40_sdk-0.1.0/src/f40_sdk/mat/tools.py +1257 -0
  71. f40_sdk-0.1.0/src/f40_sdk/mat/utils/__init__.py +79 -0
  72. f40_sdk-0.1.0/src/f40_sdk/mat/utils/_globals.py +143 -0
  73. f40_sdk-0.1.0/src/f40_sdk/mat/utils/_numpy.py +57 -0
  74. f40_sdk-0.1.0/src/f40_sdk/mat/utils/calculator/__init__.py +268 -0
  75. f40_sdk-0.1.0/src/f40_sdk/mat/utils/calculator/builtin_methods.py +458 -0
  76. f40_sdk-0.1.0/src/f40_sdk/mat/utils/calculator/expression.py +956 -0
  77. f40_sdk-0.1.0/src/f40_sdk/mat/utils/cmms.py +434 -0
  78. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/__init__.py +11 -0
  79. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/arrays.py +1774 -0
  80. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/blocks.py +770 -0
  81. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/core.py +1117 -0
  82. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/formatter.py +153 -0
  83. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/index.py +299 -0
  84. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/io.py +21 -0
  85. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/matrixes.py +687 -0
  86. f40_sdk-0.1.0/src/f40_sdk/mat/utils/data_frame/merger.py +423 -0
  87. f40_sdk-0.1.0/src/f40_sdk/mat/utils/dt/__init__.py +1595 -0
  88. f40_sdk-0.1.0/src/f40_sdk/mat/utils/exceptions.py +64 -0
  89. f40_sdk-0.1.0/src/f40_sdk/mat/utils/filtering.py +929 -0
  90. f40_sdk-0.1.0/src/f40_sdk/mat/utils/folder.py +580 -0
  91. f40_sdk-0.1.0/src/f40_sdk/mat/utils/load_toml.py +1109 -0
  92. f40_sdk-0.1.0/src/f40_sdk/mat/utils/multithreading.py +200 -0
  93. f40_sdk-0.1.0/src/f40_sdk/mat/utils/objects.py +521 -0
  94. f40_sdk-0.1.0/src/f40_sdk/mat/utils/parser.py +55 -0
  95. f40_sdk-0.1.0/src/f40_sdk/py.typed +0 -0
  96. f40_sdk-0.1.0/src/f40_sdk.egg-info/PKG-INFO +64 -0
  97. f40_sdk-0.1.0/src/f40_sdk.egg-info/SOURCES.txt +100 -0
  98. f40_sdk-0.1.0/src/f40_sdk.egg-info/dependency_links.txt +1 -0
  99. f40_sdk-0.1.0/src/f40_sdk.egg-info/requires.txt +22 -0
  100. f40_sdk-0.1.0/src/f40_sdk.egg-info/top_level.txt +1 -0
  101. f40_sdk-0.1.0/tests/test_builtin_methods.py +78 -0
  102. f40_sdk-0.1.0/tests/test_toml_variables.py +182 -0
f40_sdk-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 40-Factory
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
f40_sdk-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: f40-sdk
3
+ Version: 0.1.0
4
+ Summary: SDK clients for MAT platform services (Auth Manager, Data Manager, AI Agents, CMMS, Wilson).
5
+ Author-email: 40F ECSD <m.domenicale@40-factory.com>
6
+ License-Expression: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development :: Libraries
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: f40-toolkit>=1.3.0
17
+ Requires-Dist: httpx>=0.27
18
+ Requires-Dist: key-vault-interface==1.0.8
19
+ Provides-Extra: cache-redis
20
+ Requires-Dist: f40-toolkit[cache-redis]>=1.3.0; extra == "cache-redis"
21
+ Provides-Extra: bsw
22
+ Requires-Dist: numpy>=1.24; extra == "bsw"
23
+ Requires-Dist: tzdata>=2023.3; extra == "bsw"
24
+ Provides-Extra: all
25
+ Requires-Dist: f40-toolkit[cache-redis]>=1.3.0; extra == "all"
26
+ Requires-Dist: numpy>=1.24; extra == "all"
27
+ Requires-Dist: tzdata>=2023.3; extra == "all"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8; extra == "dev"
30
+ Requires-Dist: mypy>=1.11; extra == "dev"
31
+ Requires-Dist: ruff>=0.6; extra == "dev"
32
+ Requires-Dist: build>=1.2; extra == "dev"
33
+ Requires-Dist: twine>=5.0; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # README #
37
+
38
+ This README would normally document whatever steps are necessary to get your application up and running.
39
+
40
+ ### What is this repository for? ###
41
+
42
+ * Quick summary
43
+ * Version
44
+ * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
45
+
46
+ ### How do I get set up? ###
47
+
48
+ * Summary of set up
49
+ * Configuration
50
+ * Dependencies
51
+ * Database configuration
52
+ * How to run tests
53
+ * Deployment instructions
54
+
55
+ ### Contribution guidelines ###
56
+
57
+ * Writing tests
58
+ * Code review
59
+ * Other guidelines
60
+
61
+ ### Who do I talk to? ###
62
+
63
+ * Repo owner or admin
64
+ * Other community or team contact
@@ -0,0 +1,29 @@
1
+ # README #
2
+
3
+ This README would normally document whatever steps are necessary to get your application up and running.
4
+
5
+ ### What is this repository for? ###
6
+
7
+ * Quick summary
8
+ * Version
9
+ * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
10
+
11
+ ### How do I get set up? ###
12
+
13
+ * Summary of set up
14
+ * Configuration
15
+ * Dependencies
16
+ * Database configuration
17
+ * How to run tests
18
+ * Deployment instructions
19
+
20
+ ### Contribution guidelines ###
21
+
22
+ * Writing tests
23
+ * Code review
24
+ * Other guidelines
25
+
26
+ ### Who do I talk to? ###
27
+
28
+ * Repo owner or admin
29
+ * Other community or team contact
@@ -0,0 +1,80 @@
1
+ [project]
2
+ name = "f40-sdk"
3
+ version = "0.1.0"
4
+ description = "SDK clients for MAT platform services (Auth Manager, Data Manager, AI Agents, CMMS, Wilson)."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "40F ECSD", email = "m.domenicale@40-factory.com" }]
10
+
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "Programming Language :: Python :: 3.12",
14
+ "Programming Language :: Python :: 3.13",
15
+ "Programming Language :: Python :: 3.14",
16
+ "Intended Audience :: Developers",
17
+ "Topic :: Software Development :: Libraries",
18
+ ]
19
+
20
+ # Core building blocks come from f40-toolkit; httpx is needed because the SDK
21
+ # always performs HTTP requests (f40_toolkit.common.http imports it lazily).
22
+ dependencies = [
23
+ "f40-toolkit>=1.3.0",
24
+ "httpx>=0.27",
25
+ "key-vault-interface==1.0.8",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ # Redis-backed cache wiring in MatDataManagerClient (delegates to f40-toolkit's cache).
30
+ cache-redis = ["f40-toolkit[cache-redis]>=1.3.0"]
31
+
32
+ # The centralized BSW framework (`f40_sdk.mat`) vendors a slice of mat_utilities
33
+ # (calculator / data_frame / dt) that needs numpy at runtime. Timezones use the
34
+ # stdlib `zoneinfo` (Python >= 3.9) instead of pytz; `tzdata` provides the IANA
35
+ # database where the OS doesn't ship one (Windows, slim containers). pandas is
36
+ # optional (data_frame.core imports it in a try/except for `.to_pandas()` only).
37
+ bsw = ["numpy>=1.24", "tzdata>=2023.3"]
38
+
39
+ # NOTE: `mat_utilities` (MatDataFrame / MatCmmsHierarchy) is an internal package, not
40
+ # declared here — read_tables / get_hierarchy import it lazily and fall back gracefully.
41
+
42
+ all = ["f40-toolkit[cache-redis]>=1.3.0", "numpy>=1.24", "tzdata>=2023.3"]
43
+
44
+ dev = [
45
+ "pytest>=8",
46
+ "mypy>=1.11",
47
+ "ruff>=0.6",
48
+ "build>=1.2",
49
+ "twine>=5.0",
50
+ ]
51
+
52
+ [build-system]
53
+ requires = ["setuptools>=77", "wheel"]
54
+ build-backend = "setuptools.build_meta"
55
+
56
+ [tool.setuptools]
57
+ package-dir = { "" = "src" }
58
+
59
+ [tool.setuptools.packages.find]
60
+ where = ["src"]
61
+ include = ["f40_sdk*"]
62
+
63
+ [tool.setuptools.package-data]
64
+ "f40_sdk" = ["py.typed"]
65
+
66
+ [tool.ruff]
67
+ target-version = "py312"
68
+ line-length = 100
69
+
70
+ [tool.ruff.lint]
71
+ select = ["E", "F", "W", "I"]
72
+
73
+ [tool.mypy]
74
+ files = ["src"]
75
+ python_version = "3.12"
76
+ ignore_missing_imports = true
77
+ warn_unused_ignores = false
78
+
79
+ [tool.pytest.ini_options]
80
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,48 @@
1
+ """
2
+ f40_sdk — SDK clients for the MAT Auth Manager, Data Manager and related services.
3
+
4
+ Built on the dependency-light HTTP building block in :mod:`f40_toolkit.common.http`
5
+ (a dependency of this package). Those primitives are re-exported here under their
6
+ historical ``Mat*`` names for convenience:
7
+
8
+ MatHttpClient -> f40_toolkit.common.http.HttpClient
9
+ MatHttpToken -> f40_toolkit.common.http.BearerToken
10
+ MatHttpError -> f40_toolkit.common.http.HttpError
11
+ MatAuthError -> f40_toolkit.common.http.HttpAuthError
12
+
13
+ Requires: ``pip install f40-sdk``
14
+
15
+ Quick imports
16
+ -------------
17
+ from f40_sdk import MatDataManagerClient, MatAuthManagerClient
18
+ from f40_sdk import MatHttpClient, MatBasicClient # building blocks
19
+ from f40_sdk import MatHttpError # exception
20
+ """
21
+
22
+ from f40_toolkit.common.http import BearerToken as MatHttpToken
23
+ from f40_toolkit.common.http import HttpAuthError as MatAuthError
24
+ from f40_toolkit.common.http import HttpClient as MatHttpClient
25
+ from f40_toolkit.common.http import HttpError as MatHttpError
26
+ from .clients import (
27
+ MatAiAgentsMngClient,
28
+ MatAuthManagerClient,
29
+ MatBasicClient,
30
+ MatCmmsMngClient,
31
+ MatCompData,
32
+ MatDataManagerClient,
33
+ WilsonMngClient,
34
+ )
35
+
36
+ __all__ = [
37
+ "MatHttpClient",
38
+ "MatBasicClient",
39
+ "MatHttpToken",
40
+ "MatAuthManagerClient",
41
+ "MatDataManagerClient",
42
+ "MatCompData",
43
+ "MatAiAgentsMngClient",
44
+ "MatCmmsMngClient",
45
+ "WilsonMngClient",
46
+ "MatHttpError",
47
+ "MatAuthError",
48
+ ]
@@ -0,0 +1,19 @@
1
+ """Service SDK clients for the MAT platform."""
2
+
3
+ from .ai_agents import MatAiAgentsMngClient
4
+ from .auth_manager import MatAuthManagerClient
5
+ from .base import MatBasicClient
6
+ from .cmms import MatCmmsMngClient
7
+ from .data_manager import MatDataManagerClient
8
+ from .models import MatCompData
9
+ from .wilson import WilsonMngClient
10
+
11
+ __all__ = [
12
+ "MatBasicClient",
13
+ "MatAuthManagerClient",
14
+ "MatDataManagerClient",
15
+ "MatCompData",
16
+ "MatAiAgentsMngClient",
17
+ "MatCmmsMngClient",
18
+ "WilsonMngClient",
19
+ ]
@@ -0,0 +1,61 @@
1
+ """
2
+ SDK client for the MAT AI-Agents (IoT-Agents) service.
3
+
4
+ Auth is handled by the parent :class:`MatBasicClient` (auth_mng / basic /
5
+ bearer_token / env_name). This client adds the agent listing and invocation API.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import logging
12
+ from typing import TYPE_CHECKING, List, Optional, Union
13
+
14
+ from .base import MatBasicClient
15
+
16
+ if TYPE_CHECKING:
17
+ from key_vault_interface.key_vault_interface import KeyVaultInterface # type: ignore[import]
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class MatAiAgentsMngClient(MatBasicClient):
23
+ """SDK client for the MAT AI-Agents service."""
24
+
25
+ def get_agents(self) -> List[dict]:
26
+ """Return the list of agents (empty list when none / unexpected shape)."""
27
+ res = self._send("GET", "iota/agents")
28
+ if isinstance(res, dict):
29
+ res = res.get("agents")
30
+ return res if isinstance(res, list) else []
31
+
32
+ def run_agent(self, agent_id: str, run_message: str) -> None:
33
+ """Invoke an agent with an alert message."""
34
+ self._send(
35
+ "POST", f"iota/agents/invoke/{agent_id}",
36
+ data=json.dumps({"alertMessage": run_message}), res_type="code",
37
+ )
38
+
39
+ @classmethod
40
+ def from_json( # type: ignore[override]
41
+ cls,
42
+ _json: Union[dict, str],
43
+ kvi: Optional["KeyVaultInterface"] = None,
44
+ ) -> "MatAiAgentsMngClient":
45
+ """
46
+ Construct from a config dict or a path to a JSON file.
47
+
48
+ The JSON may have the config nested under an ``"ai_agents"`` key::
49
+
50
+ {"ai_agents": {"url": "...", "auth": {...}}}
51
+ """
52
+ if isinstance(_json, str):
53
+ with open(_json, "r") as fh:
54
+ _json = json.load(fh)
55
+ if isinstance(_json, dict) and "ai_agents" in _json:
56
+ _json = _json["ai_agents"]
57
+
58
+ if not isinstance(_json, dict):
59
+ raise TypeError(f"Expected a dict or JSON file path, got {type(_json).__name__}.")
60
+
61
+ return cls.from_dict(_json, kvi=kvi)