naas-abi-core 1.0.0__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.
Files changed (124) hide show
  1. naas_abi_core/__init__.py +1 -0
  2. naas_abi_core/apps/api/api.py +242 -0
  3. naas_abi_core/apps/api/api_test.py +281 -0
  4. naas_abi_core/apps/api/openapi_doc.py +307 -0
  5. naas_abi_core/apps/mcp/mcp_server.py +243 -0
  6. naas_abi_core/apps/mcp/mcp_server_test.py +163 -0
  7. naas_abi_core/apps/terminal_agent/main.py +555 -0
  8. naas_abi_core/apps/terminal_agent/terminal_style.py +175 -0
  9. naas_abi_core/cli/__init__.py +53 -0
  10. naas_abi_core/cli/agent.py +30 -0
  11. naas_abi_core/cli/chat.py +26 -0
  12. naas_abi_core/cli/config.py +49 -0
  13. naas_abi_core/cli/init.py +13 -0
  14. naas_abi_core/cli/module.py +28 -0
  15. naas_abi_core/cli/new.py +13 -0
  16. naas_abi_core/cli/secret.py +79 -0
  17. naas_abi_core/engine/Engine.py +87 -0
  18. naas_abi_core/engine/EngineProxy.py +109 -0
  19. naas_abi_core/engine/Engine_test.py +6 -0
  20. naas_abi_core/engine/IEngine.py +91 -0
  21. naas_abi_core/engine/conftest.py +45 -0
  22. naas_abi_core/engine/engine_configuration/EngineConfiguration.py +160 -0
  23. naas_abi_core/engine/engine_configuration/EngineConfiguration_GenericLoader.py +49 -0
  24. naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService.py +131 -0
  25. naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService_test.py +26 -0
  26. naas_abi_core/engine/engine_configuration/EngineConfiguration_SecretService.py +116 -0
  27. naas_abi_core/engine/engine_configuration/EngineConfiguration_TripleStoreService.py +171 -0
  28. naas_abi_core/engine/engine_configuration/EngineConfiguration_VectorStoreService.py +65 -0
  29. naas_abi_core/engine/engine_configuration/EngineConfiguration_test.py +9 -0
  30. naas_abi_core/engine/engine_configuration/utils/PydanticModelValidator.py +15 -0
  31. naas_abi_core/engine/engine_loaders/EngineModuleLoader.py +302 -0
  32. naas_abi_core/engine/engine_loaders/EngineOntologyLoader.py +16 -0
  33. naas_abi_core/engine/engine_loaders/EngineServiceLoader.py +47 -0
  34. naas_abi_core/integration/__init__.py +7 -0
  35. naas_abi_core/integration/integration.py +28 -0
  36. naas_abi_core/models/Model.py +198 -0
  37. naas_abi_core/models/OpenRouter.py +15 -0
  38. naas_abi_core/models/OpenRouter_test.py +36 -0
  39. naas_abi_core/module/Module.py +245 -0
  40. naas_abi_core/module/ModuleAgentLoader.py +49 -0
  41. naas_abi_core/module/ModuleUtils.py +20 -0
  42. naas_abi_core/modules/templatablesparqlquery/README.md +196 -0
  43. naas_abi_core/modules/templatablesparqlquery/__init__.py +39 -0
  44. naas_abi_core/modules/templatablesparqlquery/ontologies/TemplatableSparqlQueryOntology.ttl +116 -0
  45. naas_abi_core/modules/templatablesparqlquery/workflows/GenericWorkflow.py +48 -0
  46. naas_abi_core/modules/templatablesparqlquery/workflows/TemplatableSparqlQueryLoader.py +192 -0
  47. naas_abi_core/pipeline/__init__.py +6 -0
  48. naas_abi_core/pipeline/pipeline.py +70 -0
  49. naas_abi_core/services/__init__.py +0 -0
  50. naas_abi_core/services/agent/Agent.py +1619 -0
  51. naas_abi_core/services/agent/AgentMemory_test.py +28 -0
  52. naas_abi_core/services/agent/Agent_test.py +214 -0
  53. naas_abi_core/services/agent/IntentAgent.py +1171 -0
  54. naas_abi_core/services/agent/IntentAgent_test.py +139 -0
  55. naas_abi_core/services/agent/beta/Embeddings.py +180 -0
  56. naas_abi_core/services/agent/beta/IntentMapper.py +119 -0
  57. naas_abi_core/services/agent/beta/LocalModel.py +88 -0
  58. naas_abi_core/services/agent/beta/VectorStore.py +89 -0
  59. naas_abi_core/services/agent/test_agent_memory.py +278 -0
  60. naas_abi_core/services/agent/test_postgres_integration.py +145 -0
  61. naas_abi_core/services/cache/CacheFactory.py +31 -0
  62. naas_abi_core/services/cache/CachePort.py +63 -0
  63. naas_abi_core/services/cache/CacheService.py +246 -0
  64. naas_abi_core/services/cache/CacheService_test.py +85 -0
  65. naas_abi_core/services/cache/adapters/secondary/CacheFSAdapter.py +39 -0
  66. naas_abi_core/services/object_storage/ObjectStorageFactory.py +57 -0
  67. naas_abi_core/services/object_storage/ObjectStoragePort.py +47 -0
  68. naas_abi_core/services/object_storage/ObjectStorageService.py +41 -0
  69. naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterFS.py +52 -0
  70. naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterNaas.py +131 -0
  71. naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterS3.py +171 -0
  72. naas_abi_core/services/ontology/OntologyPorts.py +36 -0
  73. naas_abi_core/services/ontology/OntologyService.py +17 -0
  74. naas_abi_core/services/ontology/adaptors/secondary/OntologyService_SecondaryAdaptor_NERPort.py +37 -0
  75. naas_abi_core/services/secret/Secret.py +138 -0
  76. naas_abi_core/services/secret/SecretPorts.py +40 -0
  77. naas_abi_core/services/secret/Secret_test.py +65 -0
  78. naas_abi_core/services/secret/adaptors/secondary/Base64Secret.py +57 -0
  79. naas_abi_core/services/secret/adaptors/secondary/Base64Secret_test.py +39 -0
  80. naas_abi_core/services/secret/adaptors/secondary/NaasSecret.py +81 -0
  81. naas_abi_core/services/secret/adaptors/secondary/NaasSecret_test.py +25 -0
  82. naas_abi_core/services/secret/adaptors/secondary/dotenv_secret_secondaryadaptor.py +26 -0
  83. naas_abi_core/services/triple_store/TripleStoreFactory.py +116 -0
  84. naas_abi_core/services/triple_store/TripleStorePorts.py +223 -0
  85. naas_abi_core/services/triple_store/TripleStoreService.py +419 -0
  86. naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune.py +1284 -0
  87. naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune_test.py +284 -0
  88. naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph.py +597 -0
  89. naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph_test.py +1474 -0
  90. naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__Filesystem.py +223 -0
  91. naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__ObjectStorage.py +234 -0
  92. naas_abi_core/services/triple_store/adaptors/secondary/base/TripleStoreService__SecondaryAdaptor__FileBase.py +18 -0
  93. naas_abi_core/services/vector_store/IVectorStorePort.py +101 -0
  94. naas_abi_core/services/vector_store/IVectorStorePort_test.py +189 -0
  95. naas_abi_core/services/vector_store/VectorStoreFactory.py +47 -0
  96. naas_abi_core/services/vector_store/VectorStoreService.py +171 -0
  97. naas_abi_core/services/vector_store/VectorStoreService_test.py +185 -0
  98. naas_abi_core/services/vector_store/__init__.py +13 -0
  99. naas_abi_core/services/vector_store/adapters/QdrantAdapter.py +251 -0
  100. naas_abi_core/services/vector_store/adapters/QdrantAdapter_test.py +57 -0
  101. naas_abi_core/utils/Expose.py +53 -0
  102. naas_abi_core/utils/Graph.py +182 -0
  103. naas_abi_core/utils/JSON.py +49 -0
  104. naas_abi_core/utils/LazyLoader.py +44 -0
  105. naas_abi_core/utils/Logger.py +12 -0
  106. naas_abi_core/utils/OntologyReasoner.py +141 -0
  107. naas_abi_core/utils/OntologyYaml.disabled.py +679 -0
  108. naas_abi_core/utils/SPARQL.py +256 -0
  109. naas_abi_core/utils/Storage.py +33 -0
  110. naas_abi_core/utils/StorageUtils.py +398 -0
  111. naas_abi_core/utils/String.py +52 -0
  112. naas_abi_core/utils/Workers.py +114 -0
  113. naas_abi_core/utils/__init__.py +0 -0
  114. naas_abi_core/utils/onto2py/README.md +0 -0
  115. naas_abi_core/utils/onto2py/__init__.py +10 -0
  116. naas_abi_core/utils/onto2py/__main__.py +29 -0
  117. naas_abi_core/utils/onto2py/onto2py.py +611 -0
  118. naas_abi_core/utils/onto2py/tests/ttl2py_test.py +271 -0
  119. naas_abi_core/workflow/__init__.py +5 -0
  120. naas_abi_core/workflow/workflow.py +48 -0
  121. naas_abi_core-1.0.0.dist-info/METADATA +75 -0
  122. naas_abi_core-1.0.0.dist-info/RECORD +124 -0
  123. naas_abi_core-1.0.0.dist-info/WHEEL +4 -0
  124. naas_abi_core-1.0.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Dict, List, Union
