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.
Files changed (199) hide show
  1. DolphinLanguageSDK/__init__.py +58 -0
  2. dolphin/__init__.py +62 -0
  3. dolphin/cli/__init__.py +20 -0
  4. dolphin/cli/args/__init__.py +9 -0
  5. dolphin/cli/args/parser.py +567 -0
  6. dolphin/cli/builtin_agents/__init__.py +22 -0
  7. dolphin/cli/commands/__init__.py +4 -0
  8. dolphin/cli/interrupt/__init__.py +8 -0
  9. dolphin/cli/interrupt/handler.py +205 -0
  10. dolphin/cli/interrupt/keyboard.py +82 -0
  11. dolphin/cli/main.py +49 -0
  12. dolphin/cli/multimodal/__init__.py +34 -0
  13. dolphin/cli/multimodal/clipboard.py +327 -0
  14. dolphin/cli/multimodal/handler.py +249 -0
  15. dolphin/cli/multimodal/image_processor.py +214 -0
  16. dolphin/cli/multimodal/input_parser.py +149 -0
  17. dolphin/cli/runner/__init__.py +8 -0
  18. dolphin/cli/runner/runner.py +989 -0
  19. dolphin/cli/ui/__init__.py +10 -0
  20. dolphin/cli/ui/console.py +2795 -0
  21. dolphin/cli/ui/input.py +340 -0
  22. dolphin/cli/ui/layout.py +425 -0
  23. dolphin/cli/ui/stream_renderer.py +302 -0
  24. dolphin/cli/utils/__init__.py +8 -0
  25. dolphin/cli/utils/helpers.py +135 -0
  26. dolphin/cli/utils/version.py +49 -0
  27. dolphin/core/__init__.py +107 -0
  28. dolphin/core/agent/__init__.py +10 -0
  29. dolphin/core/agent/agent_state.py +69 -0
  30. dolphin/core/agent/base_agent.py +970 -0
  31. dolphin/core/code_block/__init__.py +0 -0
  32. dolphin/core/code_block/agent_init_block.py +0 -0
  33. dolphin/core/code_block/assign_block.py +98 -0
  34. dolphin/core/code_block/basic_code_block.py +1865 -0
  35. dolphin/core/code_block/explore_block.py +1327 -0
  36. dolphin/core/code_block/explore_block_v2.py +712 -0
  37. dolphin/core/code_block/explore_strategy.py +672 -0
  38. dolphin/core/code_block/judge_block.py +220 -0
  39. dolphin/core/code_block/prompt_block.py +32 -0
  40. dolphin/core/code_block/skill_call_deduplicator.py +291 -0
  41. dolphin/core/code_block/tool_block.py +129 -0
  42. dolphin/core/common/__init__.py +17 -0
  43. dolphin/core/common/constants.py +176 -0
  44. dolphin/core/common/enums.py +1173 -0
  45. dolphin/core/common/exceptions.py +133 -0
  46. dolphin/core/common/multimodal.py +539 -0
  47. dolphin/core/common/object_type.py +165 -0
  48. dolphin/core/common/output_format.py +432 -0
  49. dolphin/core/common/types.py +36 -0
  50. dolphin/core/config/__init__.py +16 -0
  51. dolphin/core/config/global_config.py +1289 -0
  52. dolphin/core/config/ontology_config.py +133 -0
  53. dolphin/core/context/__init__.py +12 -0
  54. dolphin/core/context/context.py +1580 -0
  55. dolphin/core/context/context_manager.py +161 -0
  56. dolphin/core/context/var_output.py +82 -0
  57. dolphin/core/context/variable_pool.py +356 -0
  58. dolphin/core/context_engineer/__init__.py +41 -0
  59. dolphin/core/context_engineer/config/__init__.py +5 -0
  60. dolphin/core/context_engineer/config/settings.py +402 -0
  61. dolphin/core/context_engineer/core/__init__.py +7 -0
  62. dolphin/core/context_engineer/core/budget_manager.py +327 -0
  63. dolphin/core/context_engineer/core/context_assembler.py +583 -0
  64. dolphin/core/context_engineer/core/context_manager.py +637 -0
  65. dolphin/core/context_engineer/core/tokenizer_service.py +260 -0
  66. dolphin/core/context_engineer/example/incremental_example.py +267 -0
  67. dolphin/core/context_engineer/example/traditional_example.py +334 -0
  68. dolphin/core/context_engineer/services/__init__.py +5 -0
  69. dolphin/core/context_engineer/services/compressor.py +399 -0
  70. dolphin/core/context_engineer/utils/__init__.py +6 -0
  71. dolphin/core/context_engineer/utils/context_utils.py +441 -0
  72. dolphin/core/context_engineer/utils/message_formatter.py +270 -0
  73. dolphin/core/context_engineer/utils/token_utils.py +139 -0
  74. dolphin/core/coroutine/__init__.py +15 -0
  75. dolphin/core/coroutine/context_snapshot.py +154 -0
  76. dolphin/core/coroutine/context_snapshot_profile.py +922 -0
  77. dolphin/core/coroutine/context_snapshot_store.py +268 -0
  78. dolphin/core/coroutine/execution_frame.py +145 -0
  79. dolphin/core/coroutine/execution_state_registry.py +161 -0
  80. dolphin/core/coroutine/resume_handle.py +101 -0
  81. dolphin/core/coroutine/step_result.py +101 -0
  82. dolphin/core/executor/__init__.py +18 -0
  83. dolphin/core/executor/debug_controller.py +630 -0
  84. dolphin/core/executor/dolphin_executor.py +1063 -0
  85. dolphin/core/executor/executor.py +624 -0
  86. dolphin/core/flags/__init__.py +27 -0
  87. dolphin/core/flags/definitions.py +49 -0
  88. dolphin/core/flags/manager.py +113 -0
  89. dolphin/core/hook/__init__.py +95 -0
  90. dolphin/core/hook/expression_evaluator.py +499 -0
  91. dolphin/core/hook/hook_dispatcher.py +380 -0
  92. dolphin/core/hook/hook_types.py +248 -0
  93. dolphin/core/hook/isolated_variable_pool.py +284 -0
  94. dolphin/core/interfaces.py +53 -0
  95. dolphin/core/llm/__init__.py +0 -0
  96. dolphin/core/llm/llm.py +495 -0
  97. dolphin/core/llm/llm_call.py +100 -0
  98. dolphin/core/llm/llm_client.py +1285 -0
  99. dolphin/core/llm/message_sanitizer.py +120 -0
  100. dolphin/core/logging/__init__.py +20 -0
  101. dolphin/core/logging/logger.py +526 -0
  102. dolphin/core/message/__init__.py +8 -0
  103. dolphin/core/message/compressor.py +749 -0
  104. dolphin/core/parser/__init__.py +8 -0
  105. dolphin/core/parser/parser.py +405 -0
  106. dolphin/core/runtime/__init__.py +10 -0
  107. dolphin/core/runtime/runtime_graph.py +926 -0
  108. dolphin/core/runtime/runtime_instance.py +446 -0
  109. dolphin/core/skill/__init__.py +14 -0
  110. dolphin/core/skill/context_retention.py +157 -0
  111. dolphin/core/skill/skill_function.py +686 -0
  112. dolphin/core/skill/skill_matcher.py +282 -0
  113. dolphin/core/skill/skillkit.py +700 -0
  114. dolphin/core/skill/skillset.py +72 -0
  115. dolphin/core/trajectory/__init__.py +10 -0
  116. dolphin/core/trajectory/recorder.py +189 -0
  117. dolphin/core/trajectory/trajectory.py +522 -0
  118. dolphin/core/utils/__init__.py +9 -0
  119. dolphin/core/utils/cache_kv.py +212 -0
  120. dolphin/core/utils/tools.py +340 -0
  121. dolphin/lib/__init__.py +93 -0
  122. dolphin/lib/debug/__init__.py +8 -0
  123. dolphin/lib/debug/visualizer.py +409 -0
  124. dolphin/lib/memory/__init__.py +28 -0
  125. dolphin/lib/memory/async_processor.py +220 -0
  126. dolphin/lib/memory/llm_calls.py +195 -0
  127. dolphin/lib/memory/manager.py +78 -0
  128. dolphin/lib/memory/sandbox.py +46 -0
  129. dolphin/lib/memory/storage.py +245 -0
  130. dolphin/lib/memory/utils.py +51 -0
  131. dolphin/lib/ontology/__init__.py +12 -0
  132. dolphin/lib/ontology/basic/__init__.py +0 -0
  133. dolphin/lib/ontology/basic/base.py +102 -0
  134. dolphin/lib/ontology/basic/concept.py +130 -0
  135. dolphin/lib/ontology/basic/object.py +11 -0
  136. dolphin/lib/ontology/basic/relation.py +63 -0
  137. dolphin/lib/ontology/datasource/__init__.py +27 -0
  138. dolphin/lib/ontology/datasource/datasource.py +66 -0
  139. dolphin/lib/ontology/datasource/oracle_datasource.py +338 -0
  140. dolphin/lib/ontology/datasource/sql.py +845 -0
  141. dolphin/lib/ontology/mapping.py +177 -0
  142. dolphin/lib/ontology/ontology.py +733 -0
  143. dolphin/lib/ontology/ontology_context.py +16 -0
  144. dolphin/lib/ontology/ontology_manager.py +107 -0
  145. dolphin/lib/skill_results/__init__.py +31 -0
  146. dolphin/lib/skill_results/cache_backend.py +559 -0
  147. dolphin/lib/skill_results/result_processor.py +181 -0
  148. dolphin/lib/skill_results/result_reference.py +179 -0
  149. dolphin/lib/skill_results/skillkit_hook.py +324 -0
  150. dolphin/lib/skill_results/strategies.py +328 -0
  151. dolphin/lib/skill_results/strategy_registry.py +150 -0
  152. dolphin/lib/skillkits/__init__.py +44 -0
  153. dolphin/lib/skillkits/agent_skillkit.py +155 -0
  154. dolphin/lib/skillkits/cognitive_skillkit.py +82 -0
  155. dolphin/lib/skillkits/env_skillkit.py +250 -0
  156. dolphin/lib/skillkits/mcp_adapter.py +616 -0
  157. dolphin/lib/skillkits/mcp_skillkit.py +771 -0
  158. dolphin/lib/skillkits/memory_skillkit.py +650 -0
  159. dolphin/lib/skillkits/noop_skillkit.py +31 -0
  160. dolphin/lib/skillkits/ontology_skillkit.py +89 -0
  161. dolphin/lib/skillkits/plan_act_skillkit.py +452 -0
  162. dolphin/lib/skillkits/resource/__init__.py +52 -0
  163. dolphin/lib/skillkits/resource/models/__init__.py +6 -0
  164. dolphin/lib/skillkits/resource/models/skill_config.py +109 -0
  165. dolphin/lib/skillkits/resource/models/skill_meta.py +127 -0
  166. dolphin/lib/skillkits/resource/resource_skillkit.py +393 -0
  167. dolphin/lib/skillkits/resource/skill_cache.py +215 -0
  168. dolphin/lib/skillkits/resource/skill_loader.py +395 -0
  169. dolphin/lib/skillkits/resource/skill_validator.py +406 -0
  170. dolphin/lib/skillkits/resource_skillkit.py +11 -0
  171. dolphin/lib/skillkits/search_skillkit.py +163 -0
  172. dolphin/lib/skillkits/sql_skillkit.py +274 -0
  173. dolphin/lib/skillkits/system_skillkit.py +509 -0
  174. dolphin/lib/skillkits/vm_skillkit.py +65 -0
  175. dolphin/lib/utils/__init__.py +9 -0
  176. dolphin/lib/utils/data_process.py +207 -0
  177. dolphin/lib/utils/handle_progress.py +178 -0
  178. dolphin/lib/utils/security.py +139 -0
  179. dolphin/lib/utils/text_retrieval.py +462 -0
  180. dolphin/lib/vm/__init__.py +11 -0
  181. dolphin/lib/vm/env_executor.py +895 -0
  182. dolphin/lib/vm/python_session_manager.py +453 -0
  183. dolphin/lib/vm/vm.py +610 -0
  184. dolphin/sdk/__init__.py +60 -0
  185. dolphin/sdk/agent/__init__.py +12 -0
  186. dolphin/sdk/agent/agent_factory.py +236 -0
  187. dolphin/sdk/agent/dolphin_agent.py +1106 -0
  188. dolphin/sdk/api/__init__.py +4 -0
  189. dolphin/sdk/runtime/__init__.py +8 -0
  190. dolphin/sdk/runtime/env.py +363 -0
  191. dolphin/sdk/skill/__init__.py +10 -0
  192. dolphin/sdk/skill/global_skills.py +706 -0
  193. dolphin/sdk/skill/traditional_toolkit.py +260 -0
  194. kweaver_dolphin-0.1.0.dist-info/METADATA +521 -0
  195. kweaver_dolphin-0.1.0.dist-info/RECORD +199 -0
  196. kweaver_dolphin-0.1.0.dist-info/WHEEL +5 -0
  197. kweaver_dolphin-0.1.0.dist-info/entry_points.txt +27 -0
  198. kweaver_dolphin-0.1.0.dist-info/licenses/LICENSE.txt +201 -0
  199. kweaver_dolphin-0.1.0.dist-info/top_level.txt +2 -0
