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.
- hexdag/__init__.py +116 -0
- hexdag/__main__.py +30 -0
- hexdag/adapters/executors/__init__.py +5 -0
- hexdag/adapters/executors/local_executor.py +316 -0
- hexdag/builtin/__init__.py +6 -0
- hexdag/builtin/adapters/__init__.py +51 -0
- hexdag/builtin/adapters/anthropic/__init__.py +5 -0
- hexdag/builtin/adapters/anthropic/anthropic_adapter.py +151 -0
- hexdag/builtin/adapters/database/__init__.py +6 -0
- hexdag/builtin/adapters/database/csv/csv_adapter.py +249 -0
- hexdag/builtin/adapters/database/pgvector/__init__.py +5 -0
- hexdag/builtin/adapters/database/pgvector/pgvector_adapter.py +478 -0
- hexdag/builtin/adapters/database/sqlalchemy/sqlalchemy_adapter.py +252 -0
- hexdag/builtin/adapters/database/sqlite/__init__.py +5 -0
- hexdag/builtin/adapters/database/sqlite/sqlite_adapter.py +410 -0
- hexdag/builtin/adapters/local/README.md +59 -0
- hexdag/builtin/adapters/local/__init__.py +7 -0
- hexdag/builtin/adapters/local/local_observer_manager.py +696 -0
- hexdag/builtin/adapters/memory/__init__.py +47 -0
- hexdag/builtin/adapters/memory/file_memory_adapter.py +297 -0
- hexdag/builtin/adapters/memory/in_memory_memory.py +216 -0
- hexdag/builtin/adapters/memory/schemas.py +57 -0
- hexdag/builtin/adapters/memory/session_memory.py +178 -0
- hexdag/builtin/adapters/memory/sqlite_memory_adapter.py +215 -0
- hexdag/builtin/adapters/memory/state_memory.py +280 -0
- hexdag/builtin/adapters/mock/README.md +89 -0
- hexdag/builtin/adapters/mock/__init__.py +15 -0
- hexdag/builtin/adapters/mock/hexdag.toml +50 -0
- hexdag/builtin/adapters/mock/mock_database.py +225 -0
- hexdag/builtin/adapters/mock/mock_embedding.py +223 -0
- hexdag/builtin/adapters/mock/mock_llm.py +177 -0
- hexdag/builtin/adapters/mock/mock_tool_adapter.py +192 -0
- hexdag/builtin/adapters/mock/mock_tool_router.py +232 -0
- hexdag/builtin/adapters/openai/__init__.py +5 -0
- hexdag/builtin/adapters/openai/openai_adapter.py +634 -0
- hexdag/builtin/adapters/secret/__init__.py +7 -0
- hexdag/builtin/adapters/secret/local_secret_adapter.py +248 -0
- hexdag/builtin/adapters/unified_tool_router.py +280 -0
- hexdag/builtin/macros/__init__.py +17 -0
- hexdag/builtin/macros/conversation_agent.py +390 -0
- hexdag/builtin/macros/llm_macro.py +151 -0
- hexdag/builtin/macros/reasoning_agent.py +423 -0
- hexdag/builtin/macros/tool_macro.py +380 -0
- hexdag/builtin/nodes/__init__.py +38 -0
- hexdag/builtin/nodes/_discovery.py +123 -0
- hexdag/builtin/nodes/agent_node.py +696 -0
- hexdag/builtin/nodes/base_node_factory.py +242 -0
- hexdag/builtin/nodes/composite_node.py +926 -0
- hexdag/builtin/nodes/data_node.py +201 -0
- hexdag/builtin/nodes/expression_node.py +487 -0
- hexdag/builtin/nodes/function_node.py +454 -0
- hexdag/builtin/nodes/llm_node.py +491 -0
- hexdag/builtin/nodes/loop_node.py +920 -0
- hexdag/builtin/nodes/mapped_input.py +518 -0
- hexdag/builtin/nodes/port_call_node.py +269 -0
- hexdag/builtin/nodes/tool_call_node.py +195 -0
- hexdag/builtin/nodes/tool_utils.py +390 -0
- hexdag/builtin/prompts/__init__.py +68 -0
- hexdag/builtin/prompts/base.py +422 -0
- hexdag/builtin/prompts/chat_prompts.py +303 -0
- hexdag/builtin/prompts/error_correction_prompts.py +320 -0
- hexdag/builtin/prompts/tool_prompts.py +160 -0
- hexdag/builtin/tools/builtin_tools.py +84 -0
- hexdag/builtin/tools/database_tools.py +164 -0
- hexdag/cli/__init__.py +17 -0
- hexdag/cli/__main__.py +7 -0
- hexdag/cli/commands/__init__.py +27 -0
- hexdag/cli/commands/build_cmd.py +812 -0
- hexdag/cli/commands/create_cmd.py +208 -0
- hexdag/cli/commands/docs_cmd.py +293 -0
- hexdag/cli/commands/generate_types_cmd.py +252 -0
- hexdag/cli/commands/init_cmd.py +188 -0
- hexdag/cli/commands/pipeline_cmd.py +494 -0
- hexdag/cli/commands/plugin_dev_cmd.py +529 -0
- hexdag/cli/commands/plugins_cmd.py +441 -0
- hexdag/cli/commands/studio_cmd.py +101 -0
- hexdag/cli/commands/validate_cmd.py +221 -0
- hexdag/cli/main.py +84 -0
- hexdag/core/__init__.py +83 -0
- hexdag/core/config/__init__.py +20 -0
- hexdag/core/config/loader.py +479 -0
- hexdag/core/config/models.py +150 -0
- hexdag/core/configurable.py +294 -0
- hexdag/core/context/__init__.py +37 -0
- hexdag/core/context/execution_context.py +378 -0
- hexdag/core/docs/__init__.py +26 -0
- hexdag/core/docs/extractors.py +678 -0
- hexdag/core/docs/generators.py +890 -0
- hexdag/core/docs/models.py +120 -0
- hexdag/core/domain/__init__.py +10 -0
- hexdag/core/domain/dag.py +1225 -0
- hexdag/core/exceptions.py +234 -0
- hexdag/core/expression_parser.py +569 -0
- hexdag/core/logging.py +449 -0
- hexdag/core/models/__init__.py +17 -0
- hexdag/core/models/base.py +138 -0
- hexdag/core/orchestration/__init__.py +46 -0
- hexdag/core/orchestration/body_executor.py +481 -0
- hexdag/core/orchestration/components/__init__.py +97 -0
- hexdag/core/orchestration/components/adapter_lifecycle_manager.py +113 -0
- hexdag/core/orchestration/components/checkpoint_manager.py +134 -0
- hexdag/core/orchestration/components/execution_coordinator.py +360 -0
- hexdag/core/orchestration/components/health_check_manager.py +176 -0
- hexdag/core/orchestration/components/input_mapper.py +143 -0
- hexdag/core/orchestration/components/lifecycle_manager.py +583 -0
- hexdag/core/orchestration/components/node_executor.py +377 -0
- hexdag/core/orchestration/components/secret_manager.py +202 -0
- hexdag/core/orchestration/components/wave_executor.py +158 -0
- hexdag/core/orchestration/constants.py +17 -0
- hexdag/core/orchestration/events/README.md +312 -0
- hexdag/core/orchestration/events/__init__.py +104 -0
- hexdag/core/orchestration/events/batching.py +330 -0
- hexdag/core/orchestration/events/decorators.py +139 -0
- hexdag/core/orchestration/events/events.py +573 -0
- hexdag/core/orchestration/events/observers/__init__.py +30 -0
- hexdag/core/orchestration/events/observers/core_observers.py +690 -0
- hexdag/core/orchestration/events/observers/models.py +111 -0
- hexdag/core/orchestration/events/taxonomy.py +269 -0
- hexdag/core/orchestration/hook_context.py +237 -0
- hexdag/core/orchestration/hooks.py +437 -0
- hexdag/core/orchestration/models.py +418 -0
- hexdag/core/orchestration/orchestrator.py +910 -0
- hexdag/core/orchestration/orchestrator_factory.py +275 -0
- hexdag/core/orchestration/port_wrappers.py +327 -0
- hexdag/core/orchestration/prompt/__init__.py +32 -0
- hexdag/core/orchestration/prompt/template.py +332 -0
- hexdag/core/pipeline_builder/__init__.py +21 -0
- hexdag/core/pipeline_builder/component_instantiator.py +386 -0
- hexdag/core/pipeline_builder/include_tag.py +265 -0
- hexdag/core/pipeline_builder/pipeline_config.py +133 -0
- hexdag/core/pipeline_builder/py_tag.py +223 -0
- hexdag/core/pipeline_builder/tag_discovery.py +268 -0
- hexdag/core/pipeline_builder/yaml_builder.py +1196 -0
- hexdag/core/pipeline_builder/yaml_validator.py +569 -0
- hexdag/core/ports/__init__.py +65 -0
- hexdag/core/ports/api_call.py +133 -0
- hexdag/core/ports/database.py +489 -0
- hexdag/core/ports/embedding.py +215 -0
- hexdag/core/ports/executor.py +237 -0
- hexdag/core/ports/file_storage.py +117 -0
- hexdag/core/ports/healthcheck.py +87 -0
- hexdag/core/ports/llm.py +551 -0
- hexdag/core/ports/memory.py +70 -0
- hexdag/core/ports/observer_manager.py +130 -0
- hexdag/core/ports/secret.py +145 -0
- hexdag/core/ports/tool_router.py +94 -0
- hexdag/core/ports_builder.py +623 -0
- hexdag/core/protocols.py +273 -0
- hexdag/core/resolver.py +304 -0
- hexdag/core/schema/__init__.py +9 -0
- hexdag/core/schema/generator.py +742 -0
- hexdag/core/secrets.py +242 -0
- hexdag/core/types.py +413 -0
- hexdag/core/utils/async_warnings.py +206 -0
- hexdag/core/utils/schema_conversion.py +78 -0
- hexdag/core/utils/sql_validation.py +86 -0
- hexdag/core/validation/secure_json.py +148 -0
- hexdag/core/yaml_macro.py +517 -0
- hexdag/mcp_server.py +3120 -0
- hexdag/studio/__init__.py +10 -0
- hexdag/studio/build_ui.py +92 -0
- hexdag/studio/server/__init__.py +1 -0
- hexdag/studio/server/main.py +100 -0
- hexdag/studio/server/routes/__init__.py +9 -0
- hexdag/studio/server/routes/execute.py +208 -0
- hexdag/studio/server/routes/export.py +558 -0
- hexdag/studio/server/routes/files.py +207 -0
- hexdag/studio/server/routes/plugins.py +419 -0
- hexdag/studio/server/routes/validate.py +220 -0
- hexdag/studio/ui/index.html +13 -0
- hexdag/studio/ui/package-lock.json +2992 -0
- hexdag/studio/ui/package.json +31 -0
- hexdag/studio/ui/postcss.config.js +6 -0
- hexdag/studio/ui/public/hexdag.svg +5 -0
- hexdag/studio/ui/src/App.tsx +251 -0
- hexdag/studio/ui/src/components/Canvas.tsx +408 -0
- hexdag/studio/ui/src/components/ContextMenu.tsx +187 -0
- hexdag/studio/ui/src/components/FileBrowser.tsx +123 -0
- hexdag/studio/ui/src/components/Header.tsx +181 -0
- hexdag/studio/ui/src/components/HexdagNode.tsx +193 -0
- hexdag/studio/ui/src/components/NodeInspector.tsx +512 -0
- hexdag/studio/ui/src/components/NodePalette.tsx +262 -0
- hexdag/studio/ui/src/components/NodePortsSection.tsx +403 -0
- hexdag/studio/ui/src/components/PluginManager.tsx +347 -0
- hexdag/studio/ui/src/components/PortsEditor.tsx +481 -0
- hexdag/studio/ui/src/components/PythonEditor.tsx +195 -0
- hexdag/studio/ui/src/components/ValidationPanel.tsx +105 -0
- hexdag/studio/ui/src/components/YamlEditor.tsx +196 -0
- hexdag/studio/ui/src/components/index.ts +8 -0
- hexdag/studio/ui/src/index.css +92 -0
- hexdag/studio/ui/src/main.tsx +10 -0
- hexdag/studio/ui/src/types/index.ts +123 -0
- hexdag/studio/ui/src/vite-env.d.ts +1 -0
- hexdag/studio/ui/tailwind.config.js +29 -0
- hexdag/studio/ui/tsconfig.json +37 -0
- hexdag/studio/ui/tsconfig.node.json +13 -0
- hexdag/studio/ui/vite.config.ts +35 -0
- hexdag/visualization/__init__.py +69 -0
- hexdag/visualization/dag_visualizer.py +1020 -0
- hexdag-0.5.0.dev1.dist-info/METADATA +369 -0
- hexdag-0.5.0.dev1.dist-info/RECORD +261 -0
- hexdag-0.5.0.dev1.dist-info/WHEEL +4 -0
- hexdag-0.5.0.dev1.dist-info/entry_points.txt +4 -0
- hexdag-0.5.0.dev1.dist-info/licenses/LICENSE +190 -0
- hexdag_plugins/.gitignore +43 -0
- hexdag_plugins/README.md +73 -0
- hexdag_plugins/__init__.py +1 -0
- hexdag_plugins/azure/LICENSE +21 -0
- hexdag_plugins/azure/README.md +414 -0
- hexdag_plugins/azure/__init__.py +21 -0
- hexdag_plugins/azure/azure_blob_adapter.py +450 -0
- hexdag_plugins/azure/azure_cosmos_adapter.py +383 -0
- hexdag_plugins/azure/azure_keyvault_adapter.py +314 -0
- hexdag_plugins/azure/azure_openai_adapter.py +415 -0
- hexdag_plugins/azure/pyproject.toml +107 -0
- hexdag_plugins/azure/tests/__init__.py +1 -0
- hexdag_plugins/azure/tests/test_azure_blob_adapter.py +350 -0
- hexdag_plugins/azure/tests/test_azure_cosmos_adapter.py +323 -0
- hexdag_plugins/azure/tests/test_azure_keyvault_adapter.py +330 -0
- hexdag_plugins/azure/tests/test_azure_openai_adapter.py +329 -0
- hexdag_plugins/hexdag_etl/README.md +168 -0
- hexdag_plugins/hexdag_etl/__init__.py +53 -0
- hexdag_plugins/hexdag_etl/examples/01_simple_pandas_transform.py +270 -0
- hexdag_plugins/hexdag_etl/examples/02_simple_pandas_only.py +149 -0
- hexdag_plugins/hexdag_etl/examples/03_file_io_pipeline.py +109 -0
- hexdag_plugins/hexdag_etl/examples/test_pandas_transform.py +84 -0
- hexdag_plugins/hexdag_etl/hexdag.toml +25 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/__init__.py +48 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/__init__.py +13 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/api_extract.py +230 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/base_node_factory.py +181 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/file_io.py +415 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/outlook.py +492 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/pandas_transform.py +563 -0
- hexdag_plugins/hexdag_etl/hexdag_etl/nodes/sql_extract_load.py +112 -0
- hexdag_plugins/hexdag_etl/pyproject.toml +82 -0
- hexdag_plugins/hexdag_etl/test_transform.py +54 -0
- hexdag_plugins/hexdag_etl/tests/test_plugin_integration.py +62 -0
- hexdag_plugins/mysql_adapter/LICENSE +21 -0
- hexdag_plugins/mysql_adapter/README.md +224 -0
- hexdag_plugins/mysql_adapter/__init__.py +6 -0
- hexdag_plugins/mysql_adapter/mysql_adapter.py +408 -0
- hexdag_plugins/mysql_adapter/pyproject.toml +93 -0
- hexdag_plugins/mysql_adapter/tests/test_mysql_adapter.py +259 -0
- hexdag_plugins/storage/README.md +184 -0
- hexdag_plugins/storage/__init__.py +19 -0
- hexdag_plugins/storage/file/__init__.py +5 -0
- hexdag_plugins/storage/file/local.py +325 -0
- hexdag_plugins/storage/ports/__init__.py +5 -0
- hexdag_plugins/storage/ports/vector_store.py +236 -0
- hexdag_plugins/storage/sql/__init__.py +7 -0
- hexdag_plugins/storage/sql/base.py +187 -0
- hexdag_plugins/storage/sql/mysql.py +27 -0
- hexdag_plugins/storage/sql/postgresql.py +27 -0
- hexdag_plugins/storage/tests/__init__.py +1 -0
- hexdag_plugins/storage/tests/test_local_file_storage.py +161 -0
- hexdag_plugins/storage/tests/test_sql_adapters.py +212 -0
- hexdag_plugins/storage/vector/__init__.py +7 -0
- hexdag_plugins/storage/vector/chromadb.py +223 -0
- hexdag_plugins/storage/vector/in_memory.py +285 -0
- 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,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
|
+
]
|