hexdag 0.5.0.dev1__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 (261) hide show
  1. hexdag/__init__.py +116 -0
  2. hexdag/__main__.py +30 -0
  3. hexdag/adapters/executors/__init__.py +5 -0
  4. hexdag/adapters/executors/local_executor.py +316 -0
  5. hexdag/builtin/__init__.py +6 -0
  6. hexdag/builtin/adapters/__init__.py +51 -0
  7. hexdag/builtin/adapters/anthropic/__init__.py +5 -0
  8. hexdag/builtin/adapters/anthropic/anthropic_adapter.py +151 -0
  9. hexdag/builtin/adapters/database/__init__.py +6 -0
  10. hexdag/builtin/adapters/database/csv/csv_adapter.py +249 -0
  11. hexdag/builtin/adapters/database/pgvector/__init__.py +5 -0
  12. hexdag/builtin/adapters/database/pgvector/pgvector_adapter.py +478 -0
  13. hexdag/builtin/adapters/database/sqlalchemy/sqlalchemy_adapter.py +252 -0
  14. hexdag/builtin/adapters/database/sqlite/__init__.py +5 -0
  15. hexdag/builtin/adapters/database/sqlite/sqlite_adapter.py +410 -0
  16. hexdag/builtin/adapters/local/README.md +59 -0
  17. hexdag/builtin/adapters/local/__init__.py +7 -0
  18. hexdag/builtin/adapters/local/local_observer_manager.py +696 -0
  19. hexdag/builtin/adapters/memory/__init__.py +47 -0
  20. hexdag/builtin/adapters/memory/file_memory_adapter.py +297 -0
  21. hexdag/builtin/adapters/memory/in_memory_memory.py +216 -0
  22. hexdag/builtin/adapters/memory/schemas.py +57 -0
  23. hexdag/builtin/adapters/memory/session_memory.py +178 -0
  24. hexdag/builtin/adapters/memory/sqlite_memory_adapter.py +215 -0
  25. hexdag/builtin/adapters/memory/state_memory.py +280 -0
  26. hexdag/builtin/adapters/mock/README.md +89 -0
  27. hexdag/builtin/adapters/mock/__init__.py +15 -0
  28. hexdag/builtin/adapters/mock/hexdag.toml +50 -0
  29. hexdag/builtin/adapters/mock/mock_database.py +225 -0
  30. hexdag/builtin/adapters/mock/mock_embedding.py +223 -0
  31. hexdag/builtin/adapters/mock/mock_llm.py +177 -0
  32. hexdag/builtin/adapters/mock/mock_tool_adapter.py +192 -0
  33. hexdag/builtin/adapters/mock/mock_tool_router.py +232 -0
  34. hexdag/builtin/adapters/openai/__init__.py +5 -0
  35. hexdag/builtin/adapters/openai/openai_adapter.py +634 -0
  36. hexdag/builtin/adapters/secret/__init__.py +7 -0
  37. hexdag/builtin/adapters/secret/local_secret_adapter.py +248 -0
  38. hexdag/builtin/adapters/unified_tool_router.py +280 -0
  39. hexdag/builtin/macros/__init__.py +17 -0
  40. hexdag/builtin/macros/conversation_agent.py +390 -0
  41. hexdag/builtin/macros/llm_macro.py +151 -0
  42. hexdag/builtin/macros/reasoning_agent.py +423 -0
  43. hexdag/builtin/macros/tool_macro.py +380 -0
  44. hexdag/builtin/nodes/__init__.py +38 -0
  45. hexdag/builtin/nodes/_discovery.py +123 -0
  46. hexdag/builtin/nodes/agent_node.py +696 -0
  47. hexdag/builtin/nodes/base_node_factory.py +242 -0
  48. hexdag/builtin/nodes/composite_node.py +926 -0
  49. hexdag/builtin/nodes/data_node.py +201 -0
  50. hexdag/builtin/nodes/expression_node.py +487 -0
  51. hexdag/builtin/nodes/function_node.py +454 -0
  52. hexdag/builtin/nodes/llm_node.py +491 -0
  53. hexdag/builtin/nodes/loop_node.py +920 -0
  54. hexdag/builtin/nodes/mapped_input.py +518 -0
  55. hexdag/builtin/nodes/port_call_node.py +269 -0
  56. hexdag/builtin/nodes/tool_call_node.py +195 -0
  57. hexdag/builtin/nodes/tool_utils.py +390 -0
  58. hexdag/builtin/prompts/__init__.py +68 -0
  59. hexdag/builtin/prompts/base.py +422 -0
  60. hexdag/builtin/prompts/chat_prompts.py +303 -0
  61. hexdag/builtin/prompts/error_correction_prompts.py +320 -0
  62. hexdag/builtin/prompts/tool_prompts.py +160 -0
  63. hexdag/builtin/tools/builtin_tools.py +84 -0
  64. hexdag/builtin/tools/database_tools.py +164 -0
  65. hexdag/cli/__init__.py +17 -0
  66. hexdag/cli/__main__.py +7 -0
  67. hexdag/cli/commands/__init__.py +27 -0
  68. hexdag/cli/commands/build_cmd.py +812 -0
  69. hexdag/cli/commands/create_cmd.py +208 -0
  70. hexdag/cli/commands/docs_cmd.py +293 -0
  71. hexdag/cli/commands/generate_types_cmd.py +252 -0
  72. hexdag/cli/commands/init_cmd.py +188 -0
  73. hexdag/cli/commands/pipeline_cmd.py +494 -0
  74. hexdag/cli/commands/plugin_dev_cmd.py +529 -0
  75. hexdag/cli/commands/plugins_cmd.py +441 -0
  76. hexdag/cli/commands/studio_cmd.py +101 -0
  77. hexdag/cli/commands/validate_cmd.py +221 -0
  78. hexdag/cli/main.py +84 -0
  79. hexdag/core/__init__.py +83 -0
  80. hexdag/core/config/__init__.py +20 -0
  81. hexdag/core/config/loader.py +479 -0
  82. hexdag/core/config/models.py +150 -0
  83. hexdag/core/configurable.py +294 -0
  84. hexdag/core/context/__init__.py +37 -0
  85. hexdag/core/context/execution_context.py +378 -0
  86. hexdag/core/docs/__init__.py +26 -0
  87. hexdag/core/docs/extractors.py +678 -0
  88. hexdag/core/docs/generators.py +890 -0
  89. hexdag/core/docs/models.py +120 -0
  90. hexdag/core/domain/__init__.py +10 -0
  91. hexdag/core/domain/dag.py +1225 -0
  92. hexdag/core/exceptions.py +234 -0
  93. hexdag/core/expression_parser.py +569 -0
  94. hexdag/core/logging.py +449 -0
  95. hexdag/core/models/__init__.py +17 -0
  96. hexdag/core/models/base.py +138 -0
  97. hexdag/core/orchestration/__init__.py +46 -0
  98. hexdag/core/orchestration/body_executor.py +481 -0
  99. hexdag/core/orchestration/components/__init__.py +97 -0
  100. hexdag/core/orchestration/components/adapter_lifecycle_manager.py +113 -0
  101. hexdag/core/orchestration/components/checkpoint_manager.py +134 -0
  102. hexdag/core/orchestration/components/execution_coordinator.py +360 -0
  103. hexdag/core/orchestration/components/health_check_manager.py +176 -0
  104. hexdag/core/orchestration/components/input_mapper.py +143 -0
  105. hexdag/core/orchestration/components/lifecycle_manager.py +583 -0
  106. hexdag/core/orchestration/components/node_executor.py +377 -0
  107. hexdag/core/orchestration/components/secret_manager.py +202 -0
  108. hexdag/core/orchestration/components/wave_executor.py +158 -0
  109. hexdag/core/orchestration/constants.py +17 -0
  110. hexdag/core/orchestration/events/README.md +312 -0
  111. hexdag/core/orchestration/events/__init__.py +104 -0
  112. hexdag/core/orchestration/events/batching.py +330 -0
  113. hexdag/core/orchestration/events/decorators.py +139 -0
  114. hexdag/core/orchestration/events/events.py +573 -0
  115. hexdag/core/orchestration/events/observers/__init__.py +30 -0
  116. hexdag/core/orchestration/events/observers/core_observers.py +690 -0
  117. hexdag/core/orchestration/events/observers/models.py +111 -0
  118. hexdag/core/orchestration/events/taxonomy.py +269 -0
  119. hexdag/core/orchestration/hook_context.py +237 -0
  120. hexdag/core/orchestration/hooks.py +437 -0
  121. hexdag/core/orchestration/models.py +418 -0
  122. hexdag/core/orchestration/orchestrator.py +910 -0
  123. hexdag/core/orchestration/orchestrator_factory.py +275 -0
  124. hexdag/core/orchestration/port_wrappers.py +327 -0
  125. hexdag/core/orchestration/prompt/__init__.py +32 -0
  126. hexdag/core/orchestration/prompt/template.py +332 -0
  127. hexdag/core/pipeline_builder/__init__.py +21 -0
  128. hexdag/core/pipeline_builder/component_instantiator.py +386 -0
  129. hexdag/core/pipeline_builder/include_tag.py +265 -0
  130. hexdag/core/pipeline_builder/pipeline_config.py +133 -0
  131. hexdag/core/pipeline_builder/py_tag.py +223 -0
  132. hexdag/core/pipeline_builder/tag_discovery.py +268 -0
  133. hexdag/core/pipeline_builder/yaml_builder.py +1196 -0
  134. hexdag/core/pipeline_builder/yaml_validator.py +569 -0
  135. hexdag/core/ports/__init__.py +65 -0
  136. hexdag/core/ports/api_call.py +133 -0
  137. hexdag/core/ports/database.py +489 -0
  138. hexdag/core/ports/embedding.py +215 -0
  139. hexdag/core/ports/executor.py +237 -0
  140. hexdag/core/ports/file_storage.py +117 -0
  141. hexdag/core/ports/healthcheck.py +87 -0
  142. hexdag/core/ports/llm.py +551 -0
  143. hexdag/core/ports/memory.py +70 -0
  144. hexdag/core/ports/observer_manager.py +130 -0
  145. hexdag/core/ports/secret.py +145 -0
  146. hexdag/core/ports/tool_router.py +94 -0
  147. hexdag/core/ports_builder.py +623 -0
  148. hexdag/core/protocols.py +273 -0
  149. hexdag/core/resolver.py +304 -0
  150. hexdag/core/schema/__init__.py +9 -0
  151. hexdag/core/schema/generator.py +742 -0
  152. hexdag/core/secrets.py +242 -0
  153. hexdag/core/types.py +413 -0
  154. hexdag/core/utils/async_warnings.py +206 -0
  155. hexdag/core/utils/schema_conversion.py +78 -0
  156. hexdag/core/utils/sql_validation.py +86 -0
  157. hexdag/core/validation/secure_json.py +148 -0
  158. hexdag/core/yaml_macro.py +517 -0
  159. hexdag/mcp_server.py +3120 -0
  160. hexdag/studio/__init__.py +10 -0
  161. hexdag/studio/build_ui.py +92 -0
  162. hexdag/studio/server/__init__.py +1 -0
  163. hexdag/studio/server/main.py +100 -0
  164. hexdag/studio/server/routes/__init__.py +9 -0
  165. hexdag/studio/server/routes/execute.py +208 -0
  166. hexdag/studio/server/routes/export.py +558 -0
  167. hexdag/studio/server/routes/files.py +207 -0
  168. hexdag/studio/server/routes/plugins.py +419 -0
  169. hexdag/studio/server/routes/validate.py +220 -0
  170. hexdag/studio/ui/index.html +13 -0
  171. hexdag/studio/ui/package-lock.json +2992 -0
  172. hexdag/studio/ui/package.json +31 -0
  173. hexdag/studio/ui/postcss.config.js +6 -0
  174. hexdag/studio/ui/public/hexdag.svg +5 -0
  175. hexdag/studio/ui/src/App.tsx +251 -0
  176. hexdag/studio/ui/src/components/Canvas.tsx +408 -0
  177. hexdag/studio/ui/src/components/ContextMenu.tsx +187 -0
  178. hexdag/studio/ui/src/components/FileBrowser.tsx +123 -0
  179. hexdag/studio/ui/src/components/Header.tsx +181 -0
  180. hexdag/studio/ui/src/components/HexdagNode.tsx +193 -0
  181. hexdag/studio/ui/src/components/NodeInspector.tsx +512 -0
  182. hexdag/studio/ui/src/components/NodePalette.tsx +262 -0
  183. hexdag/studio/ui/src/components/NodePortsSection.tsx +403 -0
  184. hexdag/studio/ui/src/components/PluginManager.tsx +347 -0
  185. hexdag/studio/ui/src/components/PortsEditor.tsx +481 -0
  186. hexdag/studio/ui/src/components/PythonEditor.tsx +195 -0
  187. hexdag/studio/ui/src/components/ValidationPanel.tsx +105 -0
  188. hexdag/studio/ui/src/components/YamlEditor.tsx +196 -0
  189. hexdag/studio/ui/src/components/index.ts +8 -0
  190. hexdag/studio/ui/src/index.css +92 -0
  191. hexdag/studio/ui/src/main.tsx +10 -0
  192. hexdag/studio/ui/src/types/index.ts +123 -0
  193. hexdag/studio/ui/src/vite-env.d.ts +1 -0
  194. hexdag/studio/ui/tailwind.config.js +29 -0
  195. hexdag/studio/ui/tsconfig.json +37 -0
  196. hexdag/studio/ui/tsconfig.node.json +13 -0
  197. hexdag/studio/ui/vite.config.ts +35 -0
  198. hexdag/visualization/__init__.py +69 -0
  199. hexdag/visualization/dag_visualizer.py +1020 -0
  200. hexdag-0.5.0.dev1.dist-info/METADATA +369 -0
  201. hexdag-0.5.0.dev1.dist-info/RECORD +261 -0
  202. hexdag-0.5.0.dev1.dist-info/WHEEL +4 -0
  203. hexdag-0.5.0.dev1.dist-info/entry_points.txt +4 -0
  204. hexdag-0.5.0.dev1.dist-info/licenses/LICENSE +190 -0
  205. hexdag_plugins/.gitignore +43 -0
  206. hexdag_plugins/README.md +73 -0
  207. hexdag_plugins/__init__.py +1 -0
  208. hexdag_plugins/azure/LICENSE +21 -0
  209. hexdag_plugins/azure/README.md +414 -0
  210. hexdag_plugins/azure/__init__.py +21 -0
  211. hexdag_plugins/azure/azure_blob_adapter.py +450 -0
  212. hexdag_plugins/azure/azure_cosmos_adapter.py +383 -0
  213. hexdag_plugins/azure/azure_keyvault_adapter.py +314 -0
  214. hexdag_plugins/azure/azure_openai_adapter.py +415 -0
  215. hexdag_plugins/azure/pyproject.toml +107 -0
  216. hexdag_plugins/azure/tests/__init__.py +1 -0
  217. hexdag_plugins/azure/tests/test_azure_blob_adapter.py +350 -0
  218. hexdag_plugins/azure/tests/test_azure_cosmos_adapter.py +323 -0
  219. hexdag_plugins/azure/tests/test_azure_keyvault_adapter.py +330 -0
  220. hexdag_plugins/azure/tests/test_azure_openai_adapter.py +329 -0
  221. hexdag_plugins/hexdag_etl/README.md +168 -0
  222. hexdag_plugins/hexdag_etl/__init__.py +53 -0
  223. hexdag_plugins/hexdag_etl/examples/01_simple_pandas_transform.py +270 -0
  224. hexdag_plugins/hexdag_etl/examples/02_simple_pandas_only.py +149 -0
  225. hexdag_plugins/hexdag_etl/examples/03_file_io_pipeline.py +109 -0
  226. hexdag_plugins/hexdag_etl/examples/test_pandas_transform.py +84 -0
  227. hexdag_plugins/hexdag_etl/hexdag.toml +25 -0
  228. hexdag_plugins/hexdag_etl/hexdag_etl/__init__.py +48 -0
  229. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/__init__.py +13 -0
  230. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/api_extract.py +230 -0
  231. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/base_node_factory.py +181 -0
  232. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/file_io.py +415 -0
  233. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/outlook.py +492 -0
  234. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/pandas_transform.py +563 -0
  235. hexdag_plugins/hexdag_etl/hexdag_etl/nodes/sql_extract_load.py +112 -0
  236. hexdag_plugins/hexdag_etl/pyproject.toml +82 -0
  237. hexdag_plugins/hexdag_etl/test_transform.py +54 -0
  238. hexdag_plugins/hexdag_etl/tests/test_plugin_integration.py +62 -0
  239. hexdag_plugins/mysql_adapter/LICENSE +21 -0
  240. hexdag_plugins/mysql_adapter/README.md +224 -0
  241. hexdag_plugins/mysql_adapter/__init__.py +6 -0
  242. hexdag_plugins/mysql_adapter/mysql_adapter.py +408 -0
  243. hexdag_plugins/mysql_adapter/pyproject.toml +93 -0
  244. hexdag_plugins/mysql_adapter/tests/test_mysql_adapter.py +259 -0
  245. hexdag_plugins/storage/README.md +184 -0
  246. hexdag_plugins/storage/__init__.py +19 -0
  247. hexdag_plugins/storage/file/__init__.py +5 -0
  248. hexdag_plugins/storage/file/local.py +325 -0
  249. hexdag_plugins/storage/ports/__init__.py +5 -0
  250. hexdag_plugins/storage/ports/vector_store.py +236 -0
  251. hexdag_plugins/storage/sql/__init__.py +7 -0
  252. hexdag_plugins/storage/sql/base.py +187 -0
  253. hexdag_plugins/storage/sql/mysql.py +27 -0
  254. hexdag_plugins/storage/sql/postgresql.py +27 -0
  255. hexdag_plugins/storage/tests/__init__.py +1 -0
  256. hexdag_plugins/storage/tests/test_local_file_storage.py +161 -0
  257. hexdag_plugins/storage/tests/test_sql_adapters.py +212 -0
  258. hexdag_plugins/storage/vector/__init__.py +7 -0
  259. hexdag_plugins/storage/vector/chromadb.py +223 -0
  260. hexdag_plugins/storage/vector/in_memory.py +285 -0
  261. hexdag_plugins/storage/vector/pgvector.py +502 -0