dolphin/lib/vm/vm.py ADDED
@@ -0,0 +1,610 @@
1
+ from abc import abstractmethod
2
+ import ast
3
+ import os
4
+ from typing import Any, Dict, Optional, List
5
+ import tempfile
6
+ import random
7
+ import string
8
+
9
+ from dolphin.core.config.global_config import VMConfig, VMConnectionType
10
+ from dolphin.core.utils.cache_kv import CacheKVMgr, GlobalCacheKVCenter
11
+ from dolphin.lib.utils.security import SecurityUtils
12
+ from dolphin.core.logging.logger import get_logger
13
+
14
+
15
+ logger = get_logger("vm")
16
+
17
+ PreImport = [
18
+ "datetime",
19
+ "json",
20
+ ]
21
+
22
+
23
+ class VM:
24
+ """Virtual machine base class, defining the interface for virtual machine operations"""
25
+
26
+ @abstractmethod
27
+ def connect(self) -> bool:
28
+ """Connect to virtual machine
29
+
30
+ Returns:
31
+ bool: Whether the connection was successful
32
+ """
33
+ pass
34
+
35
+ @abstractmethod
36
+ def execBash(self, command: str) -> str:
37
+ """Execute Bash command
38
+
39
+ Args:
40
+ command: The Bash command to execute
41
+
42
+ Returns:
43
+ str: Result of the command execution
44
+ """
45
+ pass
46
+
47
+ def execPython(
48
+ self, code: str, varDict: Optional[Dict[str, Any]] = None, **kwargs
49
+ ) -> str:
50
+ """Execute Python commands. The Python code can be directly generated as a parameter for tool invocation.
51
+ [Attention] The Python code should be directly generated as a parameter for tool invocation, and it is forbidden to generate code blocks like ```python separately!
52
+
53
+ Args:
54
+ code: The Python code to execute. The result should be assigned to return_value at the end of the code.
55
+ varDict: Optional dictionary of variables that will be set in the Python environment before executing the code.
56
+
57
+ Returns:
58
+ str: The command execution result, usually the value of return_value or the output/error during execution.
59
+ """
60
+ pass
61
+
62
+ @abstractmethod
63
+ def disconnect(self) -> None:
64
+ """Disconnect from the virtual machine"""
65
+ pass
66
+
67
+ @staticmethod
68
+ def deserializePythonResult(result: str) -> Any:
69
+ if not result:
70
+ return result
71
+
72
+ if result[0] == "[" or result[0] == "{":
73
+ return ast.literal_eval(result)
74
+ else:
75
+ return result
76
+
77
+
78
+ class VMSSH(VM):
79
+ """SSH-based virtual machine connection implementation"""
80
+
81
+ def __init__(self, config: VMConfig, cache_vm: CacheKVMgr):
82
+ """Initialize SSH connection
83
+
84
+ Args:
85
+ config: Configuration object containing SSH connection information
86
+ """
87
+ self.config = config
88
+ self.cache_vm = cache_vm
89
+ self.client = None
90
+ self.connected = False
91
+ self.attempt_count = 0
92
+ self._paramiko = None # 延迟导入 paramiko
93
+
94
+ def _get_paramiko(self):
95
+ """获取 paramiko 模块(延迟导入)"""
96
+ if self._paramiko is None:
97
+ try:
98
+ import paramiko
99
+ self._paramiko = paramiko
100
+ except ImportError:
101
+ logger.error("paramiko is required for VMSSH but not installed. Please install it: pip install paramiko")
102
+ raise ImportError("paramiko is required for VMSSH but not installed. Please install it: pip install paramiko")
103
+ return self._paramiko
104
+
105
+ def connect(self) -> bool:
106
+ """Establish SSH connection using Paramiko
107
+
108
+ Supports password authentication and SSH key authentication
109
+
110
+ Returns:
111
+ bool: whether the connection is successful
112
+ """
113
+ try:
114
+ paramiko = self._get_paramiko()
115
+ except ImportError:
116
+ return False
117
+
118
+ if not self.config.validate():
119
+ logger.error("VM配置验证failed")
120
+ return False
121
+
122
+ # Reset connection attempt count
123
+ self.attempt_count = 0
124
+ return self._attempt_connect(paramiko)
125
+
126
+ def _attempt_connect(self, paramiko) -> bool:
127
+ """Try to connect, with retry support
128
+
129
+ Args:
130
+ paramiko: The paramiko module (passed to avoid repeated imports)
131
+
132
+ Returns:
133
+ bool: Whether the connection was successful
134
+ """
135
+
136
+ while self.attempt_count < self.config.retryCount:
137
+ try:
138
+ self.attempt_count += 1
139
+ logger.info(
140
+ f"正在connect to到 {self.config.host}:{self.config.port} (尝试 {self.attempt_count}/{self.config.retryCount})"
141
+ )
142
+
143
+ self.client = paramiko.SSHClient()
144
+ self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
145
+
146
+ connect_args = {
147
+ "hostname": self.config.host,
148
+ "port": self.config.port,
149
+ "username": self.config.username,
150
+ "timeout": self.config.timeout,
151
+ }
152
+
153
+ # Use SSH key authenticationPrioritize usingSSH密钥认证
154
+ if self.config.sshKeyPath and os.path.exists(self.config.sshKeyPath):
155
+ logger.info(f"使用SSH密钥认证: {self.config.sshKeyPath}")
156
+ connect_args["key_filename"] = self.config.sshKeyPath
157
+ else:
158
+ # Use password authentication
159
+ logger.info("使用密码认证")
160
+ password = self._decryptPassword(self.config.encryptedPassword)
161
+ connect_args["password"] = password
162
+
163
+ self.client.connect(**connect_args)
164
+ self.connected = True
165
+ logger.info(f"Successfully connected to {self.config.host}")
166
+ return True
167
+
168
+ except Exception as e:
169
+ logger.warning(
170
+ f"connect tofailed (尝试 {self.attempt_count}/{self.config.retryCount}): {str(e)}"
171
+ )
172
+ if self.client:
173
+ self.client.close()
174
+ self.client = None
175
+
176
+ # If the maximum number of retries has been reached, return failure
177
+ if self.attempt_count >= self.config.retryCount:
178
+ logger.error(
179
+ f"connect tofailed,已达到最大重试次数 ({self.config.retryCount})"
180
+ )
181
+ self.connected = False
182
+ return False
183
+
184
+ # Retry after a while
185
+ import time
186
+
187
+ time.sleep(2) # Wait 2 seconds before retrying
188
+
189
+ return False
190
+
191
+ def _decryptPassword(self, encryptedPassword: str) -> str:
192
+ """Decrypt stored encrypted password
193
+
194
+ Args:
195
+ encryptedPassword: Encrypted password
196
+
197
+ Returns:
198
+ str: Decrypted password
199
+ """
200
+ try:
201
+ # Get the key for decrypting passwords from environment variables
202
+ password = SecurityUtils.get_env_password()
203
+ # Decrypt saved encrypted passwords
204
+ return SecurityUtils.decrypt(encryptedPassword, password)
205
+ except Exception as e:
206
+ logger.error(f"密码解密failed: {str(e)}")
207
+ # If decryption fails, it may be because the password was not encrypted; return directly.
208
+ return encryptedPassword
209
+
210
+ def _checkConnection(self) -> bool:
211
+ """Check the connection status and attempt to connect if not connected.
212
+
213
+ Returns:
214
+ bool: Whether the connection is available
215
+ """
216
+ if not self.connected or self.client is None:
217
+ return self.connect()
218
+
219
+ # Test whether the connection is still alive
220
+ try:
221
+ transport = self.client.get_transport()
222
+ if transport is None or not transport.is_active():
223
+ logger.warning("SSHconnect to已断开,尝试重新connect to")
224
+ self.disconnect()
225
+ return self.connect()
226
+ return True
227
+ except Exception as e:
228
+ logger.warning(f"检查connect to状态时出错: {str(e)}")
229
+ self.disconnect()
230
+ return self.connect()
231
+
232
+ def execBash(self, command: str) -> str:
233
+ """Execute Bash commands via SSH
234
+
235
+ Args:
236
+ command: The Bash command to execute
237
+
238
+ Returns:
239
+ str: The result of the command execution
240
+ """
241
+ if not self._checkConnection():
242
+ return "connect tofailed,无法执行命令"
243
+
244
+ command = self._preprocessCode(command, "bash")
245
+ try:
246
+ stdin, stdout, stderr = self.client.exec_command(
247
+ f"source base/bin/activate && {command}"
248
+ )
249
+
250
+ # Read command output
251
+ output = stdout.read().decode("utf-8")
252
+ error = stderr.read().decode("utf-8")
253
+
254
+ if error:
255
+ logger.warning(f"命令执行产生错误: {error}")
256
+ return f"输出: {output}\n错误: {error}"
257
+
258
+ return output
259
+ except Exception as e:
260
+ logger.error(f"执行命令时出错: {str(e)}")
261
+ return f"执行命令时出错: {str(e)}"
262
+
263
+ def execPython(
264
+ self, code: str, varDict: Optional[Dict[str, Any]] = None, **kwargs
265
+ ) -> str:
266
+ """Execute Python code via SSH, supporting session state persistence.
267
+
268
+ To obtain the execution result, assign the value to be returned at the end of the provided code
269
+ to the special variable return_value.
270
+ For example: code="a=1\nb=2\nreturn_value = a+b"
271
+
272
+ Args:
273
+ code: The Python code to execute. The last line of the code should assign the result to return_value.
274
+ varDict: Optional dictionary of variables to set in the Python environment before executing the code.
275
+ session_id: Optional session ID to maintain execution state.
276
+ session_manager: Optional session manager instance.
277
+
278
+ Returns:
279
+ str: Command execution result, typically the value of return_value or output/errors during execution.
280
+ """
281
+ # Check whether session management is used
282
+ session_id = kwargs.get("session_id")
283
+ session_manager = kwargs.get("session_manager")
284
+
285
+ if session_id and session_manager:
286
+ # Handling code with session manager
287
+
288
+ session = session_manager.get_or_create_session(session_id)
289
+ code = session_manager.prepare_session_code(code, session, varDict)
290
+ # No longer need to handle varDict separately, already handled in prepare_session_code
291
+ varDict = None
292
+ else:
293
+ # Original Code Processing
294
+ code = self._preprocessCode(code, "python")
295
+
296
+ # Generate random suffixes to avoid conflicts
297
+ random_suffix = "".join(
298
+ random.choices(string.ascii_lowercase + string.digits, k=8)
299
+ )
300
+ remoteTmpFile = f"/tmp/milkie_python_cmd_{os.getpid()}_{random_suffix}.py"
301
+ remoteTmpVarFile = None
302
+ result = "执行failed" # Default Result
303
+ localTmpFilePath = None
304
+ varDictTmpFilePath = None
305
+ try:
306
+ # Prepare list of Python script lines
307
+ script_lines = []
308
+ # Add necessary imports
309
+ script_lines.append("# -*- coding: utf-8 -*-")
310
+ script_lines.append("import json")
311
+ script_lines.append("import reprlib")
312
+ script_lines.append("return_value = None")
313
+
314
+ # Auto-configure matplotlib for Chinese font support
315
+ script_lines.append("")
316
+ script_lines.append("# 自动配置matplotlib中文字体支持")
317
+ script_lines.append("try:")
318
+ script_lines.append(" import matplotlib")
319
+ script_lines.append(" import matplotlib.pyplot as plt")
320
+ script_lines.append(" # 配置matplotlib使用中文字体")
321
+ script_lines.append(
322
+ " plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC', 'WenQuanYi Micro Hei', 'WenQuanYi Zen Hei', 'DejaVu Sans']"
323
+ )
324
+ script_lines.append(
325
+ " plt.rcParams['axes.unicode_minus'] = False # 修复负号显示"
326
+ )
327
+ script_lines.append(" # 重建字体缓存以确保新字体生效")
328
+ script_lines.append(" matplotlib.font_manager.fontManager.__init__()")
329
+ script_lines.append("except ImportError:")
330
+ script_lines.append(" pass # matplotlib未安装时忽略字体配置")
331
+ script_lines.append("")
332
+
333
+ for preImport in PreImport:
334
+ # Avoid duplicate imports
335
+ if f"import {preImport}" not in script_lines:
336
+ script_lines.append(f"import {preImport}")
337
+
338
+ # Add user code
339
+ script_lines.append(code)
340
+
341
+ # Concatenate all lines into a script string
342
+ script_content = "\n".join(script_lines)
343
+
344
+ # Create a local temporary file to store the script
345
+ with tempfile.NamedTemporaryFile(
346
+ mode="w", suffix=".py", delete=False, encoding="utf-8"
347
+ ) as localTmpFile:
348
+ localTmpFile.write(script_content)
349
+ localTmpFilePath = localTmpFile.name
350
+
351
+ logger.info(f"本地临时脚本: {localTmpFilePath}")
352
+ logger.info(f"远程临时脚本: {remoteTmpFile}")
353
+
354
+ # If a variable dictionary is provided, save it to a temporary JSON file and upload it
355
+ if varDict and isinstance(varDict, dict):
356
+ import json
357
+
358
+ # Temporary file for variable dictionary
359
+ with tempfile.NamedTemporaryFile(
360
+ mode="w", suffix=".json", delete=False, encoding="utf-8"
361
+ ) as varDictTmpFile:
362
+ json.dump(varDict, varDictTmpFile, ensure_ascii=False)
363
+ varDictTmpFilePath = varDictTmpFile.name
364
+
365
+ # Upload variable dictionary file to remote server
366
+ remoteTmpVarFile = (
367
+ f"/tmp/milkie_vars_{os.getpid()}_{random_suffix}.json"
368
+ )
369
+ logger.info(
370
+ f"将变量字典保存到临时文件并上传: {varDictTmpFilePath} -> {remoteTmpVarFile}"
371
+ )
372
+
373
+ if not self.uploadFile(varDictTmpFilePath, remoteTmpVarFile):
374
+ logger.error("上传变量字典文件failed")
375
+ raise IOError("上传变量字典文件failed")
376
+
377
+ # Modify the script to read a variable dictionary from a file
378
+ prepend_script = [
379
+ "# 从临时文件读取变量字典",
380
+ "import json",
381
+ f"with open('{remoteTmpVarFile}', 'r', encoding='utf-8') as var_file:",
382
+ " _var_dict = json.load(var_file)",
383
+ "globals().update(_var_dict)",
384
+ ]
385
+
386
+ # Insert code to read variables at the beginning of the script
387
+ script_content = "\n".join(prepend_script) + "\n" + script_content
388
+
389
+ # Rewrite the updated script
390
+ with open(localTmpFilePath, "w", encoding="utf-8") as f:
391
+ f.write(script_content)
392
+
393
+ result = self.cache_vm.getValue("python", [{"content": script_content}])
394
+ if result:
395
+ return result
396
+
397
+ # Upload script files to remote server
398
+ if not self.uploadFile(localTmpFilePath, remoteTmpFile):
399
+ logger.error("上传脚本文件failed")
400
+ raise IOError("上传脚本文件failed")
401
+
402
+ # Execute remote script
403
+ execution_output = self.execBash(f"python3 {remoteTmpFile}")
404
+ result = execution_output.strip()
405
+ self.cache_vm.setValue("python", [{"content": script_content}], result)
406
+
407
+ except Exception as e:
408
+ logger.error(f"执行Python脚本过程中出错: {str(e)}")
409
+ result = f"执行Python脚本过程中出错: {str(e)}"
410
+ finally:
411
+ # Clean up temporary files
412
+ # self._cleanupTempFile(localTmpFilePath, "local temporary script")
413
+ # self._cleanupTempFile(varDictTmpFilePath, "temporary file for local variable dictionary")
414
+
415
+ # Clean remote files
416
+ # if remoteTmpFile:
417
+ # self._cleanupRemoteTempFile(remoteTmpFile, "remote temporary script")
418
+
419
+ # if remoteTmpVarFile:
420
+ # self._cleanupRemoteTempFile(remoteTmpVarFile, "remote variable dictionary temporary file")
421
+ pass
422
+
423
+ return result
424
+
425
+ def uploadFile(self, localPath: str, remotePath: str) -> bool:
426
+ """Upload file to remote server
427
+
428
+ Args:
429
+ localPath: local file path
430
+ remotePath: remote file path
431
+
432
+ Returns:
433
+ bool: whether the upload was successful
434
+ """
435
+ if not self._checkConnection():
436
+ return False
437
+
438
+ try:
439
+ sftp = self.client.open_sftp()
440
+
441
+ # Ensure the target directory exists
442
+ remoteDir = os.path.dirname(remotePath)
443
+ if remoteDir:
444
+ try:
445
+ self.execBash(f"mkdir -p {remoteDir}")
446
+ except Exception as e:
447
+ logger.warning(f"创建目录failed: {remoteDir}: {str(e)}")
448
+
449
+ sftp.put(localPath, remotePath)
450
+ sftp.close()
451
+ logger.info(f"文件上传successful: {localPath} -> {remotePath}")
452
+ return True
453
+ except Exception as e:
454
+ logger.error(f"文件上传failed: {str(e)}")
455
+ return False
456
+
457
+ def downloadFile(self, remotePath: str, localPath: str) -> bool:
458
+ """Download a file from a remote server.
459
+
460
+ Args:
461
+ remotePath: Remote file path
462
+ localPath: Local file path
463
+
464
+ Returns:
465
+ bool: Whether the download was successful
466
+ """
467
+ if not self._checkConnection():
468
+ return False
469
+
470
+ try:
471
+ sftp = self.client.open_sftp()
472
+
473
+ # Ensure the local target directory exists
474
+ localDir = os.path.dirname(localPath)
475
+ if localDir:
476
+ os.makedirs(localDir, exist_ok=True)
477
+
478
+ sftp.get(remotePath, localPath)
479
+ sftp.close()
480
+ logger.info(f"文件下载successful: {remotePath} -> {localPath}")
481
+ return True
482
+ except Exception as e:
483
+ logger.error(f"文件下载failed: {str(e)}")
484
+ return False
485
+
486
+ def listDir(self, remotePath: str) -> List[str]:
487
+ """List files and directories in the remote directory
488
+
489
+ Args:
490
+ remotePath: Remote directory path
491
+
492
+ Returns:
493
+ List[str]: List of files and directories
494
+ """
495
+ if not self._checkConnection():
496
+ return []
497
+
498
+ try:
499
+ sftp = self.client.open_sftp()
500
+ files = sftp.listdir(remotePath)
501
+ sftp.close()
502
+ return files
503
+ except Exception as e:
504
+ logger.error(f"列出目录failed: {str(e)}")
505
+ return []
506
+
507
+ def disconnect(self) -> None:
508
+ """Disconnect SSH connection"""
509
+ if self.client:
510
+ self.client.close()
511
+ self.client = None
512
+ self.connected = False
513
+ logger.info(f"已断开与 {self.config.host} 的connect to")
514
+
515
+ def _preprocessCode(self, code: str, type: str) -> str:
516
+ """Preprocessing code
517
+
518
+ Args:
519
+ code: The code to preprocess
520
+ """
521
+ startFlag = f"```{type}"
522
+ endFlag = "```"
523
+ idxStart = code.find(startFlag)
524
+ if idxStart == -1:
525
+ return code
526
+
527
+ idxEnd = code.find(endFlag, idxStart + len(startFlag))
528
+ if idxEnd == -1:
529
+ return code[idxStart + len(startFlag) :]
530
+ return code[idxStart + len(startFlag) : idxEnd]
531
+
532
+ def _cleanupTempFile(self, filepath: Optional[str], description: str) -> None:
533
+ """Clean up local temporary files
534
+
535
+ Args:
536
+ filepath: File path
537
+ description: File description, used for logging
538
+ """
539
+ if filepath and os.path.exists(filepath):
540
+ try:
541
+ os.remove(filepath)
542
+ logger.info(f"已删除{description}: {filepath}")
543
+ except OSError as e:
544
+ logger.warning(f"删除{description}failed: {filepath}, Error: {e}")
545
+
546
+ def _cleanupRemoteTempFile(self, remotepath: str, description: str) -> None:
547
+ """Clean up remote temporary files
548
+
549
+ Args:
550
+ remotepath: Remote file path
551
+ description: File description, used for logging
552
+ """
553
+ cleanup_result = self.execBash(f"rm -f {remotepath}")
554
+ if any(
555
+ err in cleanup_result for err in ["错误", "Error", "No such file", "failed"]
556
+ ):
557
+ logger.warning(
558
+ f"清理{description}可能failed: {remotepath}, 清理命令输出: {cleanup_result}"
559
+ )
560
+ else:
561
+ logger.info(f"已尝试清理{description}: {remotepath}")
562
+
563
+ def __enter__(self):
564
+ """Support context management with the 'with' statement"""
565
+ self.connect()
566
+ return self
567
+
568
+ def __exit__(self, exc_type, exc_val, exc_tb):
569
+ """Close the connection when exiting the context"""
570
+ self.disconnect()
571
+
572
+
573
+ class VMFactory:
574
+ """Virtual machine factory class, used to create VM instances of different types"""
575
+
576
+ cache_vm = GlobalCacheKVCenter.getCacheMgr("data/cache", category="vm")
577
+
578
+ @staticmethod
579
+ def createVM(config: VMConfig) -> VM:
580
+ """Create the corresponding VM instance according to the configuration.
581
+
582
+ Args:
583
+ config: VM configuration information
584
+
585
+ Returns:
586
+ VM: The created VM instance
587
+ """
588
+ if config.connection_type == VMConnectionType.SSH:
589
+ return VMSSH(config, VMFactory.cache_vm)
590
+ elif config.connection_type == VMConnectionType.DOCKER:
591
+ # Here you can implement VMs of Docker type
592
+ raise NotImplementedError("Docker类型的VM尚未实现")
593
+ else:
594
+ raise ValueError(f"不支持的VMconnect to类型: {config.connectionType}")
595
+
596
+
597
+ if __name__ == "__main__":
598
+ encryptedPassword = SecurityUtils.encrypt(
599
+ "password", SecurityUtils.get_env_password()
600
+ )
601
+ print(encryptedPassword)
602
+ vmConfig = VMConfig(
603
+ host="localhost",
604
+ port=2222,
605
+ username="myuser",
606
+ encryptedPassword=encryptedPassword,
607
+ connectionType=VMConnectionType.SSH,
608
+ )
609
+ vm = VMFactory.createVM(vmConfig)
610
+ print(vm.execPython("import random; print(random.randint(1, 10))"))
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Dolphin SDK - 开发者 SDK(开发框架)
4
+
5
+ 职责:
6
+ - Agent 开发框架(DolphinAgent)
7
+ - Skill 扩展开发(GlobalSkills)
8
+ - 运行时环境(Env)
9
+ - 开发者友好的 API 封装
10
+
11
+ 依赖规则:
12
+ - dolphin.sdk → 依赖 dolphin.lib, dolphin.core
13
+ """
14
+
15
+ # Agent
16
+ from dolphin.sdk.agent.dolphin_agent import DolphinAgent
17
+ from dolphin.sdk.agent.agent_factory import AgentFactory
18
+
19
+ # Runtime
20
+ from dolphin.sdk.runtime.env import Env
21
+
22
+ # Skill
23
+ from dolphin.sdk.skill.global_skills import GlobalSkills
24
+ from dolphin.sdk.skill.traditional_toolkit import TriditionalToolkit
25
+
26
+ # 重新导出 core/lib 组件以便捷使用
27
+ from dolphin.core import (
28
+ BaseAgent,
29
+ AgentState,
30
+ Context,
31
+ Skillset,
32
+ Skillkit,
33
+ SkillFunction,
34
+ )
35
+
36
+ from dolphin.lib import (
37
+ Ontology,
38
+ OntologyManager,
39
+ )
40
+
41
+ __all__ = [
42
+ # Agent
43
+ "DolphinAgent",
44
+ "AgentFactory",
45
+ # Runtime
46
+ "Env",
47
+ # Skill
48
+ "GlobalSkills",
49
+ "TriditionalToolkit",
50
+ # Re-exported from core
51
+ "BaseAgent",
52
+ "AgentState",
53
+ "Context",
54
+ "Skillset",
55
+ "Skillkit",
56
+ "SkillFunction",
57
+ # Re-exported from lib
58
+ "Ontology",
59
+ "OntologyManager",
60
+ ]
@@ -0,0 +1,12 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Agent 模块 - Agent 开发框架"""
3
+
4
+ from dolphin.sdk.agent.dolphin_agent import DolphinAgent
5
+ from dolphin.sdk.agent.agent_factory import AgentFactory
6
+ from dolphin.core.agent.agent_state import PauseType
7
+
8
+ __all__ = [
9
+ "DolphinAgent",
10
+ "AgentFactory",
11
+ "PauseType",
12
+ ]