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,160 @@
1
+ """Composable tool usage prompt templates.
2
+
3
+ These prompts provide tool calling instructions that can be composed
4
+ with other prompts using the builder pattern.
5
+ """
6
+
7
+ from hexdag.builtin.nodes.tool_utils import ToolCallFormat
8
+ from hexdag.core.orchestration.prompt.template import PromptTemplate
9
+
10
+
11
+ class FunctionToolPrompt(PromptTemplate):
12
+ """Tool usage prompt for function-style tool calls.
13
+
14
+ Format: INVOKE_TOOL: tool_name(param='value')
15
+
16
+ This prompt is composable - add it to any base prompt:
17
+ main_prompt + FunctionToolPrompt()
18
+
19
+ Examples
20
+ --------
21
+ Standalone usage:
22
+ >>> prompt = FunctionToolPrompt()
23
+ >>> text = prompt.render(
24
+ ... tools="search(query), calculator(expression)",
25
+ ... tool_schemas=[...]
26
+ ... )
27
+
28
+ Composed with main prompt:
29
+ >>> main = PromptTemplate("Analyze {{data}}")
30
+ >>> full_prompt = main + FunctionToolPrompt()
31
+ """
32
+
33
+ def __init__(self) -> None:
34
+ """Initialize function-style tool prompt template."""
35
+ template = """
36
+ ## Available Tools
37
+ {{tools}}
38
+
39
+ ## Usage Guidelines
40
+ - Call ONE tool at a time using: INVOKE_TOOL: tool_name(param='value')
41
+ - Use single quotes for string parameters
42
+ - For final answer and structured output: INVOKE_TOOL: tool_end(field1='value1', field2='value2')
43
+ - For phase change: INVOKE_TOOL: change_phase(phase='new_phase', reason='why changing', carried_data={'key': 'value'})
44
+
45
+ ## Examples
46
+ INVOKE_TOOL: search(query='latest AI news')
47
+ INVOKE_TOOL: calculator(expression='2 + 2')
48
+ INVOKE_TOOL: tool_end(result='Analysis complete', confidence='high')
49
+ """
50
+ super().__init__(template, input_vars=["tools"])
51
+
52
+
53
+ class JsonToolPrompt(PromptTemplate):
54
+ """Tool usage prompt for JSON-style tool calls.
55
+
56
+ Format: INVOKE_TOOL: {"tool": "tool_name", "params": {"param": "value"}}
57
+
58
+ This prompt is composable - add it to any base prompt:
59
+ main_prompt + JsonToolPrompt()
60
+
61
+ Examples
62
+ --------
63
+ Standalone usage:
64
+ >>> prompt = JsonToolPrompt()
65
+ >>> text = prompt.render(tools="search, calculator", tool_schemas=[...])
66
+
67
+ Composed with main prompt:
68
+ >>> main = PromptTemplate("Analyze {{data}}")
69
+ >>> full_prompt = main + JsonToolPrompt()
70
+ """
71
+
72
+ def __init__(self) -> None:
73
+ """Initialize JSON-style tool prompt template."""
74
+ template = """
75
+ ## Available Tools
76
+ {{tools}}
77
+
78
+ ## Usage Guidelines
79
+ - Call ONE tool at a time using JSON format
80
+ - Format: INVOKE_TOOL: {"tool": "tool_name", "params": {"param": "value"}}
81
+ - Use valid JSON syntax with double quotes
82
+ - For final answer: INVOKE_TOOL: {"tool": "tool_end", "params": {"field1": "value1", "field2": "value2"}}
83
+ - For phase change: INVOKE_TOOL: {"tool": "change_phase", "params": {"phase": "new_phase", "reason": "why", "carried_data": {"key": "val"}}}
84
+
85
+ ## Examples
86
+ INVOKE_TOOL: {"tool": "search", "params": {"query": "latest AI news"}}
87
+ INVOKE_TOOL: {"tool": "calculator", "params": {"expression": "2 + 2"}}
88
+ INVOKE_TOOL: {"tool": "tool_end", "params": {"result": "Analysis complete", "confidence": "high"}}
89
+ """
90
+ super().__init__(template, input_vars=["tools"])
91
+
92
+
93
+ class MixedToolPrompt(PromptTemplate):
94
+ """Tool usage prompt supporting both function and JSON styles.
95
+
96
+ Format: Either function or JSON style
97
+ - Function: INVOKE_TOOL: tool_name(param='value')
98
+ - JSON: INVOKE_TOOL: {"tool": "tool_name", "params": {"param": "value"}}
99
+
100
+ This prompt is composable - add it to any base prompt:
101
+ main_prompt + MixedToolPrompt()
102
+
103
+ Examples
104
+ --------
105
+ Standalone usage:
106
+ >>> prompt = MixedToolPrompt()
107
+ >>> text = prompt.render(tools="search, calculator", tool_schemas=[...])
108
+
109
+ Composed with main prompt:
110
+ >>> main = PromptTemplate("Analyze {{data}}")
111
+ >>> full_prompt = main + MixedToolPrompt()
112
+ """
113
+
114
+ def __init__(self) -> None:
115
+ """Initialize mixed-style tool prompt template."""
116
+ template = """
117
+ ## Available Tools
118
+ {{tools}}
119
+
120
+ ## Usage Guidelines
121
+ - Call ONE tool at a time using either format:
122
+ - Function style: INVOKE_TOOL: tool_name(param='value')
123
+ - JSON style: INVOKE_TOOL: {"tool": "tool_name", "params": {"param": "value"}}
124
+
125
+ ### Function Style Examples
126
+ INVOKE_TOOL: search(query='latest AI news')
127
+ INVOKE_TOOL: tool_end(result='Analysis complete', confidence='high')
128
+ INVOKE_TOOL: change_phase(phase='refinement', reason='need more data', carried_data={'initial': 'findings'})
129
+
130
+ ### JSON Style Examples
131
+ INVOKE_TOOL: {"tool": "search", "params": {"query": "latest AI news"}}
132
+ INVOKE_TOOL: {"tool": "tool_end", "params": {"result": "Analysis complete", "confidence": "high"}}
133
+ INVOKE_TOOL: {"tool": "change_phase", "params": {"phase": "refinement", "reason": "need more data", "carried_data": {"initial": "findings"}}}
134
+ """
135
+ super().__init__(template, input_vars=["tools"])
136
+
137
+
138
+ def get_tool_prompt_for_format(format_style: ToolCallFormat) -> type[PromptTemplate]:
139
+ """Get the appropriate tool prompt class for a given format.
140
+
141
+ Args
142
+ ----
143
+ format_style: Tool call format (FUNCTION_CALL, JSON, or MIXED)
144
+
145
+ Returns
146
+ -------
147
+ type[PromptTemplate]
148
+ Appropriate tool prompt class
149
+
150
+ Examples
151
+ --------
152
+ >>> PromptClass = get_tool_prompt_for_format(ToolCallFormat.FUNCTION_CALL)
153
+ >>> prompt = PromptClass()
154
+ >>> text = prompt.render(tools="search, calculator")
155
+ """
156
+ if format_style == ToolCallFormat.FUNCTION_CALL:
157
+ return FunctionToolPrompt
158
+ if format_style == ToolCallFormat.JSON:
159
+ return JsonToolPrompt
160
+ return MixedToolPrompt
@@ -0,0 +1,84 @@
1
+ """Built-in tools that are essential for agent operations."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ if TYPE_CHECKING:
6
+ from hexdag.builtin.nodes.agent_node import PhaseContext
7
+
8
+
9
+ def tool_end(**kwargs: Any) -> dict[str, Any]:
10
+ """End tool execution with structured output.
11
+
12
+ This is a built-in tool that agents can use to return
13
+ structured data matching their output schema.
14
+
15
+ Args
16
+ ----
17
+ **kwargs: Any structured data to return
18
+
19
+ Returns
20
+ -------
21
+ The structured data as provided
22
+ """
23
+ return kwargs
24
+
25
+
26
+ def change_phase(
27
+ phase: str,
28
+ previous_phase: str | None = None,
29
+ reason: str | None = None,
30
+ carried_data: dict[str, Any] | None = None,
31
+ target_output: str | None = None,
32
+ iteration: int | None = None,
33
+ metadata: dict[str, Any] | None = None,
34
+ ) -> dict[str, Any]:
35
+ """Change the agent's reasoning phase with typed context.
36
+
37
+ This tool allows agents to transition between different
38
+ reasoning phases with strongly-typed context data.
39
+
40
+ Args
41
+ ----
42
+ phase: The new phase name to transition to
43
+ previous_phase: The phase being transitioned from (auto-filled if not provided)
44
+ reason: Explanation for why the phase change is occurring
45
+ carried_data: Data to carry forward from the previous phase
46
+ target_output: Expected output format or goal for the new phase
47
+ iteration: Current iteration number if in a loop or retry scenario
48
+ metadata: Additional metadata about the phase transition
49
+
50
+ Returns
51
+ -------
52
+ Dictionary with phase change information including:
53
+ - action: Always "change_phase"
54
+ - new_phase: The phase being transitioned to
55
+ - context: PhaseContext-typed data
56
+
57
+ Examples
58
+ --------
59
+ >>> change_phase("analysis", reason="Initial data gathering complete")
60
+ {'action': 'change_phase', 'new_phase': 'analysis', 'context': {'reason':
61
+ 'Initial data gathering complete'}}
62
+
63
+ >>> change_phase("synthesis",
64
+ ... previous_phase="analysis",
65
+ ... carried_data={"key_findings": ["item1", "item2"]},
66
+ ... iteration=2)
67
+ {'action': 'change_phase', 'new_phase': 'synthesis', 'context': {...}}
68
+ """
69
+ context: PhaseContext = {}
70
+
71
+ if previous_phase is not None:
72
+ context["previous_phase"] = previous_phase
73
+ if reason is not None:
74
+ context["reason"] = reason
75
+ if carried_data is not None:
76
+ context["carried_data"] = carried_data
77
+ if target_output is not None:
78
+ context["target_output"] = target_output
79
+ if iteration is not None:
80
+ context["iteration"] = iteration
81
+ if metadata is not None:
82
+ context["metadata"] = metadata
83
+
84
+ return {"action": "change_phase", "new_phase": phase, "context": context}
@@ -0,0 +1,164 @@
1
+ """Database-related tools that require database port."""
2
+
3
+ import asyncio
4
+ from typing import Any
5
+
6
+ from hexdag.core.exceptions import DependencyError
7
+ from hexdag.core.ports.database import DatabasePort
8
+
9
+
10
+ async def database_query(
11
+ sql: str, params: dict[str, Any] | None = None, database_port: DatabasePort | None = None
12
+ ) -> list[dict[str, Any]]:
13
+ """Execute a SQL query on the database.
14
+
15
+ This tool requires a database port to be available.
16
+ The database port will be injected when the tool is executed.
17
+
18
+ Args
19
+ ----
20
+ sql: SQL query to execute
21
+ params: Optional parameters for parameterized queries
22
+ database_port: Injected database port (provided by framework)
23
+
24
+ Returns
25
+ -------
26
+ List of dictionaries representing query results
27
+
28
+ Raises
29
+ ------
30
+ DependencyError
31
+ If database port is not provided
32
+ """
33
+ if database_port is None:
34
+ raise DependencyError("database_port", "required for database query execution")
35
+
36
+ # Use the database port to execute the query
37
+ return await database_port.aexecute_query(sql, params or {})
38
+
39
+
40
+ async def database_execute(
41
+ sql: str, params: dict[str, Any] | None = None, database_port: Any | None = None
42
+ ) -> None:
43
+ """Execute a SQL command (INSERT, UPDATE, DELETE) on the database.
44
+
45
+ This tool requires a database port to be available.
46
+
47
+ Args
48
+ ----
49
+ sql: SQL command to execute
50
+ params: Optional parameters for parameterized queries
51
+ database_port: Injected database port (provided by framework)
52
+
53
+ Raises
54
+ ------
55
+ DependencyError
56
+ If database port is not provided
57
+ """
58
+ if database_port is None:
59
+ raise DependencyError("database_port", "required for database query execution")
60
+
61
+ # Execute returns no value, just runs the query
62
+ await database_port.aexecute_query(sql, params or {})
63
+
64
+
65
+ async def list_tables(database_port: DatabasePort | None = None) -> list[str]:
66
+ """List all tables in the database.
67
+
68
+ Args
69
+ ----
70
+ database_port: Injected database port
71
+
72
+ Returns
73
+ -------
74
+ List of table names
75
+
76
+ Raises
77
+ ------
78
+ DependencyError
79
+ If database port is not provided
80
+ """
81
+ if database_port is None:
82
+ raise DependencyError("database_port", "required for database query execution")
83
+
84
+ # Standard SQL to get table list (may vary by database)
85
+ sql = """
86
+ SELECT table_name
87
+ FROM information_schema.tables
88
+ WHERE table_schema = 'public'
89
+ """
90
+
91
+ results = await database_port.aexecute_query(sql)
92
+ return [row["table_name"] for row in results]
93
+
94
+
95
+ async def describe_table(
96
+ table: str, database_port: DatabasePort | None = None
97
+ ) -> list[dict[str, Any]]:
98
+ """Get schema information for a database table.
99
+
100
+ Args
101
+ ----
102
+ table: Name of the table
103
+ database_port: Injected database port
104
+
105
+ Returns
106
+ -------
107
+ List of column information
108
+
109
+ Raises
110
+ ------
111
+ DependencyError
112
+ If database port is not provided
113
+ """
114
+ if database_port is None:
115
+ raise DependencyError("database_port", "required for database query execution")
116
+
117
+ sql = """
118
+ SELECT
119
+ column_name,
120
+ data_type,
121
+ is_nullable,
122
+ column_default
123
+ FROM information_schema.columns
124
+ WHERE table_name = :table
125
+ ORDER BY ordinal_position
126
+ """
127
+
128
+ return await database_port.aexecute_query(sql, {"table": table})
129
+
130
+
131
+ # Synchronous versions for compatibility
132
+ def database_query_sync(
133
+ sql: str, params: dict[str, Any] | None = None, database_port: DatabasePort | None = None
134
+ ) -> list[dict[str, Any]]:
135
+ """Execute a database query synchronously.
136
+
137
+ Args
138
+ ----
139
+ sql: SQL query to execute
140
+ params: Optional parameters
141
+ database_port: Injected database port
142
+
143
+ Returns
144
+ -------
145
+ Query results
146
+
147
+ Raises
148
+ ------
149
+ DependencyError
150
+ If database port is not provided
151
+ """
152
+ if database_port is None:
153
+ raise DependencyError("database_port", "required for database query execution")
154
+ return asyncio.run(database_port.aexecute_query(sql, params or {}))
155
+
156
+
157
+ # Export key tools
158
+ __all__ = [
159
+ "database_query",
160
+ "database_execute",
161
+ "list_tables",
162
+ "describe_table",
163
+ "database_query_sync",
164
+ ]
hexdag/cli/__init__.py ADDED
@@ -0,0 +1,17 @@
1
+ """Command-line interface for HexDAG.
2
+
3
+ Note: The CLI requires the 'cli' extra to be installed:
4
+ pip install hexdag[cli]
5
+ or
6
+ uv pip install hexdag[cli]
7
+ """
8
+
9
+
10
+ def main() -> None:
11
+ """Entry point for HexDAG CLI."""
12
+ from hexdag.cli.main import main as cli_main
13
+
14
+ return cli_main()
15
+
16
+
17
+ __all__ = ["main"]
hexdag/cli/__main__.py ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env python3
2
+ """Entry point for HexDAG CLI when run as python -m hexdag.cli."""
3
+
4
+ if __name__ == "__main__":
5
+ from hexdag.cli.main import main
6
+
7
+ main()
@@ -0,0 +1,27 @@
1
+ """CLI command modules."""
2
+
3
+ from . import (
4
+ build_cmd,
5
+ create_cmd,
6
+ docs_cmd,
7
+ generate_types_cmd,
8
+ init_cmd,
9
+ pipeline_cmd,
10
+ plugin_dev_cmd,
11
+ plugins_cmd,
12
+ studio_cmd,
13
+ validate_cmd,
14
+ )
15
+
16
+ __all__ = [
17
+ "build_cmd",
18
+ "create_cmd",
19
+ "docs_cmd",
20
+ "generate_types_cmd",
21
+ "init_cmd",
22
+ "pipeline_cmd",
23
+ "plugin_dev_cmd",
24
+ "plugins_cmd",
25
+ "studio_cmd",
26
+ "validate_cmd",
27
+ ]