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,303 @@
|
|
|
1
|
+
"""Registrable chat and few-shot prompt templates.
|
|
2
|
+
|
|
3
|
+
These are pre-configured, reusable prompt templates that can be
|
|
4
|
+
referenced in YAML pipelines or composed programmatically.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from hexdag.builtin.prompts.base import (
|
|
11
|
+
ChatFewShotTemplate,
|
|
12
|
+
ChatPromptTemplate,
|
|
13
|
+
FewShotPromptTemplate,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ChatQAPrompt(ChatPromptTemplate):
|
|
18
|
+
"""Chat template for question-answering tasks.
|
|
19
|
+
|
|
20
|
+
Provides a helpful assistant persona with structured Q&A format.
|
|
21
|
+
|
|
22
|
+
Examples
|
|
23
|
+
--------
|
|
24
|
+
Direct usage::
|
|
25
|
+
|
|
26
|
+
prompt = ChatQAPrompt()
|
|
27
|
+
messages = prompt.to_messages(
|
|
28
|
+
domain="AI",
|
|
29
|
+
question="What is machine learning?"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
Composition::
|
|
33
|
+
|
|
34
|
+
from hexdag.builtin.prompts import ToolPrompt
|
|
35
|
+
full_prompt = ChatQAPrompt() + ToolPrompt()
|
|
36
|
+
|
|
37
|
+
YAML usage::
|
|
38
|
+
|
|
39
|
+
nodes:
|
|
40
|
+
- type: prompt_node
|
|
41
|
+
name: qa_prompt
|
|
42
|
+
params:
|
|
43
|
+
template: core:chat_qa
|
|
44
|
+
inputs:
|
|
45
|
+
domain: "science"
|
|
46
|
+
question: "{{user_question}}"
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
"""Initialize Q&A chat template."""
|
|
51
|
+
super().__init__(
|
|
52
|
+
system_message="You are a helpful expert in {{domain}}. "
|
|
53
|
+
"Provide clear, accurate, and concise answers.",
|
|
54
|
+
human_message="Question: {{question}}",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ChatAnalysisPrompt(ChatPromptTemplate):
|
|
59
|
+
"""Chat template for analytical tasks.
|
|
60
|
+
|
|
61
|
+
Encourages step-by-step reasoning and structured output.
|
|
62
|
+
|
|
63
|
+
Examples
|
|
64
|
+
--------
|
|
65
|
+
prompt = ChatAnalysisPrompt()
|
|
66
|
+
messages = prompt.to_messages(
|
|
67
|
+
task="sentiment analysis",
|
|
68
|
+
data="Customer feedback: Great product!"
|
|
69
|
+
)
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self) -> None:
|
|
73
|
+
"""Initialize analysis chat template."""
|
|
74
|
+
super().__init__(
|
|
75
|
+
system_message="You are an expert analyst. "
|
|
76
|
+
"Analyze the given data thoroughly and provide structured insights. "
|
|
77
|
+
"Think step-by-step and explain your reasoning.",
|
|
78
|
+
human_message="Task: {{task}}\n\nData:\n{{data}}\n\nProvide your analysis:",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ChatConversationalPrompt(ChatPromptTemplate):
|
|
83
|
+
"""Conversational chat template with conversation history.
|
|
84
|
+
|
|
85
|
+
Designed for multi-turn conversations with context.
|
|
86
|
+
|
|
87
|
+
Examples
|
|
88
|
+
--------
|
|
89
|
+
prompt = ChatConversationalPrompt()
|
|
90
|
+
messages = prompt.to_messages(
|
|
91
|
+
bot_name="Assistant",
|
|
92
|
+
user_message="Tell me about quantum computing",
|
|
93
|
+
context_history=[
|
|
94
|
+
{"role": "user", "content": "Hello!"},
|
|
95
|
+
{"role": "assistant", "content": "Hi! How can I help?"}
|
|
96
|
+
]
|
|
97
|
+
)
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
def __init__(self) -> None:
|
|
101
|
+
"""Initialize conversational chat template."""
|
|
102
|
+
super().__init__(
|
|
103
|
+
system_message="You are {{bot_name}}, a friendly and helpful conversational AI. "
|
|
104
|
+
"Maintain context from previous messages and provide engaging responses.",
|
|
105
|
+
human_message="{{user_message}}",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class FewShotClassificationPrompt(FewShotPromptTemplate):
|
|
110
|
+
"""Few-shot template for classification tasks.
|
|
111
|
+
|
|
112
|
+
Provides examples to guide the model's classification behavior.
|
|
113
|
+
|
|
114
|
+
Examples
|
|
115
|
+
--------
|
|
116
|
+
Direct usage::
|
|
117
|
+
|
|
118
|
+
examples = [
|
|
119
|
+
{"input": "I love this!", "output": "positive"},
|
|
120
|
+
{"input": "Terrible experience", "output": "negative"},
|
|
121
|
+
{"input": "It's okay", "output": "neutral"}
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
prompt = FewShotClassificationPrompt(examples=examples)
|
|
125
|
+
text = prompt.format(text="Amazing product!")
|
|
126
|
+
|
|
127
|
+
YAML usage::
|
|
128
|
+
|
|
129
|
+
nodes:
|
|
130
|
+
- type: prompt_node
|
|
131
|
+
name: classifier
|
|
132
|
+
params:
|
|
133
|
+
template: core:fewshot_classification
|
|
134
|
+
examples:
|
|
135
|
+
- input: "Great!"
|
|
136
|
+
output: "positive"
|
|
137
|
+
- input: "Bad"
|
|
138
|
+
output: "negative"
|
|
139
|
+
inputs:
|
|
140
|
+
text: "{{review}}"
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(
|
|
144
|
+
self,
|
|
145
|
+
examples: list[dict[str, Any]] | None = None,
|
|
146
|
+
format_example: Callable[[dict[str, Any]], str] | None = None,
|
|
147
|
+
) -> None:
|
|
148
|
+
"""Initialize classification few-shot template.
|
|
149
|
+
|
|
150
|
+
Args
|
|
151
|
+
----
|
|
152
|
+
examples: List of example dicts with 'input' and 'output' keys
|
|
153
|
+
format_example: Optional custom formatter for examples
|
|
154
|
+
"""
|
|
155
|
+
if format_example is None:
|
|
156
|
+
|
|
157
|
+
def _classification_formatter(ex: dict[str, Any]) -> str:
|
|
158
|
+
inp = ex.get("input", "")
|
|
159
|
+
out = ex.get("output", "")
|
|
160
|
+
return f"Text: {inp}\nClassification: {out}"
|
|
161
|
+
|
|
162
|
+
format_example = _classification_formatter
|
|
163
|
+
|
|
164
|
+
super().__init__(
|
|
165
|
+
template="Classify the following text:\n\nText: {{text}}\nClassification:",
|
|
166
|
+
examples=examples or [],
|
|
167
|
+
format_example=format_example,
|
|
168
|
+
example_separator="\n\n",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class FewShotExtractionPrompt(FewShotPromptTemplate):
|
|
173
|
+
"""Few-shot template for extracting structured information.
|
|
174
|
+
|
|
175
|
+
Examples
|
|
176
|
+
--------
|
|
177
|
+
examples = [
|
|
178
|
+
{
|
|
179
|
+
"input": "John Doe, age 30, lives in NYC",
|
|
180
|
+
"output": '{"name": "John Doe", "age": 30, "city": "NYC"}'
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
prompt = FewShotExtractionPrompt(examples=examples)
|
|
185
|
+
text = prompt.format(text="Jane Smith, 25, from LA")
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
def __init__(
|
|
189
|
+
self,
|
|
190
|
+
examples: list[dict[str, Any]] | None = None,
|
|
191
|
+
format_example: Callable[[dict[str, Any]], str] | None = None,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""Initialize extraction few-shot template."""
|
|
194
|
+
if format_example is None:
|
|
195
|
+
|
|
196
|
+
def _extraction_formatter(ex: dict[str, Any]) -> str:
|
|
197
|
+
inp = ex.get("input", "")
|
|
198
|
+
out = ex.get("output", "")
|
|
199
|
+
return f"Input: {inp}\nExtracted: {out}"
|
|
200
|
+
|
|
201
|
+
format_example = _extraction_formatter
|
|
202
|
+
|
|
203
|
+
super().__init__(
|
|
204
|
+
template="Extract structured information from the following text:\n\nInput: {{text}}\nExtracted:",
|
|
205
|
+
examples=examples or [],
|
|
206
|
+
format_example=format_example,
|
|
207
|
+
example_separator="\n\n",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class ChatFewShotQAPrompt(ChatFewShotTemplate):
|
|
212
|
+
"""Chat template with few-shot examples for question answering.
|
|
213
|
+
|
|
214
|
+
Combines chat-style interaction with example-based learning.
|
|
215
|
+
|
|
216
|
+
Examples
|
|
217
|
+
--------
|
|
218
|
+
examples = [
|
|
219
|
+
{
|
|
220
|
+
"input": "What is Python?",
|
|
221
|
+
"output": "Python is a high-level programming language known for simplicity."
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"input": "What is AI?",
|
|
225
|
+
"output": "AI is the simulation of human intelligence by machines."
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
prompt = ChatFewShotQAPrompt(examples=examples)
|
|
230
|
+
messages = prompt.to_messages(question="What is blockchain?")
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
def __init__(
|
|
234
|
+
self,
|
|
235
|
+
examples: list[dict[str, Any]] | None = None,
|
|
236
|
+
format_example: Callable[[dict[str, Any]], str] | None = None,
|
|
237
|
+
) -> None:
|
|
238
|
+
"""Initialize chat few-shot Q&A template."""
|
|
239
|
+
if format_example is None:
|
|
240
|
+
|
|
241
|
+
def _qa_formatter(ex: dict[str, Any]) -> str:
|
|
242
|
+
inp = ex.get("input", "")
|
|
243
|
+
out = ex.get("output", "")
|
|
244
|
+
return f"Q: {inp}\nA: {out}"
|
|
245
|
+
|
|
246
|
+
format_example = _qa_formatter
|
|
247
|
+
|
|
248
|
+
super().__init__(
|
|
249
|
+
system_message="You are a knowledgeable assistant. "
|
|
250
|
+
"Answer questions clearly and concisely, following the example format.",
|
|
251
|
+
human_message="Q: {{question}}\nA:",
|
|
252
|
+
examples=examples or [],
|
|
253
|
+
format_example=format_example,
|
|
254
|
+
example_separator="\n\n",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# Factory function for creating custom chat prompts
|
|
259
|
+
def create_chat_prompt(
|
|
260
|
+
system_message: str,
|
|
261
|
+
human_message: str,
|
|
262
|
+
) -> type[ChatPromptTemplate]:
|
|
263
|
+
"""Factory for creating custom chat prompts.
|
|
264
|
+
|
|
265
|
+
Examples
|
|
266
|
+
--------
|
|
267
|
+
MyCustomPrompt = create_chat_prompt(
|
|
268
|
+
system_message="You are a {{role}}",
|
|
269
|
+
human_message="{{task}}",
|
|
270
|
+
)
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
class CustomChatPrompt(ChatPromptTemplate):
|
|
274
|
+
def __init__(self) -> None:
|
|
275
|
+
super().__init__(system_message=system_message, human_message=human_message)
|
|
276
|
+
|
|
277
|
+
return CustomChatPrompt
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
# Factory for creating custom few-shot prompts
|
|
281
|
+
def create_fewshot_prompt(
|
|
282
|
+
template: str,
|
|
283
|
+
examples: list[dict[str, Any]],
|
|
284
|
+
format_example: Callable[[dict[str, Any]], str] | None = None,
|
|
285
|
+
) -> type[FewShotPromptTemplate]:
|
|
286
|
+
"""Factory for creating custom few-shot prompts.
|
|
287
|
+
|
|
288
|
+
Examples
|
|
289
|
+
--------
|
|
290
|
+
MyFewShotPrompt = create_fewshot_prompt(
|
|
291
|
+
template="Translate: {{text}}",
|
|
292
|
+
examples=[
|
|
293
|
+
{"input": "Hello", "output": "Hola"},
|
|
294
|
+
{"input": "Goodbye", "output": "Adiós"}
|
|
295
|
+
],
|
|
296
|
+
)
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
class CustomFewShotPrompt(FewShotPromptTemplate):
|
|
300
|
+
def __init__(self) -> None:
|
|
301
|
+
super().__init__(template=template, examples=examples, format_example=format_example)
|
|
302
|
+
|
|
303
|
+
return CustomFewShotPrompt
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""Error correction and retry prompt templates.
|
|
2
|
+
|
|
3
|
+
These prompts help LLMs fix their mistakes when parsing fails.
|
|
4
|
+
They provide clear instructions on what went wrong and how to fix it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from hexdag.core.orchestration.prompt.template import PromptTemplate
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class JsonParseErrorPrompt(PromptTemplate):
|
|
11
|
+
"""Prompt to help fix JSON parsing errors.
|
|
12
|
+
|
|
13
|
+
Uses clear examples and common mistake patterns to guide the LLM
|
|
14
|
+
toward producing valid JSON.
|
|
15
|
+
|
|
16
|
+
Variables
|
|
17
|
+
---------
|
|
18
|
+
- original_prompt: The original prompt that was given
|
|
19
|
+
- llm_output: The output that failed to parse
|
|
20
|
+
- error_message: The parse error message
|
|
21
|
+
- schema: Expected JSON schema (optional)
|
|
22
|
+
|
|
23
|
+
Examples
|
|
24
|
+
--------
|
|
25
|
+
Usage in ParseRetryPolicy::
|
|
26
|
+
|
|
27
|
+
retry_prompt = JsonParseErrorPrompt()
|
|
28
|
+
corrected = retry_prompt.render(
|
|
29
|
+
original_prompt="Generate user data",
|
|
30
|
+
llm_output='name: "John", age: 30', # Invalid JSON
|
|
31
|
+
error_message="Expecting property name enclosed in double quotes",
|
|
32
|
+
schema={"name": "str", "age": "int"}
|
|
33
|
+
)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self) -> None:
|
|
37
|
+
"""Initialize JSON parse error correction prompt."""
|
|
38
|
+
template = """{{original_prompt}}
|
|
39
|
+
|
|
40
|
+
⚠️ PREVIOUS ATTEMPT FAILED - JSON PARSING ERROR
|
|
41
|
+
|
|
42
|
+
Your previous response could not be parsed as valid JSON:
|
|
43
|
+
```
|
|
44
|
+
{{llm_output}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Error: {{error_message}}
|
|
48
|
+
|
|
49
|
+
IMPORTANT: Respond with VALID JSON that follows these rules:
|
|
50
|
+
|
|
51
|
+
1. ✅ Use double quotes for strings: "text" not 'text'
|
|
52
|
+
2. ✅ No trailing commas: {"a": 1, "b": 2} not {"a": 1, "b": 2,}
|
|
53
|
+
3. ✅ Property names must be quoted: {"name": "value"} not {name: "value"}
|
|
54
|
+
4. ✅ Use true/false not True/False
|
|
55
|
+
5. ✅ Use null not None
|
|
56
|
+
|
|
57
|
+
Common mistakes to avoid:
|
|
58
|
+
- ❌ Single quotes: {'name': 'John'}
|
|
59
|
+
- ❌ Trailing commas: {"age": 30,}
|
|
60
|
+
- ❌ Unquoted keys: {name: "John"}
|
|
61
|
+
- ❌ Python booleans: {"active": True}
|
|
62
|
+
|
|
63
|
+
Correct format:
|
|
64
|
+
- ✅ {"name": "John", "age": 30, "active": true}
|
|
65
|
+
|
|
66
|
+
{{#schema}}Expected schema:
|
|
67
|
+
```json
|
|
68
|
+
{{schema}}
|
|
69
|
+
```{{/schema}}
|
|
70
|
+
|
|
71
|
+
Please respond ONLY with valid JSON. No explanations, no markdown formatting.
|
|
72
|
+
"""
|
|
73
|
+
super().__init__(template)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class JsonValidationErrorPrompt(PromptTemplate):
|
|
77
|
+
"""Prompt to fix schema validation errors.
|
|
78
|
+
|
|
79
|
+
When JSON parses correctly but doesn't match the expected schema,
|
|
80
|
+
this prompt helps the LLM understand what fields are missing or incorrect.
|
|
81
|
+
|
|
82
|
+
Variables
|
|
83
|
+
---------
|
|
84
|
+
- original_prompt: The original prompt
|
|
85
|
+
- llm_output: The parsed JSON that failed validation
|
|
86
|
+
- validation_errors: List of validation errors
|
|
87
|
+
- required_fields: Required fields in the schema
|
|
88
|
+
- schema: Full schema specification
|
|
89
|
+
|
|
90
|
+
Examples
|
|
91
|
+
--------
|
|
92
|
+
Usage::
|
|
93
|
+
|
|
94
|
+
retry_prompt = JsonValidationErrorPrompt()
|
|
95
|
+
corrected = retry_prompt.render(
|
|
96
|
+
original_prompt="Generate user profile",
|
|
97
|
+
llm_output='{"name": "John"}', # Missing 'age' field
|
|
98
|
+
validation_errors=["Field 'age' required"],
|
|
99
|
+
required_fields=["name", "age", "email"],
|
|
100
|
+
schema={"name": "str", "age": "int", "email": "str"}
|
|
101
|
+
)
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(self) -> None:
|
|
105
|
+
"""Initialize JSON validation error correction prompt."""
|
|
106
|
+
template = """{{original_prompt}}
|
|
107
|
+
|
|
108
|
+
⚠️ PREVIOUS ATTEMPT FAILED - SCHEMA VALIDATION ERROR
|
|
109
|
+
|
|
110
|
+
Your response was valid JSON but did NOT match the required schema.
|
|
111
|
+
|
|
112
|
+
Your output:
|
|
113
|
+
```json
|
|
114
|
+
{{llm_output}}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Validation errors:
|
|
118
|
+
{{validation_errors}}
|
|
119
|
+
|
|
120
|
+
Required schema:
|
|
121
|
+
```json
|
|
122
|
+
{{schema}}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
REQUIRED FIELDS (must include ALL):
|
|
126
|
+
{{#required_fields}}- {{.}}
|
|
127
|
+
{{/required_fields}}
|
|
128
|
+
|
|
129
|
+
Instructions:
|
|
130
|
+
1. Include ALL required fields
|
|
131
|
+
2. Use correct data types (string, number, boolean, array, object)
|
|
132
|
+
3. Field names must match EXACTLY (case-sensitive)
|
|
133
|
+
4. Arrays must contain the correct element types
|
|
134
|
+
|
|
135
|
+
Example of CORRECT format:
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"name": "John Doe",
|
|
139
|
+
"age": 30,
|
|
140
|
+
"email": "john@example.com",
|
|
141
|
+
"active": true
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Please respond with valid JSON that matches the schema exactly.
|
|
146
|
+
"""
|
|
147
|
+
super().__init__(template)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class SafeJsonInstructionsPrompt(PromptTemplate):
|
|
151
|
+
"""Proactive JSON instructions to prevent common errors.
|
|
152
|
+
|
|
153
|
+
Add this to prompts that expect JSON output to reduce errors upfront.
|
|
154
|
+
|
|
155
|
+
Variables
|
|
156
|
+
---------
|
|
157
|
+
- schema: Expected JSON schema
|
|
158
|
+
|
|
159
|
+
Examples
|
|
160
|
+
--------
|
|
161
|
+
Compose with main prompt::
|
|
162
|
+
|
|
163
|
+
from hexdag.builtin.prompts import SafeJsonInstructionsPrompt
|
|
164
|
+
|
|
165
|
+
main_prompt = PromptTemplate("Generate user data: {{requirements}}")
|
|
166
|
+
json_instructions = SafeJsonInstructionsPrompt()
|
|
167
|
+
|
|
168
|
+
full_prompt = main_prompt + json_instructions
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(self) -> None:
|
|
172
|
+
"""Initialize safe JSON instructions prompt."""
|
|
173
|
+
template = """
|
|
174
|
+
## JSON Output Requirements
|
|
175
|
+
|
|
176
|
+
IMPORTANT: Your response must be valid JSON following these rules:
|
|
177
|
+
|
|
178
|
+
✅ Valid JSON format:
|
|
179
|
+
- Use double quotes for strings: "text"
|
|
180
|
+
- No trailing commas
|
|
181
|
+
- Quote all property names
|
|
182
|
+
- Use true/false (not True/False)
|
|
183
|
+
- Use null (not None)
|
|
184
|
+
|
|
185
|
+
{{#schema}}Expected structure:
|
|
186
|
+
```json
|
|
187
|
+
{{schema}}
|
|
188
|
+
```{{/schema}}
|
|
189
|
+
|
|
190
|
+
Respond with ONLY the JSON object. No explanations before or after.
|
|
191
|
+
"""
|
|
192
|
+
super().__init__(template)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class MarkdownJsonErrorPrompt(PromptTemplate):
|
|
196
|
+
"""Prompt to fix JSON wrapped in markdown code blocks.
|
|
197
|
+
|
|
198
|
+
Helps when the LLM correctly generates JSON but wraps it in
|
|
199
|
+
markdown formatting that breaks parsing.
|
|
200
|
+
|
|
201
|
+
Variables
|
|
202
|
+
---------
|
|
203
|
+
- original_prompt: Original prompt
|
|
204
|
+
- error_message: Parse error
|
|
205
|
+
|
|
206
|
+
Examples
|
|
207
|
+
--------
|
|
208
|
+
retry_prompt = MarkdownJsonErrorPrompt()
|
|
209
|
+
corrected = retry_prompt.render(
|
|
210
|
+
original_prompt="Generate config",
|
|
211
|
+
error_message="Could not find JSON in response"
|
|
212
|
+
)
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
def __init__(self) -> None:
|
|
216
|
+
"""Initialize markdown JSON error prompt."""
|
|
217
|
+
template = """{{original_prompt}}
|
|
218
|
+
|
|
219
|
+
⚠️ PREVIOUS ATTEMPT FAILED - JSON FORMATTING ERROR
|
|
220
|
+
|
|
221
|
+
Error: {{error_message}}
|
|
222
|
+
|
|
223
|
+
IMPORTANT: Respond with ONLY the raw JSON object.
|
|
224
|
+
|
|
225
|
+
❌ DO NOT wrap in markdown code blocks:
|
|
226
|
+
```json
|
|
227
|
+
{"name": "value"}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
❌ DO NOT add explanations:
|
|
231
|
+
Here is the JSON: {"name": "value"}
|
|
232
|
+
|
|
233
|
+
✅ CORRECT - Just the JSON:
|
|
234
|
+
{"name": "value"}
|
|
235
|
+
|
|
236
|
+
Please provide ONLY the JSON object, nothing else.
|
|
237
|
+
"""
|
|
238
|
+
super().__init__(template)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class GenericParseErrorPrompt(PromptTemplate):
|
|
242
|
+
"""Generic parse error correction prompt.
|
|
243
|
+
|
|
244
|
+
Fallback for parse errors that don't fit specific categories.
|
|
245
|
+
|
|
246
|
+
Variables
|
|
247
|
+
---------
|
|
248
|
+
- original_prompt: Original prompt
|
|
249
|
+
- llm_output: Failed output
|
|
250
|
+
- error_message: Error message
|
|
251
|
+
- format: Expected format (json, yaml, etc.)
|
|
252
|
+
|
|
253
|
+
Examples
|
|
254
|
+
--------
|
|
255
|
+
retry_prompt = GenericParseErrorPrompt()
|
|
256
|
+
corrected = retry_prompt.render(
|
|
257
|
+
original_prompt="Extract data",
|
|
258
|
+
llm_output="invalid data...",
|
|
259
|
+
error_message="Parse failed",
|
|
260
|
+
format="json"
|
|
261
|
+
)
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self) -> None:
|
|
265
|
+
"""Initialize generic parse error prompt."""
|
|
266
|
+
template = """{{original_prompt}}
|
|
267
|
+
|
|
268
|
+
⚠️ PREVIOUS ATTEMPT FAILED
|
|
269
|
+
|
|
270
|
+
Your previous response could not be parsed:
|
|
271
|
+
```
|
|
272
|
+
{{llm_output}}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Error: {{error_message}}
|
|
276
|
+
|
|
277
|
+
Expected format: {{format}}
|
|
278
|
+
|
|
279
|
+
Please provide a response in valid {{format}} format.
|
|
280
|
+
Ensure:
|
|
281
|
+
- Correct syntax
|
|
282
|
+
- Proper formatting
|
|
283
|
+
- All required fields included
|
|
284
|
+
|
|
285
|
+
Try again with a correctly formatted response.
|
|
286
|
+
"""
|
|
287
|
+
super().__init__(template)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def get_error_correction_prompt(error_type: str, strategy: str = "json") -> type[PromptTemplate]:
|
|
291
|
+
"""Get appropriate error correction prompt for error type.
|
|
292
|
+
|
|
293
|
+
Args
|
|
294
|
+
----
|
|
295
|
+
error_type: Type of error ("parse", "validation", "markdown", "generic")
|
|
296
|
+
strategy: Parsing strategy ("json", "yaml", etc.)
|
|
297
|
+
|
|
298
|
+
Returns
|
|
299
|
+
-------
|
|
300
|
+
type[PromptTemplate]
|
|
301
|
+
Appropriate error correction prompt class
|
|
302
|
+
|
|
303
|
+
Examples
|
|
304
|
+
--------
|
|
305
|
+
PromptClass = get_error_correction_prompt("parse", "json")
|
|
306
|
+
prompt = PromptClass()
|
|
307
|
+
corrected = prompt.render(original_prompt="...", error_message="...")
|
|
308
|
+
"""
|
|
309
|
+
if error_type == "parse":
|
|
310
|
+
if strategy == "json":
|
|
311
|
+
return JsonParseErrorPrompt
|
|
312
|
+
return GenericParseErrorPrompt
|
|
313
|
+
|
|
314
|
+
if error_type == "validation":
|
|
315
|
+
return JsonValidationErrorPrompt
|
|
316
|
+
|
|
317
|
+
if error_type == "markdown":
|
|
318
|
+
return MarkdownJsonErrorPrompt
|
|
319
|
+
|
|
320
|
+
return GenericParseErrorPrompt
|