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,390 @@
1
+ """Enhanced tool utilities for agent nodes.
2
+
3
+ Supports multiple tool calling formats and tool description management.
4
+ """
5
+
6
+ import json
7
+ import re
8
+ from dataclasses import dataclass
9
+ from enum import StrEnum
10
+ from typing import Any
11
+
12
+ from pydantic import BaseModel, Field
13
+
14
+ from hexdag.core.validation.secure_json import SafeJSON
15
+
16
+
17
+ class ToolCallFormat(StrEnum):
18
+ """Tool calling formats supported by INVOKE_TOOL: prefix."""
19
+
20
+ FUNCTION_CALL = "function_call" # INVOKE_TOOL: tool_name(param1='value1')
21
+ JSON = "json" # INVOKE_TOOL: {"tool": "tool_name", "params": {...}}
22
+ MIXED = "mixed" # Support both formats
23
+
24
+
25
+ class ToolParameter(BaseModel):
26
+ """Definition of a tool parameter."""
27
+
28
+ name: str = Field(..., description="Parameter name")
29
+ description: str = Field(..., description="Parameter description")
30
+ param_type: str = Field(default="str", description="Parameter type")
31
+ required: bool = Field(default=True, description="Whether parameter is required")
32
+ default: Any = Field(default=None, description="Default value if not required")
33
+
34
+
35
+ class ToolDefinition(BaseModel):
36
+ """Complete tool definition with descriptions and parameters."""
37
+
38
+ name: str = Field(..., description="Tool name")
39
+ simplified_description: str = Field(..., description="Brief tool description")
40
+ detailed_description: str = Field(..., description="Detailed tool description")
41
+ parameters: list[ToolParameter] = Field(default_factory=list, description="Tool parameters")
42
+ examples: list[str] = Field(default_factory=list, description="Usage examples")
43
+
44
+ def to_simplified_string(self) -> str:
45
+ """Convert to simplified string format.
46
+
47
+ Returns
48
+ -------
49
+ str
50
+ Simplified string representation of the tool
51
+ """
52
+ return f"{self.name}: {self.simplified_description}"
53
+
54
+ def to_detailed_string(self) -> str:
55
+ """Convert to detailed string format.
56
+
57
+ Returns
58
+ -------
59
+ str
60
+ Detailed string representation of the tool with parameters and examples
61
+ """
62
+ lines = [f"Tool: {self.name}", f"Description: {self.detailed_description}", "Parameters:"]
63
+
64
+ for param in self.parameters:
65
+ req_str = "required" if param.required else "optional"
66
+ lines.append(f" - {param.name} ({param.param_type}, {req_str}): {param.description}")
67
+
68
+ if self.examples:
69
+ lines.append("Examples:")
70
+ lines.extend(f" {example}" for example in self.examples)
71
+
72
+ return "\n".join(lines)
73
+
74
+
75
+ @dataclass(frozen=True, slots=True)
76
+ class ToolCall:
77
+ """Parsed tool call information."""
78
+
79
+ name: str
80
+ params: dict[str, Any]
81
+ format: ToolCallFormat
82
+ raw_text: str
83
+
84
+
85
+ class ToolParser:
86
+ """Parse tool calls with INVOKE_TOOL: prefix for clear identification."""
87
+
88
+ # Function call pattern with INVOKE_TOOL: prefix (supports namespace:tool_name)
89
+ INVOKE_TOOL_PATTERN = re.compile(
90
+ r"INVOKE_TOOL:\s*([\w:]+)\s*\(\s*((?:[^()]*(?:\([^()]*\)[^()]*)*)*)\s*\)"
91
+ )
92
+
93
+ # JSON pattern with INVOKE_TOOL: prefix
94
+ INVOKE_TOOL_JSON_PATTERN = re.compile(r"INVOKE_TOOL:\s*(\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\})")
95
+
96
+ # Parameter parsing pattern
97
+ PARAM_PATTERN = re.compile(r"(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\"|([^,\s\)]+))")
98
+
99
+ @classmethod
100
+ def parse_tool_calls(
101
+ cls, text: str, format: ToolCallFormat = ToolCallFormat.MIXED
102
+ ) -> list[ToolCall]:
103
+ """Extract all tool calls from text using INVOKE_TOOL: prefix.
104
+
105
+ Returns
106
+ -------
107
+ list[ToolCall]
108
+ List of parsed tool calls found in the text
109
+ """
110
+ calls = []
111
+
112
+ if format in (ToolCallFormat.FUNCTION_CALL, ToolCallFormat.MIXED):
113
+ calls.extend(cls._parse_function_calls(text))
114
+
115
+ if format in (ToolCallFormat.JSON, ToolCallFormat.MIXED):
116
+ calls.extend(cls._parse_json_calls(text))
117
+
118
+ return calls
119
+
120
+ @classmethod
121
+ def _parse_function_calls(cls, text: str) -> list[ToolCall]:
122
+ """Parse function calls with INVOKE_TOOL: prefix.
123
+
124
+ Returns
125
+ -------
126
+ list[ToolCall]
127
+ List of parsed function-style tool calls
128
+ """
129
+ calls = []
130
+
131
+ for match in cls.INVOKE_TOOL_PATTERN.finditer(text):
132
+ tool_name = match.group(1)
133
+ args_str = match.group(2)
134
+ params = cls._parse_parameters(args_str)
135
+
136
+ calls.append(
137
+ ToolCall(
138
+ name=tool_name,
139
+ params=params,
140
+ format=ToolCallFormat.FUNCTION_CALL,
141
+ raw_text=match.group(0),
142
+ )
143
+ )
144
+
145
+ return calls
146
+
147
+ @classmethod
148
+ def _parse_json_calls(cls, text: str) -> list[ToolCall]:
149
+ """Parse JSON calls with INVOKE_TOOL: prefix.
150
+
151
+ Returns
152
+ -------
153
+ list[ToolCall]
154
+ List of parsed JSON-style tool calls
155
+ """
156
+ calls = []
157
+
158
+ for match in cls.INVOKE_TOOL_JSON_PATTERN.finditer(text):
159
+ try:
160
+ json_str = match.group(1)
161
+ data = SafeJSON().loads(json_str)
162
+
163
+ if isinstance(data, dict) and "tool" in data:
164
+ calls.append(
165
+ ToolCall(
166
+ name=data["tool"],
167
+ params=data.get("params", {}),
168
+ format=ToolCallFormat.JSON,
169
+ raw_text=match.group(0),
170
+ )
171
+ )
172
+
173
+ except json.JSONDecodeError:
174
+ continue
175
+
176
+ return calls
177
+
178
+ @classmethod
179
+ def _parse_parameters(cls, args_str: str) -> dict[str, Any]:
180
+ """Parse function parameters from argument string.
181
+
182
+ Returns
183
+ -------
184
+ dict[str, Any]
185
+ Dictionary of parsed parameter names and values
186
+ """
187
+ params = {}
188
+
189
+ for match in cls.PARAM_PATTERN.finditer(args_str):
190
+ key = match.group(1)
191
+ value = match.group(2) or match.group(3) or match.group(4)
192
+
193
+ # Try to parse as JSON for complex types
194
+ try:
195
+ params[key] = json.loads(value)
196
+ except (json.JSONDecodeError, TypeError):
197
+ params[key] = value
198
+
199
+ return params
200
+
201
+
202
+ class ToolSchemaConverter:
203
+ """Convert ToolDefinition to various LLM provider formats."""
204
+
205
+ @staticmethod
206
+ def to_openai_schema(tool_def: ToolDefinition) -> dict[str, Any]:
207
+ """Convert ToolDefinition to OpenAI function calling format.
208
+
209
+ Args
210
+ ----
211
+ tool_def: Tool definition to convert
212
+
213
+ Returns
214
+ -------
215
+ dict[str, Any]
216
+ OpenAI-compatible tool schema
217
+ """
218
+ properties = {}
219
+ required = []
220
+
221
+ for param in tool_def.parameters:
222
+ # Map Python types to JSON Schema types
223
+ json_type = ToolSchemaConverter._python_type_to_json_type(param.param_type)
224
+
225
+ properties[param.name] = {"type": json_type, "description": param.description}
226
+
227
+ if param.required:
228
+ required.append(param.name)
229
+
230
+ return {
231
+ "type": "function",
232
+ "function": {
233
+ "name": tool_def.name,
234
+ "description": tool_def.detailed_description,
235
+ "parameters": {
236
+ "type": "object",
237
+ "properties": properties,
238
+ "required": required,
239
+ },
240
+ },
241
+ }
242
+
243
+ @staticmethod
244
+ def to_anthropic_schema(tool_def: ToolDefinition) -> dict[str, Any]:
245
+ """Convert ToolDefinition to Anthropic tool use format.
246
+
247
+ Args
248
+ ----
249
+ tool_def: Tool definition to convert
250
+
251
+ Returns
252
+ -------
253
+ dict[str, Any]
254
+ Anthropic-compatible tool schema
255
+ """
256
+ properties = {}
257
+ required = []
258
+
259
+ for param in tool_def.parameters:
260
+ json_type = ToolSchemaConverter._python_type_to_json_type(param.param_type)
261
+
262
+ properties[param.name] = {"type": json_type, "description": param.description}
263
+
264
+ if param.required:
265
+ required.append(param.name)
266
+
267
+ return {
268
+ "name": tool_def.name,
269
+ "description": tool_def.detailed_description,
270
+ "input_schema": {
271
+ "type": "object",
272
+ "properties": properties,
273
+ "required": required,
274
+ },
275
+ }
276
+
277
+ @staticmethod
278
+ def _python_type_to_json_type(python_type: str) -> str:
279
+ """Map Python type strings to JSON Schema types.
280
+
281
+ Args
282
+ ----
283
+ python_type: Python type as string (e.g., "str", "int")
284
+
285
+ Returns
286
+ -------
287
+ str
288
+ JSON Schema type
289
+ """
290
+ type_mapping = {
291
+ "str": "string",
292
+ "int": "integer",
293
+ "float": "number",
294
+ "bool": "boolean",
295
+ "list": "array",
296
+ "dict": "object",
297
+ }
298
+
299
+ # Handle generic types like list[str], dict[str, int]
300
+ base_type = python_type.split("[")[0].strip()
301
+
302
+ return type_mapping.get(base_type, "string")
303
+
304
+
305
+ class ToolDescriptionManager:
306
+ """Manage tool descriptions with simplified/detailed views."""
307
+
308
+ def __init__(self) -> None:
309
+ """Initialize tool description manager."""
310
+ self.tools: dict[str, ToolDefinition] = {}
311
+
312
+ def register_tool(self, tool_def: ToolDefinition) -> None:
313
+ """Register a tool definition.
314
+
315
+ Parameters
316
+ ----------
317
+ tool_def : ToolDefinition
318
+ The tool definition to register
319
+ """
320
+ self.tools[tool_def.name] = tool_def
321
+
322
+ def register_tools(self, tool_defs: list[ToolDefinition]) -> None:
323
+ """Register multiple tool definitions.
324
+
325
+ Parameters
326
+ ----------
327
+ tool_defs : list[ToolDefinition]
328
+ List of tool definitions to register
329
+ """
330
+ for tool_def in tool_defs:
331
+ self.register_tool(tool_def)
332
+
333
+ def get_simplified_descriptions(self) -> str:
334
+ """Get simplified tool descriptions for prompt.
335
+
336
+ Returns
337
+ -------
338
+ str
339
+ Formatted string with simplified tool descriptions
340
+ """
341
+ lines = ["Available tools:"]
342
+
343
+ lines.extend(f"- {tool.to_simplified_string()}" for tool in self.tools.values())
344
+
345
+ return "\n".join(lines)
346
+
347
+ def get_detailed_descriptions(self) -> str:
348
+ """Get detailed tool descriptions for prompt.
349
+
350
+ Returns
351
+ -------
352
+ str
353
+ Formatted string with detailed tool descriptions
354
+ """
355
+ lines = ["Available tools (detailed):"]
356
+
357
+ for tool in self.tools.values():
358
+ lines.append(tool.to_detailed_string())
359
+ lines.append("") # Add spacing between tools
360
+
361
+ return "\n".join(lines)
362
+
363
+ def get_detailed_description(self, tool_name: str) -> str:
364
+ """Get detailed description for a specific tool.
365
+
366
+ Returns
367
+ -------
368
+ str
369
+ Detailed description of the specified tool
370
+ """
371
+ tool = self.tools.get(tool_name)
372
+ if not tool:
373
+ return f"No description available for tool: {tool_name}"
374
+
375
+ return tool.to_detailed_string()
376
+
377
+ def create_tool_check_function(self) -> Any:
378
+ """Create a function that returns detailed tool descriptions.
379
+
380
+ Returns
381
+ -------
382
+ Callable[[str], str]
383
+ Async function that takes a tool name and returns its detailed description
384
+ """
385
+
386
+ async def check_tool_description(tool_name: str) -> str:
387
+ """Get detailed description for a tool."""
388
+ return self.get_detailed_description(tool_name)
389
+
390
+ return check_tool_description
@@ -0,0 +1,68 @@
1
+ """Builtin composable prompt templates for hexDAG.
2
+
3
+ This module provides reusable, registry-based prompt templates that can be
4
+ composed using the builder pattern:
5
+
6
+ main_prompt + tool_prompt + fewshot_prompt
7
+
8
+ All prompts are registered in the component registry and can be referenced
9
+ in YAML configurations or composed programmatically.
10
+ """
11
+
12
+ from hexdag.builtin.prompts.base import (
13
+ ChatFewShotTemplate,
14
+ ChatPromptTemplate,
15
+ FewShotPromptTemplate,
16
+ )
17
+ from hexdag.builtin.prompts.chat_prompts import (
18
+ ChatAnalysisPrompt,
19
+ ChatConversationalPrompt,
20
+ ChatFewShotQAPrompt,
21
+ ChatQAPrompt,
22
+ FewShotClassificationPrompt,
23
+ FewShotExtractionPrompt,
24
+ create_chat_prompt,
25
+ create_fewshot_prompt,
26
+ )
27
+ from hexdag.builtin.prompts.error_correction_prompts import (
28
+ GenericParseErrorPrompt,
29
+ JsonParseErrorPrompt,
30
+ JsonValidationErrorPrompt,
31
+ MarkdownJsonErrorPrompt,
32
+ SafeJsonInstructionsPrompt,
33
+ get_error_correction_prompt,
34
+ )
35
+ from hexdag.builtin.prompts.tool_prompts import (
36
+ FunctionToolPrompt,
37
+ JsonToolPrompt,
38
+ MixedToolPrompt,
39
+ )
40
+
41
+ __all__ = [
42
+ # Base template classes
43
+ "ChatPromptTemplate",
44
+ "FewShotPromptTemplate",
45
+ "ChatFewShotTemplate",
46
+ # Tool prompts
47
+ "FunctionToolPrompt",
48
+ "JsonToolPrompt",
49
+ "MixedToolPrompt",
50
+ # Chat prompts
51
+ "ChatQAPrompt",
52
+ "ChatAnalysisPrompt",
53
+ "ChatConversationalPrompt",
54
+ "ChatFewShotQAPrompt",
55
+ # Few-shot prompts
56
+ "FewShotClassificationPrompt",
57
+ "FewShotExtractionPrompt",
58
+ # Error correction prompts
59
+ "JsonParseErrorPrompt",
60
+ "JsonValidationErrorPrompt",
61
+ "MarkdownJsonErrorPrompt",
62
+ "SafeJsonInstructionsPrompt",
63
+ "GenericParseErrorPrompt",
64
+ "get_error_correction_prompt",
65
+ # Factories
66
+ "create_chat_prompt",
67
+ "create_fewshot_prompt",
68
+ ]