4
+
5
+ from naas_abi_core.services.object_storage.ObjectStorageService import (
6
+ ObjectStorageService,
7
+ )
8
+ from naas_abi_core.services.secret.Secret import Secret
9
+ from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
10
+ from naas_abi_core.services.vector_store.VectorStoreService import VectorStoreService
11
+
12
+ if TYPE_CHECKING:
13
+ from naas_abi_core.module.Module import BaseModule
14
+
15
+
16
+ class IEngine:
17
+ class Services:
18
+ __object_storage: ObjectStorageService | None
19
+ __triple_store: TripleStoreService | None
20
+ __vector_store: VectorStoreService | None
21
+ __secret: Secret | None
22
+
23
+ def __init__(
24
+ self,
25
+ object_storage: ObjectStorageService | None = None,
26
+ triple_store: TripleStoreService | None = None,
27
+ vector_store: VectorStoreService | None = None,
28
+ secret: Secret | None = None,
29
+ ):
30
+ self.__object_storage = object_storage
31
+ self.__triple_store = triple_store
32
+ self.__vector_store = vector_store
33
+ self.__secret = secret
34
+
35
+ @property
36
+ def object_storage(self) -> ObjectStorageService:
37
+ assert self.__object_storage is not None, (
38
+ "Object storage service is not initialized"
39
+ )
40
+ return self.__object_storage
41
+
42
+ @property
43
+ def triple_store(self) -> TripleStoreService:
44
+ assert self.__triple_store is not None, (
45
+ "Triple store service is not initialized"
46
+ )
47
+ return self.__triple_store
48
+
49
+ def triple_store_available(self) -> bool:
50
+ return self.__triple_store is not None
51
+
52
+ @property
53
+ def vector_store(self) -> VectorStoreService:
54
+ assert self.__vector_store is not None, (
55
+ "Vector store service is not initialized"
56
+ )
57
+ return self.__vector_store
58
+
59
+ @property
60
+ def secret(self) -> Secret:
61
+ assert self.__secret is not None, "Secret service is not initialized"
62
+ return self.__secret
63
+
64
+ @property
65
+ def all(
66
+ self,
67
+ ) -> List[
68
+ Union[
69
+ ObjectStorageService | None,
70
+ TripleStoreService | None,
71
+ VectorStoreService | None,
72
+ Secret | None,
73
+ ]
74
+ ]:
75
+ return [
76
+ self.__object_storage,
77
+ self.__triple_store,
78
+ self.__vector_store,
79
+ self.__secret,
80
+ ]
81
+
82
+ __services: Services
83
+ __modules: Dict[str, BaseModule]
84
+
85
+ @property
86
+ def services(self) -> Services:
87
+ return self.__services
88
+
89
+ @property
90
+ def modules(self) -> Dict[str, BaseModule]:
91
+ return self.__modules
@@ -0,0 +1,45 @@
1
+ from pytest import fixture
2
+
3
+
4
+ @fixture
5
+ def test_configuration():
6
+ return """
7
+ workspace_id: "1234567890"
8
+ storage_name: "test"
9
+ github_repository: "test"
10
+ github_project_id: 1234567890
11
+ triple_store_path: "test"
12
+ api_title: "test"
13
+ api_description: "test"
14
+ logo_path: "test"
15
+ favicon_path: "test"
16
+ space_name: "test"
17
+ cors_origins:
18
+ - "http://localhost:9879"
19
+
20
+ services:
21
+ object_storage: &object_storage_service
22
+ object_storage_adapter:
23
+ adapter: "fs"
24
+ config:
25
+ base_path: "test"
26
+ test: "{{ secret.OXIGRAPH_URL }}"
27
+
28
+ triple_store:
29
+ triple_store_adapter:
30
+ adapter: "object_storage"
31
+ config:
32
+ triples_prefix: "test"
33
+ object_storage_service: *object_storage_service
34
+
35
+
36
+ vector_store:
37
+ vector_store_adapter:
38
+ adapter: "qdrant"
39
+ config: {}
40
+
41
+ secret:
42
+ secret_adapters:
43
+ - adapter: "dotenv"
44
+ config: {}
45
+ """
@@ -0,0 +1,160 @@
1
+ import os
2
+ from io import StringIO
3
+ from typing import List
4
+
5
+ import yaml
6
+ from jinja2 import Template
7
+ from naas_abi_core import logger
8
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_ObjectStorageService import (
9
+ ObjectStorageServiceConfiguration,
10
+ )
11
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_SecretService import (
12
+ SecretServiceConfiguration,
13
+ )
14
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_TripleStoreService import (
15
+ TripleStoreServiceConfiguration,
16
+ )
17
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_VectorStoreService import (
18
+ VectorStoreServiceConfiguration,
19
+ )
20
+ from naas_abi_core.services.secret.Secret import Secret
21
+ from pydantic import BaseModel, model_validator
22
+ from typing_extensions import Literal
23
+
24
+
25
+ class ServicesConfiguration(BaseModel):
26
+ object_storage: ObjectStorageServiceConfiguration
27
+ triple_store: TripleStoreServiceConfiguration
28
+ vector_store: VectorStoreServiceConfiguration
29
+ secret: SecretServiceConfiguration
30
+
31
+
32
+ class ApiConfiguration(BaseModel):
33
+ title: str = "ABI API"
34
+ description: str = "API for ABI, your Artifical Business Intelligence"
35
+ logo_path: str = "assets/logo.png"
36
+ favicon_path: str = "assets/favicon.ico"
37
+ cors_origins: List[str] = ["http://localhost:9879"]
38
+
39
+
40
+ class FirstPassConfiguration(BaseModel):
41
+ """This is a first pass configuration that is used to load the secret service.
42
+
43
+ It is used to load the secret service before the other services are loaded.
44
+ This is because the secret service needs to be loaded before the other services
45
+ are loaded to be able to resolve the secrets.
46
+ This is a first pass configuration that is used to load the secret service.
47
+ """
48
+
49
+ class FirstPassServicesConfiguration(BaseModel):
50
+ secret: SecretServiceConfiguration
51
+
52
+ services: FirstPassServicesConfiguration
53
+
54
+
55
+ class ModuleConfig(BaseModel):
56
+ path: str | None = None
57
+ module: str | None = None
58
+ enabled: bool
59
+ config: dict = {}
60
+
61
+ @model_validator(mode="after")
62
+ def validate_path_or_module(self):
63
+ if self.path is None and self.module is None:
64
+ raise ValueError("Either path or module must be provided")
65
+
66
+ if self.path is None:
67
+ assert self.module is not None, (
68
+ "module must be provided if path is not provided"
69
+ )
70
+ if self.module is None:
71
+ assert self.path is not None, (
72
+ "path must be provided if module is not provided"
73
+ )
74
+ return self
75
+
76
+
77
+ class GlobalConfig(BaseModel):
78
+ ai_mode: Literal["cloud", "local", "airgap"]
79
+
80
+
81
+ class EngineConfiguration(BaseModel):
82
+ api: ApiConfiguration
83
+
84
+ services: ServicesConfiguration
85
+
86
+ global_config: GlobalConfig
87
+
88
+ modules: List[ModuleConfig]
89
+
90
+ @classmethod
91
+ def from_yaml(cls, yaml_path: str) -> "EngineConfiguration":
92
+ with open(yaml_path, "r") as file:
93
+ return cls.from_yaml_content(file.read())
94
+
95
+ @classmethod
96
+ def from_yaml_content(cls, yaml_content: str) -> "EngineConfiguration":
97
+ # First we do a pass with the minimal configuration to load the secret service.
98
+ class SecretServiceWrapper:
99
+ secret_service: Secret | None = None
100
+
101
+ def __init__(self, secret_service: Secret | None = None):
102
+ self.secret_service = secret_service
103
+
104
+ def __getattr__(self, name):
105
+ if self.secret_service is None:
106
+ return 0
107
+ secret = self.secret_service.get(name)
108
+ if secret is None:
109
+ raise ValueError(f"Secret {name} not found")
110
+ return secret
111
+
112
+ def get(self, key, default=None):
113
+ return 0
114
+
115
+ first_pass_data = yaml.safe_load(
116
+ StringIO(Template(yaml_content).render(secret=SecretServiceWrapper()))
117
+ )
118
+
119
+ first_pass_configuration = FirstPassConfiguration(**first_pass_data)
120
+ secret_service = first_pass_configuration.services.secret.load()
121
+
122
+ # Here we can now template the yaml by using `yaml_content` and the secret service.
123
+ # Using Jinja2 template engine.
124
+
125
+ logger.debug("Yaml content: {yaml_content}")
126
+
127
+ template = Template(yaml_content)
128
+ templated_yaml = template.render(secret=SecretServiceWrapper(secret_service))
129
+
130
+ logger.debug(f"Templated yaml: {templated_yaml}")
131
+
132
+ data = yaml.safe_load(StringIO(templated_yaml))
133
+
134
+ logger.debug(f"Data: {data}")
135
+
136
+ return cls(**data)
137
+
138
+ @classmethod
139
+ def load_configuration(
140
+ cls, configuration_yaml: str | None = None
141
+ ) -> "EngineConfiguration":
142
+ # This is useful for testing.
143
+ if configuration_yaml is not None:
144
+ return cls.from_yaml_content(configuration_yaml)
145
+
146
+ logger.debug(f"Loading configuration from {os.getenv('ENV')}")
147
+
148
+ if os.path.exists(f"config.{os.getenv('ENV')}.yaml"):
149
+ return cls.from_yaml(f"config.{os.getenv('ENV')}.yaml")
150
+ elif os.path.exists("config.yaml"):
151
+ return cls.from_yaml("config.yaml")
152
+ else:
153
+ raise FileNotFoundError(
154
+ "Configuration file not found. Please create a config.yaml file or config.{env}.yaml file."
155
+ )
156
+
157
+
158
+ if __name__ == "__main__":
159
+ config = EngineConfiguration.load_configuration()
160
+ print(config)
@@ -0,0 +1,49 @@
1
+ import importlib
2
+ from typing import Any, Dict
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class GenericLoader(BaseModel):
8
+ """
9
+ Generic loader for dynamically importing and instantiating Python callables.
10
+
11
+ This class enables dynamic loading of Python classes or functions by specifying
12
+ the module path and callable name. The callable is invoked with the provided
13
+ configuration dictionary unpacked as keyword arguments.
14
+
15
+ Usage:
16
+ 1. Use importlib.import_module(python_module) to import the target module
17
+ 2. Use getattr(module, module_callable) to retrieve the callable
18
+ 3. Invoke the callable with the custom_config as **custom_config
19
+
20
+ Example:
21
+ loader = GenericLoader(
22
+ python_module="my.package.module",
23
+ module_callable="MyClass",
24
+ custom_config={"param1": "value1", "param2": 42}
25
+ )
26
+ # This would effectively do:
27
+ # import importlib
28
+ # module = importlib.import_module("my.package.module")
29
+ # callable_obj = getattr(module, "MyClass")
30
+ # instance = callable_obj(param1="value1", param2=42)
31
+
32
+ Attributes:
33
+ python_module: The fully qualified Python module path (e.g., "package.subpackage.module")
34
+ module_callable: The name of the callable (class or function) to retrieve from the module
35
+ custom_config: Dictionary of configuration parameters to pass as keyword arguments to the callable
36
+ """
37
+
38
+ python_module: str | None = None
39
+ module_callable: str | None = None
40
+ custom_config: Dict[str, Any] | None = None
41
+
42
+ def load(self) -> Any:
43
+ assert self.python_module is not None, "python_module is required"
44
+ assert self.module_callable is not None, "module_callable is required"
45
+ assert self.custom_config is not None, "custom_config is required"
46
+
47
+ module = importlib.import_module(self.python_module)
48
+ callable_obj = getattr(module, self.module_callable)
49
+ return callable_obj(**self.custom_config)
@@ -0,0 +1,131 @@
1
+ from typing import Dict, Literal, Tuple, Union
2
+
3
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_GenericLoader import (
4
+ GenericLoader,
5
+ )
6
+ from naas_abi_core.engine.engine_configuration.utils.PydanticModelValidator import (
7
+ pydantic_model_validator,
8
+ )
9
+ from naas_abi_core.services.object_storage.ObjectStoragePort import (
10
+ IObjectStorageAdapter,
11
+ )
12
+ from naas_abi_core.services.object_storage.ObjectStorageService import (
13
+ ObjectStorageService,
14
+ )
15
+ from pydantic import BaseModel, model_validator
16
+ from typing_extensions import Self
17
+
18
+
19
+ class ObjectStorageAdapterFSConfiguration(BaseModel):
20
+ base_path: str
21
+
22
+
23
+ class ObjectStorageAdapterS3Configuration(BaseModel):
24
+ bucket_name: str
25
+ access_key_id: str
26
+ secret_access_key: str
27
+ base_prefix: str
28
+ session_token: str | None = None
29
+
30
+
31
+ class ObjectStorageAdapterNaasConfiguration(BaseModel):
32
+ naas_api_key: str
33
+ workspace_id: str
34
+ storage_name: str
35
+ base_prefix: str = ""
36
+
37
+
38
+ class ObjectStorageAdapterConfiguration(GenericLoader):
39
+ adapter: Literal["fs", "s3", "naas", "custom"]
40
+ config: (
41
+ Union[
42
+ ObjectStorageAdapterFSConfiguration,
43
+ ObjectStorageAdapterS3Configuration,
44
+ ObjectStorageAdapterNaasConfiguration,
45
+ ]
46
+ | None
47
+ ) = None
48
+
49
+ __MAPPING: Dict[Literal["fs", "s3", "naas"], Tuple[str, str]] = {
50
+ "fs": (
51
+ "abi.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterFS",
52
+ "ObjectStorageSecondaryAdapterFS",
53
+ ),
54
+ "s3": (
55
+ "abi.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterS3",
56
+ "ObjectStorageSecondaryAdapterS3",
57
+ ),
58
+ "naas": (
59
+ "abi.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterNaas",
60
+ "ObjectStorageSecondaryAdapterNaas",
61
+ ),
62
+ }
63
+
64
+ @model_validator(mode="after")
65
+ def validate_adapter(self) -> Self:
66
+ if self.adapter != "custom":
67
+ assert self.config is not None, (
68
+ "config is required if adapter is not custom"
69
+ )
70
+
71
+ if self.adapter == "fs":
72
+ pydantic_model_validator(
73
+ ObjectStorageAdapterFSConfiguration,
74
+ self.config,
75
+ "Invalid configuration for services.object_storage.object_storage_adapter 'fs' adapter",
76
+ )
77
+ if self.adapter == "s3":
78
+ pydantic_model_validator(
79
+ ObjectStorageAdapterS3Configuration,
80
+ self.config,
81
+ "Invalid configuration for services.object_storage.object_storage_adapter 's3' adapter",
82
+ )
83
+ if self.adapter == "naas":
84
+ pydantic_model_validator(
85
+ ObjectStorageAdapterNaasConfiguration,
86
+ self.config,
87
+ "Invalid configuration for services.object_storage.object_storage_adapter 'naas' adapter",
88
+ )
89
+
90
+ return self
91
+
92
+ def load(self) -> IObjectStorageAdapter:
93
+ if self.adapter != "custom":
94
+ assert self.config is not None, (
95
+ "config is required if adapter is not custom"
96
+ )
97
+
98
+ if self.adapter == "fs":
99
+ from naas_abi_core.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterFS import (
100
+ ObjectStorageSecondaryAdapterFS,
101
+ )
102
+
103
+ return ObjectStorageSecondaryAdapterFS(**self.config.model_dump())
104
+ elif self.adapter == "s3":
105
+ from naas_abi_core.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterS3 import (
106
+ ObjectStorageSecondaryAdapterS3,
107
+ )
108
+
109
+ return ObjectStorageSecondaryAdapterS3(**self.config.model_dump())
110
+ elif self.adapter == "naas":
111
+ from naas_abi_core.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterNaas import (
112
+ ObjectStorageSecondaryAdapterNaas,
113
+ )
114
+
115
+ return ObjectStorageSecondaryAdapterNaas(**self.config.model_dump())
116
+ else:
117
+ raise ValueError(f"Unknown adapter: {self.adapter}")
118
+ # return GenericLoader(
119
+ # python_module=self.__MAPPING[self.adapter][0],
120
+ # module_callable=self.__MAPPING[self.adapter][1],
121
+ # custom_config=self.config.model_dump(),
122
+ # ).load()
123
+ else:
124
+ return super().load()
125
+
126
+
127
+ class ObjectStorageServiceConfiguration(BaseModel):
128
+ object_storage_adapter: ObjectStorageAdapterConfiguration
129
+
130
+ def load(self) -> ObjectStorageService:
131
+ return ObjectStorageService(adapter=self.object_storage_adapter.load())
@@ -0,0 +1,26 @@
1
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_ObjectStorageService import (
2
+ ObjectStorageAdapterConfiguration,
3
+ ObjectStorageAdapterFSConfiguration,
4
+ ObjectStorageServiceConfiguration,
5
+ )
6
+ from naas_abi_core.services.object_storage.adapters.secondary.ObjectStorageSecondaryAdapterFS import (
7
+ ObjectStorageSecondaryAdapterFS,
8
+ )
9
+ from naas_abi_core.services.object_storage.ObjectStoragePort import (
10
+ IObjectStorageAdapter,
11
+ )
12
+
13
+
14
+ def test_object_storage_service_configuration():
15
+ configuration = ObjectStorageServiceConfiguration(
16
+ object_storage_adapter=ObjectStorageAdapterConfiguration(
17
+ adapter="fs", config=ObjectStorageAdapterFSConfiguration(base_path="test")
18
+ )
19
+ )
20
+ assert configuration.object_storage_adapter is not None
21
+
22
+ object_storage_adapter = configuration.object_storage_adapter.load()
23
+
24
+ assert object_storage_adapter is not None
25
+ assert isinstance(object_storage_adapter, IObjectStorageAdapter)
26
+ assert isinstance(object_storage_adapter, ObjectStorageSecondaryAdapterFS)
@@ -0,0 +1,116 @@
1
+ from typing import TYPE_CHECKING, List, Literal, Union
2
+
3
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_GenericLoader import (
4
+ GenericLoader,
5
+ )
6
+ from naas_abi_core.engine.engine_configuration.utils.PydanticModelValidator import (
7
+ pydantic_model_validator,
8
+ )
9
+ from naas_abi_core.services.secret.Secret import Secret
10
+ from naas_abi_core.services.secret.SecretPorts import ISecretAdapter
11
+ from pydantic import BaseModel, model_validator
12
+ from typing_extensions import Self
13
+
14
+ # Only import for type checking, not at runtime
15
+ if TYPE_CHECKING:
16
+ from naas_abi_core.services.secret.adaptors.secondary.Base64Secret import (
17
+ Base64Secret,
18
+ )
19
+
20
+
21
+ class Base64SecretConfiguration(BaseModel):
22
+ secret_adapter: "SecretAdapterConfiguration"
23
+ base64_secret_key: str
24
+
25
+ def load(self) -> "Base64Secret":
26
+ from naas_abi_core.services.secret.adaptors.secondary.Base64Secret import (
27
+ Base64Secret,
28
+ )
29
+
30
+ return Base64Secret(self.secret_adapter.load(), self.base64_secret_key)
31
+
32
+
33
+ class NaasSecretConfiguration(BaseModel):
34
+ naas_api_key: str
35
+ naas_api_url: str
36
+
37
+
38
+ class DotenvSecretConfiguration(BaseModel):
39
+ pass
40
+
41
+
42
+ class SecretAdapterConfiguration(GenericLoader):
43
+ adapter: Literal["dotenv", "naas", "base64", "custom"]
44
+ config: (
45
+ Union[
46
+ DotenvSecretConfiguration,
47
+ NaasSecretConfiguration,
48
+ Base64SecretConfiguration,
49
+ ]
50
+ | None
51
+ ) = None
52
+
53
+ @model_validator(mode="after")
54
+ def validate_adapter(self) -> Self:
55
+ if self.adapter != "custom":
56
+ assert self.config is not None, (
57
+ "config is required if adapter is not custom"
58
+ )
59
+ if self.adapter == "base64":
60
+ pydantic_model_validator(
61
+ Base64SecretConfiguration,
62
+ self.config,
63
+ "Invalid configuration for services.secret.secret_adapters 'base64' adapter",
64
+ )
65
+ if self.adapter == "dotenv":
66
+ pydantic_model_validator(
67
+ DotenvSecretConfiguration,
68
+ self.config,
69
+ "Invalid configuration for services.secret.secret_adapters 'dotenv' adapter",
70
+ )
71
+ if self.adapter == "naas":
72
+ pydantic_model_validator(
73
+ NaasSecretConfiguration,
74
+ self.config,
75
+ "Invalid configuration for services.secret.secret_adapters 'naas' adapter",
76
+ )
77
+ return self
78
+
79
+ def load(self) -> ISecretAdapter:
80
+ if self.adapter != "custom":
81
+ assert self.config is not None, (
82
+ "config is required if adapter is not custom"
83
+ )
84
+
85
+ # Lazy import: only import the adapter that's actually configured
86
+ if self.adapter == "base64":
87
+ assert isinstance(self.config, Base64SecretConfiguration), (
88
+ "config must be a Base64SecretConfiguration if adapter is base64"
89
+ )
90
+ assert hasattr(self.config, "load"), (
91
+ "config must have a load method if adapter is base64"
92
+ )
93
+ return self.config.load()
94
+ elif self.adapter == "dotenv":
95
+ from naas_abi_core.services.secret.adaptors.secondary.dotenv_secret_secondaryadaptor import (
96
+ DotenvSecretSecondaryAdaptor,
97
+ )
98
+
99
+ return DotenvSecretSecondaryAdaptor(**self.config.model_dump())
100
+ elif self.adapter == "naas":
101
+ from naas_abi_core.services.secret.adaptors.secondary.NaasSecret import (
102
+ NaasSecret,
103
+ )
104
+
105
+ return NaasSecret(**self.config.model_dump())
106
+ else:
107
+ raise ValueError(f"Unknown adapter: {self.adapter}")
108
+ else:
109
+ return super().load()
110
+
111
+
112
+ class SecretServiceConfiguration(BaseModel):
113
+ secret_adapters: List[SecretAdapterConfiguration]
114
+
115
+ def load(self) -> Secret:
116
+ return Secret(adapters=[adapter.load() for adapter in self.secret_adapters])