@@ -0,0 +1,130 @@
1
+ """Observer Manager Port - Clean interface for event observation systems.
2
+
3
+ This port defines the complete contract for observer managers, including
4
+ all safety features and configuration options from the concrete implementation.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from abc import abstractmethod
10
+ from collections.abc import Callable, Iterable
11
+ from typing import Any, Protocol
12
+
13
+ from hexdag.core.orchestration.events.events import Event
14
+
15
+ # Type aliases for observer functions
16
+ ObserverFunc = Callable[[Event], None]
17
+ AsyncObserverFunc = Callable[[Event], Any] # Returns awaitable
18
+
19
+
20
+ class Observer(Protocol):
21
+ """Protocol for observers that monitor events."""
22
+
23
+ async def handle(self, event: Event) -> None:
24
+ """Handle an event (read-only, no return value)."""
25
+ ...
26
+
27
+
28
+ class ObserverManagerPort(Protocol):
29
+ """Port interface for event observation systems.
30
+
31
+ Key Safety Guarantees:
32
+ - Observers must be READ-ONLY and cannot affect execution
33
+ - Observer failures must not crash the pipeline (fault isolation)
34
+ - Fire-and-forget pattern with async, non-blocking execution
35
+ - Event type filtering for performance optimization
36
+ - Configurable concurrency control and timeouts
37
+ - Optional weak reference support for memory management
38
+ """
39
+
40
+ @abstractmethod
41
+ def register(
42
+ self,
43
+ handler: Observer | ObserverFunc | AsyncObserverFunc,
44
+ *,
45
+ observer_id: str | None = None,
46
+ event_types: Iterable[type[Event]] | type[Event] | None = None,
47
+ timeout: float | None = None,
48
+ max_concurrency: int | None = None,
49
+ keep_alive: bool = False,
50
+ ) -> str:
51
+ """Register an observer with optional event type filtering.
52
+
53
+ Args
54
+ ----
55
+ handler: Either an Observer protocol implementation or
56
+ a function (sync/async) that takes an event
57
+ observer_id: Optional ID for the observer
58
+ event_types: Event type or collection of types to observe (None = all events)
59
+ timeout: Optional timeout override for this observer
60
+ max_concurrency: Optional per-observer concurrency cap (>= 1)
61
+ keep_alive: Keep a strong reference even when using weak refs
62
+
63
+ Returns
64
+ -------
65
+ str: The ID of the registered observer
66
+ """
67
+ ...
68
+
69
+ @abstractmethod
70
+ def unregister(self, handler_id: str) -> bool:
71
+ """Unregister an observer by ID.
72
+
73
+ Args
74
+ ----
75
+ handler_id: The ID of the observer to unregister
76
+
77
+ Returns
78
+ -------
79
+ bool: True if observer was found and removed, False otherwise
80
+ """
81
+ ...
82
+
83
+ @abstractmethod
84
+ async def notify(self, event: Event) -> None:
85
+ """Notify all interested observers of an event.
86
+
87
+ Only observers registered for this event type will be notified.
88
+ Errors are handled according to the configured error handler
89
+ but don't affect execution.
90
+
91
+ Args
92
+ ----
93
+ event: The event to distribute to observers
94
+ """
95
+ ...
96
+
97
+ @abstractmethod
98
+ def clear(self) -> None:
99
+ """Remove all registered observers."""
100
+ ...
101
+
102
+ @abstractmethod
103
+ async def close(self) -> None:
104
+ """Close the manager and cleanup resources."""
105
+ ...
106
+
107
+ @abstractmethod
108
+ def __len__(self) -> int:
109
+ """Return number of registered observers."""
110
+ ...
111
+
112
+ @abstractmethod
113
+ def __enter__(self) -> ObserverManagerPort:
114
+ """Context manager entry."""
115
+ ...
116
+
117
+ @abstractmethod
118
+ def __exit__(self, _exc_type: Any, _exc_val: Any, _exc_tb: Any) -> None:
119
+ """Context manager exit with cleanup."""
120
+ ...
121
+
122
+ @abstractmethod
123
+ async def __aenter__(self) -> ObserverManagerPort:
124
+ """Async context manager entry."""
125
+ ...
126
+
127
+ @abstractmethod
128
+ async def __aexit__(self, _exc_type: Any, _exc_val: Any, _exc_tb: Any) -> None:
129
+ """Async context manager exit with cleanup."""
130
+ ...
@@ -0,0 +1,145 @@
1
+ """Port interface for secret management (KeyVault, AWS Secrets Manager, etc.)."""
2
+
3
+ from abc import abstractmethod
4
+ from typing import TYPE_CHECKING, Protocol, runtime_checkable
5
+
6
+ if TYPE_CHECKING:
7
+ from hexdag.core.ports.healthcheck import HealthStatus
8
+ from hexdag.core.ports.memory import Memory
9
+ from hexdag.core.types import Secret
10
+
11
+
12
+ @runtime_checkable
13
+ class SecretPort(Protocol):
14
+ """Port interface for secret/credential management systems.
15
+
16
+ This port abstracts access to secret management services like:
17
+ - Azure KeyVault
18
+ - AWS Secrets Manager
19
+ - HashiCorp Vault
20
+ - Google Secret Manager
21
+ - Environment variables
22
+
23
+ Secrets are returned as Secret[str] objects to prevent accidental logging.
24
+
25
+ Optional Methods
26
+ ----------------
27
+ Adapters may optionally implement:
28
+ - ahealth_check(): Verify secret service connectivity and authentication
29
+ """
30
+
31
+ @abstractmethod
32
+ async def aget_secret(self, key: str) -> "Secret":
33
+ """Retrieve a single secret by key.
34
+
35
+ Args
36
+ ----
37
+ key: Secret identifier (e.g., "OPENAI_API_KEY", "database/password")
38
+
39
+ Returns
40
+ -------
41
+ Secret
42
+ Secret wrapper containing the secret value. Use .get() to retrieve the value.
43
+
44
+ Raises
45
+ ------
46
+ KeyError
47
+ If the secret does not exist
48
+ ValueError
49
+ If the secret value is empty or invalid
50
+
51
+ Examples
52
+ --------
53
+ Example usage::
54
+
55
+ # Fetch secret from KeyVault
56
+ secret = await keyvault.aget_secret("OPENAI_API_KEY")
57
+ api_key = secret.get() # Unwrap the secret value
58
+ """
59
+ ...
60
+
61
+ @abstractmethod
62
+ async def aload_secrets_to_memory(
63
+ self,
64
+ memory: "Memory",
65
+ prefix: str = "secret:",
66
+ keys: list[str] | None = None,
67
+ ) -> dict[str, str]:
68
+ """Bulk load secrets into Memory port with a prefix.
69
+
70
+ This is the primary method for pre-DAG hooks to inject secrets
71
+ into the pipeline's memory for nodes to access.
72
+
73
+ Args
74
+ ----
75
+ memory: Memory port instance to store secrets in
76
+ prefix: Key prefix for stored secrets (default: "secret:")
77
+ keys: List of secret keys to load. If None, loads all available secrets.
78
+
79
+ Returns
80
+ -------
81
+ dict[str, str]
82
+ Mapping of original key → memory key (e.g., {"API_KEY": "secret:API_KEY"})
83
+
84
+ Examples
85
+ --------
86
+ Example usage::
87
+
88
+ # Load specific secrets
89
+ mapping = await keyvault.aload_secrets_to_memory(
90
+ memory=memory,
91
+ keys=["OPENAI_API_KEY", "DATABASE_PASSWORD"]
92
+ )
93
+ # Returns: {"OPENAI_API_KEY": "secret:OPENAI_API_KEY", ...}
94
+
95
+ # Load all secrets
96
+ mapping = await keyvault.aload_secrets_to_memory(memory=memory)
97
+
98
+ # Retrieve in nodes
99
+ api_key = await memory.aget("secret:OPENAI_API_KEY")
100
+ """
101
+ ...
102
+
103
+ async def alist_secret_names(self) -> list[str]:
104
+ """List all available secret names (optional).
105
+
106
+ Returns
107
+ -------
108
+ list[str]
109
+ List of secret identifiers available in this secret store
110
+
111
+ Examples
112
+ --------
113
+ Example usage::
114
+
115
+ names = await keyvault.alist_secret_names()
116
+ # ["OPENAI_API_KEY", "DATABASE_PASSWORD", "STRIPE_KEY"]
117
+ """
118
+ ...
119
+
120
+ async def ahealth_check(self) -> "HealthStatus":
121
+ """Check secret service health and connectivity (optional).
122
+
123
+ Adapters should verify:
124
+ - Authentication/authorization status
125
+ - Service connectivity
126
+ - Access permissions
127
+
128
+ This method is optional. If not implemented, the adapter will be
129
+ considered healthy by default.
130
+
131
+ Returns
132
+ -------
133
+ HealthStatus
134
+ Current health status with details about secret service connectivity
135
+
136
+ Examples
137
+ --------
138
+ Example usage::
139
+
140
+ # Azure KeyVault health check
141
+ status = await keyvault.ahealth_check()
142
+ status.status # "healthy", "degraded", or "unhealthy"
143
+ status.details # {"vault_url": "...", "authenticated": True}
144
+ """
145
+ ...
@@ -0,0 +1,94 @@
1
+ """Port interface for Tool Routers."""
2
+
3
+ from abc import abstractmethod
4
+ from typing import Any, Protocol, runtime_checkable
5
+
6
+
7
+ @runtime_checkable
8
+ class ToolRouter(Protocol):
9
+ """Protocol for routing tool calls."""
10
+
11
+ # Required methods
12
+ @abstractmethod
13
+ async def acall_tool(self, tool_name: str, params: dict[str, Any]) -> Any:
14
+ """Call a tool with parameters.
15
+
16
+ Args
17
+ ----
18
+ tool_name: The name of the tool to call.
19
+ params: Parameters to pass to the tool.
20
+
21
+ Returns
22
+ -------
23
+ The result of the tool call.
24
+ """
25
+ ...
26
+
27
+ @abstractmethod
28
+ def get_available_tools(self) -> list[str]:
29
+ """Get list of available tool names (sync version for local adapters).
30
+
31
+ Returns
32
+ -------
33
+ List of tool names that can be called
34
+ """
35
+ ...
36
+
37
+ async def aget_available_tools(self) -> list[str]:
38
+ """Get list of available tool names (async version for remote/MCP adapters).
39
+
40
+ Default implementation delegates to sync version. Override for true async behavior.
41
+
42
+ Returns
43
+ -------
44
+ List of tool names that can be called
45
+ """
46
+ return self.get_available_tools()
47
+
48
+ def get_tool_schema(self, tool_name: str) -> dict[str, Any]:
49
+ """Get schema for a specific tool (sync version).
50
+
51
+ Args
52
+ ----
53
+ tool_name: Name of the tool
54
+
55
+ Returns
56
+ -------
57
+ Dictionary containing tool schema (name, description, parameters)
58
+ """
59
+ ...
60
+
61
+ async def aget_tool_schema(self, tool_name: str) -> dict[str, Any]:
62
+ """Get schema for a specific tool (async version for remote/MCP adapters).
63
+
64
+ Default implementation delegates to sync version. Override for true async behavior.
65
+
66
+ Args
67
+ ----
68
+ tool_name: Name of the tool
69
+
70
+ Returns
71
+ -------
72
+ Dictionary containing tool schema (name, description, parameters)
73
+ """
74
+ return self.get_tool_schema(tool_name)
75
+
76
+ def get_all_tool_schemas(self) -> dict[str, dict[str, Any]]:
77
+ """Get schemas for all available tools (sync version).
78
+
79
+ Returns
80
+ -------
81
+ Dictionary mapping tool names to their schemas
82
+ """
83
+ ...
84
+
85
+ async def aget_all_tool_schemas(self) -> dict[str, dict[str, Any]]:
86
+ """Get schemas for all available tools (async version for remote/MCP adapters).
87
+
88
+ Default implementation delegates to sync version. Override for true async behavior.
89
+
90
+ Returns
91
+ -------
92
+ Dictionary mapping tool names to their schemas
93
+ """
94
+ return self.get_all_tool_schemas()