kweaver-dolphin 0.1.0__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.
- DolphinLanguageSDK/__init__.py +58 -0
- dolphin/__init__.py +62 -0
- dolphin/cli/__init__.py +20 -0
- dolphin/cli/args/__init__.py +9 -0
- dolphin/cli/args/parser.py +567 -0
- dolphin/cli/builtin_agents/__init__.py +22 -0
- dolphin/cli/commands/__init__.py +4 -0
- dolphin/cli/interrupt/__init__.py +8 -0
- dolphin/cli/interrupt/handler.py +205 -0
- dolphin/cli/interrupt/keyboard.py +82 -0
- dolphin/cli/main.py +49 -0
- dolphin/cli/multimodal/__init__.py +34 -0
- dolphin/cli/multimodal/clipboard.py +327 -0
- dolphin/cli/multimodal/handler.py +249 -0
- dolphin/cli/multimodal/image_processor.py +214 -0
- dolphin/cli/multimodal/input_parser.py +149 -0
- dolphin/cli/runner/__init__.py +8 -0
- dolphin/cli/runner/runner.py +989 -0
- dolphin/cli/ui/__init__.py +10 -0
- dolphin/cli/ui/console.py +2795 -0
- dolphin/cli/ui/input.py +340 -0
- dolphin/cli/ui/layout.py +425 -0
- dolphin/cli/ui/stream_renderer.py +302 -0
- dolphin/cli/utils/__init__.py +8 -0
- dolphin/cli/utils/helpers.py +135 -0
- dolphin/cli/utils/version.py +49 -0
- dolphin/core/__init__.py +107 -0
- dolphin/core/agent/__init__.py +10 -0
- dolphin/core/agent/agent_state.py +69 -0
- dolphin/core/agent/base_agent.py +970 -0
- dolphin/core/code_block/__init__.py +0 -0
- dolphin/core/code_block/agent_init_block.py +0 -0
- dolphin/core/code_block/assign_block.py +98 -0
- dolphin/core/code_block/basic_code_block.py +1865 -0
- dolphin/core/code_block/explore_block.py +1327 -0
- dolphin/core/code_block/explore_block_v2.py +712 -0
- dolphin/core/code_block/explore_strategy.py +672 -0
- dolphin/core/code_block/judge_block.py +220 -0
- dolphin/core/code_block/prompt_block.py +32 -0
- dolphin/core/code_block/skill_call_deduplicator.py +291 -0
- dolphin/core/code_block/tool_block.py +129 -0
- dolphin/core/common/__init__.py +17 -0
- dolphin/core/common/constants.py +176 -0
- dolphin/core/common/enums.py +1173 -0
- dolphin/core/common/exceptions.py +133 -0
- dolphin/core/common/multimodal.py +539 -0
- dolphin/core/common/object_type.py +165 -0
- dolphin/core/common/output_format.py +432 -0
- dolphin/core/common/types.py +36 -0
- dolphin/core/config/__init__.py +16 -0
- dolphin/core/config/global_config.py +1289 -0
- dolphin/core/config/ontology_config.py +133 -0
- dolphin/core/context/__init__.py +12 -0
- dolphin/core/context/context.py +1580 -0
- dolphin/core/context/context_manager.py +161 -0
- dolphin/core/context/var_output.py +82 -0
- dolphin/core/context/variable_pool.py +356 -0
- dolphin/core/context_engineer/__init__.py +41 -0
- dolphin/core/context_engineer/config/__init__.py +5 -0
- dolphin/core/context_engineer/config/settings.py +402 -0
- dolphin/core/context_engineer/core/__init__.py +7 -0
- dolphin/core/context_engineer/core/budget_manager.py +327 -0
- dolphin/core/context_engineer/core/context_assembler.py +583 -0
- dolphin/core/context_engineer/core/context_manager.py +637 -0
- dolphin/core/context_engineer/core/tokenizer_service.py +260 -0
- dolphin/core/context_engineer/example/incremental_example.py +267 -0
- dolphin/core/context_engineer/example/traditional_example.py +334 -0
- dolphin/core/context_engineer/services/__init__.py +5 -0
- dolphin/core/context_engineer/services/compressor.py +399 -0
- dolphin/core/context_engineer/utils/__init__.py +6 -0
- dolphin/core/context_engineer/utils/context_utils.py +441 -0
- dolphin/core/context_engineer/utils/message_formatter.py +270 -0
- dolphin/core/context_engineer/utils/token_utils.py +139 -0
- dolphin/core/coroutine/__init__.py +15 -0
- dolphin/core/coroutine/context_snapshot.py +154 -0
- dolphin/core/coroutine/context_snapshot_profile.py +922 -0
- dolphin/core/coroutine/context_snapshot_store.py +268 -0
- dolphin/core/coroutine/execution_frame.py +145 -0
- dolphin/core/coroutine/execution_state_registry.py +161 -0
- dolphin/core/coroutine/resume_handle.py +101 -0
- dolphin/core/coroutine/step_result.py +101 -0
- dolphin/core/executor/__init__.py +18 -0
- dolphin/core/executor/debug_controller.py +630 -0
- dolphin/core/executor/dolphin_executor.py +1063 -0
- dolphin/core/executor/executor.py +624 -0
- dolphin/core/flags/__init__.py +27 -0
- dolphin/core/flags/definitions.py +49 -0
- dolphin/core/flags/manager.py +113 -0
- dolphin/core/hook/__init__.py +95 -0
- dolphin/core/hook/expression_evaluator.py +499 -0
- dolphin/core/hook/hook_dispatcher.py +380 -0
- dolphin/core/hook/hook_types.py +248 -0
- dolphin/core/hook/isolated_variable_pool.py +284 -0
- dolphin/core/interfaces.py +53 -0
- dolphin/core/llm/__init__.py +0 -0
- dolphin/core/llm/llm.py +495 -0
- dolphin/core/llm/llm_call.py +100 -0
- dolphin/core/llm/llm_client.py +1285 -0
- dolphin/core/llm/message_sanitizer.py +120 -0
- dolphin/core/logging/__init__.py +20 -0
- dolphin/core/logging/logger.py +526 -0
- dolphin/core/message/__init__.py +8 -0
- dolphin/core/message/compressor.py +749 -0
- dolphin/core/parser/__init__.py +8 -0
- dolphin/core/parser/parser.py +405 -0
- dolphin/core/runtime/__init__.py +10 -0
- dolphin/core/runtime/runtime_graph.py +926 -0
- dolphin/core/runtime/runtime_instance.py +446 -0
- dolphin/core/skill/__init__.py +14 -0
- dolphin/core/skill/context_retention.py +157 -0
- dolphin/core/skill/skill_function.py +686 -0
- dolphin/core/skill/skill_matcher.py +282 -0
- dolphin/core/skill/skillkit.py +700 -0
- dolphin/core/skill/skillset.py +72 -0
- dolphin/core/trajectory/__init__.py +10 -0
- dolphin/core/trajectory/recorder.py +189 -0
- dolphin/core/trajectory/trajectory.py +522 -0
- dolphin/core/utils/__init__.py +9 -0
- dolphin/core/utils/cache_kv.py +212 -0
- dolphin/core/utils/tools.py +340 -0
- dolphin/lib/__init__.py +93 -0
- dolphin/lib/debug/__init__.py +8 -0
- dolphin/lib/debug/visualizer.py +409 -0
- dolphin/lib/memory/__init__.py +28 -0
- dolphin/lib/memory/async_processor.py +220 -0
- dolphin/lib/memory/llm_calls.py +195 -0
- dolphin/lib/memory/manager.py +78 -0
- dolphin/lib/memory/sandbox.py +46 -0
- dolphin/lib/memory/storage.py +245 -0
- dolphin/lib/memory/utils.py +51 -0
- dolphin/lib/ontology/__init__.py +12 -0
- dolphin/lib/ontology/basic/__init__.py +0 -0
- dolphin/lib/ontology/basic/base.py +102 -0
- dolphin/lib/ontology/basic/concept.py +130 -0
- dolphin/lib/ontology/basic/object.py +11 -0
- dolphin/lib/ontology/basic/relation.py +63 -0
- dolphin/lib/ontology/datasource/__init__.py +27 -0
- dolphin/lib/ontology/datasource/datasource.py +66 -0
- dolphin/lib/ontology/datasource/oracle_datasource.py +338 -0
- dolphin/lib/ontology/datasource/sql.py +845 -0
- dolphin/lib/ontology/mapping.py +177 -0
- dolphin/lib/ontology/ontology.py +733 -0
- dolphin/lib/ontology/ontology_context.py +16 -0
- dolphin/lib/ontology/ontology_manager.py +107 -0
- dolphin/lib/skill_results/__init__.py +31 -0
- dolphin/lib/skill_results/cache_backend.py +559 -0
- dolphin/lib/skill_results/result_processor.py +181 -0
- dolphin/lib/skill_results/result_reference.py +179 -0
- dolphin/lib/skill_results/skillkit_hook.py +324 -0
- dolphin/lib/skill_results/strategies.py +328 -0
- dolphin/lib/skill_results/strategy_registry.py +150 -0
- dolphin/lib/skillkits/__init__.py +44 -0
- dolphin/lib/skillkits/agent_skillkit.py +155 -0
- dolphin/lib/skillkits/cognitive_skillkit.py +82 -0
- dolphin/lib/skillkits/env_skillkit.py +250 -0
- dolphin/lib/skillkits/mcp_adapter.py +616 -0
- dolphin/lib/skillkits/mcp_skillkit.py +771 -0
- dolphin/lib/skillkits/memory_skillkit.py +650 -0
- dolphin/lib/skillkits/noop_skillkit.py +31 -0
- dolphin/lib/skillkits/ontology_skillkit.py +89 -0
- dolphin/lib/skillkits/plan_act_skillkit.py +452 -0
- dolphin/lib/skillkits/resource/__init__.py +52 -0
- dolphin/lib/skillkits/resource/models/__init__.py +6 -0
- dolphin/lib/skillkits/resource/models/skill_config.py +109 -0
- dolphin/lib/skillkits/resource/models/skill_meta.py +127 -0
- dolphin/lib/skillkits/resource/resource_skillkit.py +393 -0
- dolphin/lib/skillkits/resource/skill_cache.py +215 -0
- dolphin/lib/skillkits/resource/skill_loader.py +395 -0
- dolphin/lib/skillkits/resource/skill_validator.py +406 -0
- dolphin/lib/skillkits/resource_skillkit.py +11 -0
- dolphin/lib/skillkits/search_skillkit.py +163 -0
- dolphin/lib/skillkits/sql_skillkit.py +274 -0
- dolphin/lib/skillkits/system_skillkit.py +509 -0
- dolphin/lib/skillkits/vm_skillkit.py +65 -0
- dolphin/lib/utils/__init__.py +9 -0
- dolphin/lib/utils/data_process.py +207 -0
- dolphin/lib/utils/handle_progress.py +178 -0
- dolphin/lib/utils/security.py +139 -0
- dolphin/lib/utils/text_retrieval.py +462 -0
- dolphin/lib/vm/__init__.py +11 -0
- dolphin/lib/vm/env_executor.py +895 -0
- dolphin/lib/vm/python_session_manager.py +453 -0
- dolphin/lib/vm/vm.py +610 -0
- dolphin/sdk/__init__.py +60 -0
- dolphin/sdk/agent/__init__.py +12 -0
- dolphin/sdk/agent/agent_factory.py +236 -0
- dolphin/sdk/agent/dolphin_agent.py +1106 -0
- dolphin/sdk/api/__init__.py +4 -0
- dolphin/sdk/runtime/__init__.py +8 -0
- dolphin/sdk/runtime/env.py +363 -0
- dolphin/sdk/skill/__init__.py +10 -0
- dolphin/sdk/skill/global_skills.py +706 -0
- dolphin/sdk/skill/traditional_toolkit.py +260 -0
- kweaver_dolphin-0.1.0.dist-info/METADATA +521 -0
- kweaver_dolphin-0.1.0.dist-info/RECORD +199 -0
- kweaver_dolphin-0.1.0.dist-info/WHEEL +5 -0
- kweaver_dolphin-0.1.0.dist-info/entry_points.txt +27 -0
- kweaver_dolphin-0.1.0.dist-info/licenses/LICENSE.txt +201 -0
- kweaver_dolphin-0.1.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from dolphin.core.utils.tools import extract_json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class ValidationResult:
|
|
8
|
+
"""Syntax Validation Result"""
|
|
9
|
+
|
|
10
|
+
is_valid: bool
|
|
11
|
+
error_message: str = ""
|
|
12
|
+
line_number: int = 0
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def success(cls) -> "ValidationResult":
|
|
16
|
+
return cls(True)
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def error(cls, message: str, line_number: int = 0) -> "ValidationResult":
|
|
20
|
+
return cls(False, message, line_number)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DPHSyntaxValidator:
|
|
24
|
+
"""DPH File Syntax Validator
|
|
25
|
+
|
|
26
|
+
Responsibilities:
|
|
27
|
+
1. Validate the overall syntax structure of DPH files
|
|
28
|
+
2. Validate syntax rules for various code blocks
|
|
29
|
+
3. Provide clear error messages
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
self.tool_pattern = (
|
|
34
|
+
r"@([\w\u4e00-\u9fff_-]+)\((.*?)\)\s*(->|>>)\s*([\w\u4e00-\u9fff]+)"
|
|
35
|
+
)
|
|
36
|
+
self.content_lines = [] # Store content lines for line number tracking
|
|
37
|
+
|
|
38
|
+
def validate(self, content: str) -> ValidationResult:
|
|
39
|
+
"""Validate DPH file syntax
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
content: Content of the DPH file
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
ValidationResult: Validation result
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
# Store content lines for line number tracking
|
|
49
|
+
self.content_lines = content.splitlines()
|
|
50
|
+
|
|
51
|
+
# 1. Basic Content Check
|
|
52
|
+
result = self._validate_basic_content(content)
|
|
53
|
+
if not result.is_valid:
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
# 2. Try to parse as a code block
|
|
57
|
+
result = self._validate_parsing(content)
|
|
58
|
+
if not result.is_valid:
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
# 3. Verify each code block
|
|
62
|
+
result = self._validate_blocks(content)
|
|
63
|
+
if not result.is_valid:
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
return ValidationResult.success()
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
return ValidationResult.error(f"Unexpected validation error: {str(e)}", 0)
|
|
70
|
+
|
|
71
|
+
def _get_line_number(self, target_text: str) -> int:
|
|
72
|
+
"""Get the line number of the specified text in the content"""
|
|
73
|
+
try:
|
|
74
|
+
if not target_text:
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
for i, line in enumerate(self.content_lines):
|
|
78
|
+
if target_text.strip() in line:
|
|
79
|
+
return i + 1 # Return the line number in base 1.
|
|
80
|
+
return 0
|
|
81
|
+
except:
|
|
82
|
+
return 0
|
|
83
|
+
|
|
84
|
+
def _validate_basic_content(self, content: str) -> ValidationResult:
|
|
85
|
+
"""Verify basic content"""
|
|
86
|
+
if not content or not content.strip():
|
|
87
|
+
return ValidationResult.error("DPH file is empty", 1)
|
|
88
|
+
|
|
89
|
+
# Remove comments and check
|
|
90
|
+
cleaned_content = self._remove_comments(content)
|
|
91
|
+
if not cleaned_content.strip():
|
|
92
|
+
return ValidationResult.error("DPH file contains only comments", 1)
|
|
93
|
+
|
|
94
|
+
return ValidationResult.success()
|
|
95
|
+
|
|
96
|
+
def _validate_parsing(self, content: str) -> ValidationResult:
|
|
97
|
+
"""Verify whether correct parsing can be achieved"""
|
|
98
|
+
try:
|
|
99
|
+
parser = Parser(None)
|
|
100
|
+
cleaned_content = self._remove_comments(content)
|
|
101
|
+
blocks = Parser.parse(parser, cleaned_content)
|
|
102
|
+
|
|
103
|
+
if not blocks:
|
|
104
|
+
return ValidationResult.error("No valid blocks found in DPH file", 1)
|
|
105
|
+
|
|
106
|
+
return ValidationResult.success()
|
|
107
|
+
|
|
108
|
+
except Exception as e:
|
|
109
|
+
return ValidationResult.error(f"Parse error: {str(e)}", 0)
|
|
110
|
+
|
|
111
|
+
def _validate_blocks(self, content: str) -> ValidationResult:
|
|
112
|
+
"""Verify the syntax of each code block"""
|
|
113
|
+
try:
|
|
114
|
+
parser = Parser(None)
|
|
115
|
+
cleaned_content = self._remove_comments(content)
|
|
116
|
+
blocks = Parser.parse(parser, cleaned_content)
|
|
117
|
+
|
|
118
|
+
for block_type, block_content in blocks:
|
|
119
|
+
result = self._validate_single_block(block_type, block_content)
|
|
120
|
+
if not result.is_valid:
|
|
121
|
+
return result
|
|
122
|
+
|
|
123
|
+
return ValidationResult.success()
|
|
124
|
+
|
|
125
|
+
except Exception as e:
|
|
126
|
+
return ValidationResult.error(f"Block validation error: {str(e)}", 0)
|
|
127
|
+
|
|
128
|
+
def _validate_single_block(
|
|
129
|
+
self, block_type: str, block_content: str
|
|
130
|
+
) -> ValidationResult:
|
|
131
|
+
"""Verify a single code block"""
|
|
132
|
+
block_content = block_content.strip()
|
|
133
|
+
line_num = self._get_line_number(block_content)
|
|
134
|
+
|
|
135
|
+
# Basic assignment syntax check
|
|
136
|
+
if "->" not in block_content and ">>" not in block_content:
|
|
137
|
+
return ValidationResult.error(
|
|
138
|
+
f"Missing assignment operator (->/>>) in {block_type} block", line_num
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Validate by type
|
|
142
|
+
validators = {
|
|
143
|
+
"tool": self._validate_tool_block,
|
|
144
|
+
"assign": self._validate_assign_block,
|
|
145
|
+
"prompt": self._validate_action_block,
|
|
146
|
+
"judge": self._validate_action_block,
|
|
147
|
+
"explore": self._validate_action_block,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
validator = validators.get(block_type, self._validate_generic_block)
|
|
151
|
+
return validator(block_type, block_content)
|
|
152
|
+
|
|
153
|
+
def _validate_tool_block(self, block_type: str, content: str) -> ValidationResult:
|
|
154
|
+
"""Validation Tool Call Block"""
|
|
155
|
+
if not re.search(self.tool_pattern, content):
|
|
156
|
+
line_num = self._get_line_number(content)
|
|
157
|
+
return ValidationResult.error(
|
|
158
|
+
f"Invalid tool call format in {block_type} block: {content}", line_num
|
|
159
|
+
)
|
|
160
|
+
return ValidationResult.success()
|
|
161
|
+
|
|
162
|
+
def _validate_assign_block(self, block_type: str, content: str) -> ValidationResult:
|
|
163
|
+
"""Verify assignment block"""
|
|
164
|
+
line_num = self._get_line_number(content)
|
|
165
|
+
|
|
166
|
+
if "->" in content:
|
|
167
|
+
parts = content.split("->", 1)
|
|
168
|
+
if len(parts) != 2 or not parts[1].strip():
|
|
169
|
+
return ValidationResult.error(
|
|
170
|
+
f"Invalid assignment with '->': {content}", line_num
|
|
171
|
+
)
|
|
172
|
+
elif ">>" in content:
|
|
173
|
+
parts = content.split(">>", 1)
|
|
174
|
+
if len(parts) != 2 or not parts[1].strip():
|
|
175
|
+
return ValidationResult.error(
|
|
176
|
+
f"Invalid assignment with '>>': {content}", line_num
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return ValidationResult.success()
|
|
180
|
+
|
|
181
|
+
def _validate_action_block(self, block_type: str, content: str) -> ValidationResult:
|
|
182
|
+
"""Verify action block (prompt, judge, explore)"""
|
|
183
|
+
expected_prefix = f"/{block_type}/"
|
|
184
|
+
if not content.startswith(expected_prefix):
|
|
185
|
+
line_num = self._get_line_number(content)
|
|
186
|
+
return ValidationResult.error(
|
|
187
|
+
f"Missing '{expected_prefix}' prefix in {block_type} block", line_num
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return ValidationResult.success()
|
|
191
|
+
|
|
192
|
+
def _validate_generic_block(
|
|
193
|
+
self, block_type: str, content: str
|
|
194
|
+
) -> ValidationResult:
|
|
195
|
+
"""Verify generic block"""
|
|
196
|
+
# For blocks of unknown types, perform only basic checks.
|
|
197
|
+
return ValidationResult.success()
|
|
198
|
+
|
|
199
|
+
def _remove_comments(self, content: str) -> str:
|
|
200
|
+
"""Remove comment lines"""
|
|
201
|
+
lines = content.splitlines()
|
|
202
|
+
filtered_lines = [line for line in lines if not line.strip().startswith("#")]
|
|
203
|
+
return "\n".join(filtered_lines)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
label_dict = {
|
|
207
|
+
"if": "/if/",
|
|
208
|
+
"for": "/for/",
|
|
209
|
+
"parallel": "/parallel/",
|
|
210
|
+
"def": "/def/",
|
|
211
|
+
"end": "/end/",
|
|
212
|
+
"exit": "/exit/",
|
|
213
|
+
"code": "/code/",
|
|
214
|
+
"python": "/python/",
|
|
215
|
+
"tool": r"@([\w\u4e00-\u9fff_-]+)\((.*?)\)\s*(->|>>)\s*([\w\u4e00-\u9fff]+)",
|
|
216
|
+
"=": r"->\s*[a-zA-Z_]\w*", # Match the variable name after "->"
|
|
217
|
+
"append": r">>\s*[a-zA-Z_]\w*",
|
|
218
|
+
} # Match the variable name after ">>"}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def split_by_pattern(content):
|
|
222
|
+
# Regular expression matching for each block
|
|
223
|
+
if not content:
|
|
224
|
+
return None
|
|
225
|
+
pattern1 = label_dict["="]
|
|
226
|
+
pattern2 = label_dict["append"]
|
|
227
|
+
pattern = r"{}|{}".format(pattern1, pattern2)
|
|
228
|
+
matches = list(re.finditer(pattern, content))
|
|
229
|
+
split_positions = [m.end() for m in matches] # Get all matching end positions
|
|
230
|
+
# Split string by ending position
|
|
231
|
+
result = []
|
|
232
|
+
prev_position = 0
|
|
233
|
+
for pos in split_positions:
|
|
234
|
+
result.append(content[prev_position:pos].lstrip("\n")) # Get segmentation segments
|
|
235
|
+
prev_position = pos # Update start point
|
|
236
|
+
content_end = content[prev_position:].lstrip("\n")
|
|
237
|
+
# Add the last paragraph
|
|
238
|
+
if len(content_end):
|
|
239
|
+
result.append(content_end)
|
|
240
|
+
# Output result
|
|
241
|
+
return result
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def find_gaps(length, intervals):
|
|
245
|
+
# Sort Range
|
|
246
|
+
intervals.sort(key=lambda x: (x[0], x[1]))
|
|
247
|
+
|
|
248
|
+
# Merge Intervals
|
|
249
|
+
merged_intervals = []
|
|
250
|
+
for interval in intervals:
|
|
251
|
+
if not merged_intervals or merged_intervals[-1][1] < interval[0]:
|
|
252
|
+
merged_intervals.append(interval)
|
|
253
|
+
else:
|
|
254
|
+
merged_intervals[-1][1] = max(merged_intervals[-1][1], interval[1])
|
|
255
|
+
|
|
256
|
+
# Find Gap
|
|
257
|
+
gaps = []
|
|
258
|
+
prev_end = 0
|
|
259
|
+
for start, end in merged_intervals:
|
|
260
|
+
if prev_end < start:
|
|
261
|
+
gaps.append([prev_end, start])
|
|
262
|
+
prev_end = max(prev_end, end)
|
|
263
|
+
|
|
264
|
+
# Check the gap from the last interval to n
|
|
265
|
+
if prev_end < length:
|
|
266
|
+
gaps.append([prev_end, length])
|
|
267
|
+
|
|
268
|
+
return gaps
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class Parser:
|
|
272
|
+
def __init__(self, context):
|
|
273
|
+
self.parsed_data = None
|
|
274
|
+
self.context = context
|
|
275
|
+
|
|
276
|
+
def remove_comment(self, content):
|
|
277
|
+
lines = content.splitlines()
|
|
278
|
+
filtered_lines = [line for line in lines if not line.strip().startswith("#")]
|
|
279
|
+
return "\n".join(filtered_lines)
|
|
280
|
+
|
|
281
|
+
@staticmethod
|
|
282
|
+
def parse(self, input_string):
|
|
283
|
+
block_labels = {
|
|
284
|
+
"if": label_dict["if"],
|
|
285
|
+
"for": label_dict["for"],
|
|
286
|
+
"def": label_dict["def"],
|
|
287
|
+
"exit": label_dict["exit"],
|
|
288
|
+
"code": label_dict["code"],
|
|
289
|
+
"python": label_dict["python"],
|
|
290
|
+
"end": label_dict["end"],
|
|
291
|
+
"parallel": label_dict["parallel"],
|
|
292
|
+
}
|
|
293
|
+
label_indexes = []
|
|
294
|
+
for key, value in block_labels.items():
|
|
295
|
+
start_indexes = [
|
|
296
|
+
match.start() for match in re.finditer(re.escape(value), input_string)
|
|
297
|
+
]
|
|
298
|
+
for i in range(len(start_indexes)):
|
|
299
|
+
label_indexes.append(
|
|
300
|
+
[key, start_indexes[i], start_indexes[i] + len(value)]
|
|
301
|
+
)
|
|
302
|
+
sorted_label_indexes = sorted(label_indexes, key=lambda x: x[1])
|
|
303
|
+
label_stack = []
|
|
304
|
+
blocks = []
|
|
305
|
+
for i in range(len(sorted_label_indexes)):
|
|
306
|
+
if sorted_label_indexes[i][0] == "end":
|
|
307
|
+
label = label_stack[-1][0]
|
|
308
|
+
start = label_stack[-1][1]
|
|
309
|
+
end = sorted_label_indexes[i][2]
|
|
310
|
+
label_stack.pop()
|
|
311
|
+
if not label_stack:
|
|
312
|
+
blocks.append([label, start, end])
|
|
313
|
+
else:
|
|
314
|
+
label_stack.append(sorted_label_indexes[i])
|
|
315
|
+
intervals = [[start, end] for label, start, end in blocks]
|
|
316
|
+
gaps = find_gaps(len(input_string), intervals)
|
|
317
|
+
for start, end in gaps:
|
|
318
|
+
blocks.append(["prompt_or_tool", start, end])
|
|
319
|
+
sorted_blocks = sorted(blocks, key=lambda x: x[1])
|
|
320
|
+
blocks_final = []
|
|
321
|
+
for label, start, end in sorted_blocks:
|
|
322
|
+
s = input_string[start:end]
|
|
323
|
+
if label != "prompt_or_tool":
|
|
324
|
+
blocks_final.append([label, input_string[start:end]])
|
|
325
|
+
else:
|
|
326
|
+
s = input_string[start:end].strip()
|
|
327
|
+
if s:
|
|
328
|
+
promptortool_blocks = split_by_pattern(s)
|
|
329
|
+
for promptortool_block in promptortool_blocks:
|
|
330
|
+
tool_pattern = label_dict["tool"]
|
|
331
|
+
if promptortool_block.startswith("@agent_init"):
|
|
332
|
+
blocks_final.append(["agent_init", promptortool_block])
|
|
333
|
+
elif promptortool_block.startswith("/judge/"):
|
|
334
|
+
blocks_final.append(["judge", promptortool_block])
|
|
335
|
+
elif promptortool_block.startswith("/explore/"):
|
|
336
|
+
blocks_final.append(["explore", promptortool_block])
|
|
337
|
+
elif promptortool_block.startswith("/prompt/"):
|
|
338
|
+
blocks_final.append(["prompt", promptortool_block])
|
|
339
|
+
elif bool(re.search(tool_pattern, promptortool_block)):
|
|
340
|
+
blocks_final.append(["tool", promptortool_block])
|
|
341
|
+
else:
|
|
342
|
+
blocks_final.append(["assign", promptortool_block])
|
|
343
|
+
|
|
344
|
+
for block in blocks_final:
|
|
345
|
+
if "->" not in block[1] and ">>" not in block[1]:
|
|
346
|
+
raise ValueError("invalid format(no -> or >> in block)")
|
|
347
|
+
return blocks_final
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def validate_syntax(content: str) -> tuple[bool, str]:
|
|
351
|
+
"""Validate DPH file syntax, delegated to a dedicated validator
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
content: Content of the DPH file
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
tuple[bool, str]: (Is valid, Error message)
|
|
358
|
+
"""
|
|
359
|
+
validator = DPHSyntaxValidator()
|
|
360
|
+
result = validator.validate(content)
|
|
361
|
+
return result.is_valid, result.error_message
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def re_params_extract(params_content):
|
|
365
|
+
params_content = params_content.strip()
|
|
366
|
+
params = {}
|
|
367
|
+
for param in params_content.split(","):
|
|
368
|
+
param = param.strip()
|
|
369
|
+
key, value = param.split(":", 1)
|
|
370
|
+
params[key.strip()] = value.strip()
|
|
371
|
+
return params
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def params_extract_0(params_content):
|
|
375
|
+
stack = 0
|
|
376
|
+
params_content = params_content.strip()
|
|
377
|
+
|
|
378
|
+
json_end = 0
|
|
379
|
+
for index, char in enumerate(params_content):
|
|
380
|
+
if char == "{":
|
|
381
|
+
stack += 1
|
|
382
|
+
elif char == "}":
|
|
383
|
+
stack -= 1
|
|
384
|
+
if stack == 0:
|
|
385
|
+
json_end = index + 1
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
re_extracted_params = re_params_extract(params_content=params_content[:json_end])
|
|
389
|
+
return re_extracted_params
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def params_extract(params_content):
|
|
393
|
+
"""
|
|
394
|
+
Extract and parse JSON parameters from tool call content.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
params_content (str): Raw parameter content that may contain JSON
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
dict or None: Parsed parameters dict, or None if parsing fails
|
|
401
|
+
"""
|
|
402
|
+
try:
|
|
403
|
+
return extract_json(params_content)
|
|
404
|
+
except ValueError:
|
|
405
|
+
return None
|