camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__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 (224) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/_types.py +6 -2
  3. camel/agents/_utils.py +38 -0
  4. camel/agents/chat_agent.py +4014 -410
  5. camel/agents/mcp_agent.py +30 -27
  6. camel/agents/repo_agent.py +2 -1
  7. camel/benchmarks/browsecomp.py +6 -6
  8. camel/configs/__init__.py +15 -0
  9. camel/configs/aihubmix_config.py +88 -0
  10. camel/configs/amd_config.py +70 -0
  11. camel/configs/cometapi_config.py +104 -0
  12. camel/configs/minimax_config.py +93 -0
  13. camel/configs/nebius_config.py +103 -0
  14. camel/configs/vllm_config.py +2 -0
  15. camel/data_collectors/alpaca_collector.py +15 -6
  16. camel/datagen/self_improving_cot.py +1 -1
  17. camel/datasets/base_generator.py +39 -10
  18. camel/environments/__init__.py +12 -0
  19. camel/environments/rlcards_env.py +860 -0
  20. camel/environments/single_step.py +28 -3
  21. camel/environments/tic_tac_toe.py +1 -1
  22. camel/interpreters/__init__.py +2 -0
  23. camel/interpreters/docker/Dockerfile +4 -16
  24. camel/interpreters/docker_interpreter.py +3 -2
  25. camel/interpreters/e2b_interpreter.py +34 -1
  26. camel/interpreters/internal_python_interpreter.py +51 -2
  27. camel/interpreters/microsandbox_interpreter.py +395 -0
  28. camel/loaders/__init__.py +11 -2
  29. camel/loaders/base_loader.py +85 -0
  30. camel/loaders/chunkr_reader.py +9 -0
  31. camel/loaders/firecrawl_reader.py +4 -4
  32. camel/logger.py +1 -1
  33. camel/memories/agent_memories.py +84 -1
  34. camel/memories/base.py +34 -0
  35. camel/memories/blocks/chat_history_block.py +122 -4
  36. camel/memories/blocks/vectordb_block.py +8 -1
  37. camel/memories/context_creators/score_based.py +29 -237
  38. camel/memories/records.py +88 -8
  39. camel/messages/base.py +166 -40
  40. camel/messages/func_message.py +32 -5
  41. camel/models/__init__.py +10 -0
  42. camel/models/aihubmix_model.py +83 -0
  43. camel/models/aiml_model.py +1 -16
  44. camel/models/amd_model.py +101 -0
  45. camel/models/anthropic_model.py +117 -18
  46. camel/models/aws_bedrock_model.py +2 -33
  47. camel/models/azure_openai_model.py +205 -91
  48. camel/models/base_audio_model.py +3 -1
  49. camel/models/base_model.py +189 -24
  50. camel/models/cohere_model.py +5 -17
  51. camel/models/cometapi_model.py +83 -0
  52. camel/models/crynux_model.py +1 -16
  53. camel/models/deepseek_model.py +6 -16
  54. camel/models/fish_audio_model.py +6 -0
  55. camel/models/gemini_model.py +71 -20
  56. camel/models/groq_model.py +1 -17
  57. camel/models/internlm_model.py +1 -16
  58. camel/models/litellm_model.py +49 -32
  59. camel/models/lmstudio_model.py +1 -17
  60. camel/models/minimax_model.py +83 -0
  61. camel/models/mistral_model.py +1 -16
  62. camel/models/model_factory.py +27 -1
  63. camel/models/model_manager.py +24 -6
  64. camel/models/modelscope_model.py +1 -16
  65. camel/models/moonshot_model.py +185 -19
  66. camel/models/nebius_model.py +83 -0
  67. camel/models/nemotron_model.py +0 -5
  68. camel/models/netmind_model.py +1 -16
  69. camel/models/novita_model.py +1 -16
  70. camel/models/nvidia_model.py +1 -16
  71. camel/models/ollama_model.py +4 -19
  72. camel/models/openai_compatible_model.py +171 -46
  73. camel/models/openai_model.py +205 -77
  74. camel/models/openrouter_model.py +1 -17
  75. camel/models/ppio_model.py +1 -16
  76. camel/models/qianfan_model.py +1 -16
  77. camel/models/qwen_model.py +1 -16
  78. camel/models/reka_model.py +1 -16
  79. camel/models/samba_model.py +34 -47
  80. camel/models/sglang_model.py +64 -31
  81. camel/models/siliconflow_model.py +1 -16
  82. camel/models/stub_model.py +0 -4
  83. camel/models/togetherai_model.py +1 -16
  84. camel/models/vllm_model.py +1 -16
  85. camel/models/volcano_model.py +0 -17
  86. camel/models/watsonx_model.py +1 -16
  87. camel/models/yi_model.py +1 -16
  88. camel/models/zhipuai_model.py +60 -16
  89. camel/parsers/__init__.py +18 -0
  90. camel/parsers/mcp_tool_call_parser.py +176 -0
  91. camel/retrievers/auto_retriever.py +1 -0
  92. camel/runtimes/configs.py +11 -11
  93. camel/runtimes/daytona_runtime.py +15 -16
  94. camel/runtimes/docker_runtime.py +6 -6
  95. camel/runtimes/remote_http_runtime.py +5 -5
  96. camel/services/agent_openapi_server.py +380 -0
  97. camel/societies/__init__.py +2 -0
  98. camel/societies/role_playing.py +26 -28
  99. camel/societies/workforce/__init__.py +2 -0
  100. camel/societies/workforce/events.py +122 -0
  101. camel/societies/workforce/prompts.py +249 -38
  102. camel/societies/workforce/role_playing_worker.py +82 -20
  103. camel/societies/workforce/single_agent_worker.py +634 -34
  104. camel/societies/workforce/structured_output_handler.py +512 -0
  105. camel/societies/workforce/task_channel.py +169 -23
  106. camel/societies/workforce/utils.py +176 -9
  107. camel/societies/workforce/worker.py +77 -23
  108. camel/societies/workforce/workflow_memory_manager.py +772 -0
  109. camel/societies/workforce/workforce.py +3168 -478
  110. camel/societies/workforce/workforce_callback.py +74 -0
  111. camel/societies/workforce/workforce_logger.py +203 -175
  112. camel/societies/workforce/workforce_metrics.py +33 -0
  113. camel/storages/__init__.py +4 -0
  114. camel/storages/key_value_storages/json.py +15 -2
  115. camel/storages/key_value_storages/mem0_cloud.py +48 -47
  116. camel/storages/object_storages/google_cloud.py +1 -1
  117. camel/storages/vectordb_storages/__init__.py +6 -0
  118. camel/storages/vectordb_storages/chroma.py +731 -0
  119. camel/storages/vectordb_storages/oceanbase.py +13 -13
  120. camel/storages/vectordb_storages/pgvector.py +349 -0
  121. camel/storages/vectordb_storages/qdrant.py +3 -3
  122. camel/storages/vectordb_storages/surreal.py +365 -0
  123. camel/storages/vectordb_storages/tidb.py +8 -6
  124. camel/tasks/task.py +244 -27
  125. camel/toolkits/__init__.py +46 -8
  126. camel/toolkits/aci_toolkit.py +64 -19
  127. camel/toolkits/arxiv_toolkit.py +6 -6
  128. camel/toolkits/base.py +63 -5
  129. camel/toolkits/code_execution.py +28 -1
  130. camel/toolkits/context_summarizer_toolkit.py +684 -0
  131. camel/toolkits/craw4ai_toolkit.py +93 -0
  132. camel/toolkits/dappier_toolkit.py +10 -6
  133. camel/toolkits/dingtalk.py +1135 -0
  134. camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
  135. camel/toolkits/excel_toolkit.py +901 -67
  136. camel/toolkits/file_toolkit.py +1402 -0
  137. camel/toolkits/function_tool.py +30 -6
  138. camel/toolkits/github_toolkit.py +107 -20
  139. camel/toolkits/gmail_toolkit.py +1839 -0
  140. camel/toolkits/google_calendar_toolkit.py +38 -4
  141. camel/toolkits/google_drive_mcp_toolkit.py +54 -0
  142. camel/toolkits/human_toolkit.py +34 -10
  143. camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
  144. camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
  145. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
  146. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
  147. camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
  148. camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +3749 -0
  149. camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
  150. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
  151. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
  152. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
  153. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -0
  154. camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
  155. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  156. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
  157. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  158. camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +130 -0
  159. camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
  160. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
  161. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -0
  162. camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
  163. camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
  164. camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
  165. camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
  166. camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
  167. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
  168. camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
  169. camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
  170. camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
  171. camel/toolkits/image_generation_toolkit.py +390 -0
  172. camel/toolkits/jina_reranker_toolkit.py +3 -4
  173. camel/toolkits/klavis_toolkit.py +5 -1
  174. camel/toolkits/markitdown_toolkit.py +104 -0
  175. camel/toolkits/math_toolkit.py +64 -10
  176. camel/toolkits/mcp_toolkit.py +370 -45
  177. camel/toolkits/memory_toolkit.py +5 -1
  178. camel/toolkits/message_agent_toolkit.py +608 -0
  179. camel/toolkits/message_integration.py +724 -0
  180. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  181. camel/toolkits/note_taking_toolkit.py +277 -0
  182. camel/toolkits/notion_mcp_toolkit.py +224 -0
  183. camel/toolkits/openbb_toolkit.py +5 -1
  184. camel/toolkits/origene_mcp_toolkit.py +56 -0
  185. camel/toolkits/playwright_mcp_toolkit.py +12 -31
  186. camel/toolkits/pptx_toolkit.py +25 -12
  187. camel/toolkits/resend_toolkit.py +168 -0
  188. camel/toolkits/screenshot_toolkit.py +213 -0
  189. camel/toolkits/search_toolkit.py +437 -142
  190. camel/toolkits/slack_toolkit.py +104 -50
  191. camel/toolkits/sympy_toolkit.py +1 -1
  192. camel/toolkits/task_planning_toolkit.py +3 -3
  193. camel/toolkits/terminal_toolkit/__init__.py +18 -0
  194. camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
  195. camel/toolkits/terminal_toolkit/utils.py +532 -0
  196. camel/toolkits/thinking_toolkit.py +1 -1
  197. camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
  198. camel/toolkits/video_analysis_toolkit.py +106 -26
  199. camel/toolkits/video_download_toolkit.py +17 -14
  200. camel/toolkits/web_deploy_toolkit.py +1219 -0
  201. camel/toolkits/wechat_official_toolkit.py +483 -0
  202. camel/toolkits/zapier_toolkit.py +5 -1
  203. camel/types/__init__.py +2 -2
  204. camel/types/agents/tool_calling_record.py +4 -1
  205. camel/types/enums.py +316 -40
  206. camel/types/openai_types.py +2 -2
  207. camel/types/unified_model_type.py +31 -4
  208. camel/utils/commons.py +36 -5
  209. camel/utils/constants.py +3 -0
  210. camel/utils/context_utils.py +1003 -0
  211. camel/utils/mcp.py +138 -4
  212. camel/utils/mcp_client.py +45 -1
  213. camel/utils/message_summarizer.py +148 -0
  214. camel/utils/token_counting.py +43 -20
  215. camel/utils/tool_result.py +44 -0
  216. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
  217. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
  218. camel/loaders/pandas_reader.py +0 -368
  219. camel/toolkits/dalle_toolkit.py +0 -175
  220. camel/toolkits/file_write_toolkit.py +0 -444
  221. camel/toolkits/openai_agent_toolkit.py +0 -135
  222. camel/toolkits/terminal_toolkit.py +0 -1037
  223. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
  224. {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,444 +0,0 @@
1
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an "AS IS" BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
- import re
15
- from datetime import datetime
16
- from pathlib import Path
17
- from typing import List, Optional, Union
18
-
19
- from camel.logger import get_logger
20
- from camel.toolkits.base import BaseToolkit
21
- from camel.toolkits.function_tool import FunctionTool
22
- from camel.utils import MCPServer, dependencies_required
23
-
24
- logger = get_logger(__name__)
25
-
26
- # Default format when no extension is provided
27
- DEFAULT_FORMAT = '.md'
28
-
29
-
30
- @MCPServer()
31
- class FileWriteToolkit(BaseToolkit):
32
- r"""A toolkit for creating, writing, and modifying text in files.
33
-
34
- This class provides cross-platform (macOS, Linux, Windows) support for
35
- writing to various file formats (Markdown, DOCX, PDF, and plaintext),
36
- replacing text in existing files, automatic backups, custom encoding,
37
- and enhanced formatting options for specialized formats.
38
- """
39
-
40
- def __init__(
41
- self,
42
- output_dir: str = "./",
43
- timeout: Optional[float] = None,
44
- default_encoding: str = "utf-8",
45
- backup_enabled: bool = True,
46
- ) -> None:
47
- r"""Initialize the FileWriteToolkit.
48
-
49
- Args:
50
- output_dir (str): The default directory for output files.
51
- Defaults to the current working directory.
52
- timeout (Optional[float]): The timeout for the toolkit.
53
- (default: :obj: `None`)
54
- default_encoding (str): Default character encoding for text
55
- operations. (default: :obj: `utf-8`)
56
- backup_enabled (bool): Whether to create backups of existing files
57
- before overwriting. (default: :obj: `True`)
58
- """
59
- super().__init__(timeout=timeout)
60
- self.output_dir = Path(output_dir).resolve()
61
- self.output_dir.mkdir(parents=True, exist_ok=True)
62
- self.default_encoding = default_encoding
63
- self.backup_enabled = backup_enabled
64
- logger.info(
65
- f"FileWriteToolkit initialized with output directory"
66
- f": {self.output_dir}, encoding: {default_encoding}"
67
- )
68
-
69
- def _resolve_filepath(self, file_path: str) -> Path:
70
- r"""Convert the given string path to a Path object.
71
-
72
- If the provided path is not absolute, it is made relative to the
73
- default output directory. The filename part is sanitized to replace
74
- spaces and special characters with underscores, ensuring safe usage
75
- in downstream processing.
76
-
77
- Args:
78
- file_path (str): The file path to resolve.
79
-
80
- Returns:
81
- Path: A fully resolved (absolute) and sanitized Path object.
82
- """
83
- path_obj = Path(file_path)
84
- if not path_obj.is_absolute():
85
- path_obj = self.output_dir / path_obj
86
-
87
- sanitized_filename = self._sanitize_filename(path_obj.name)
88
- path_obj = path_obj.parent / sanitized_filename
89
- return path_obj.resolve()
90
-
91
- def _write_text_file(
92
- self, file_path: Path, content: str, encoding: str = "utf-8"
93
- ) -> None:
94
- r"""Write text content to a plaintext file.
95
-
96
- Args:
97
- file_path (Path): The target file path.
98
- content (str): The text content to write.
99
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
100
- """
101
- with file_path.open("w", encoding=encoding) as f:
102
- f.write(content)
103
- logger.debug(f"Wrote text to {file_path} with {encoding} encoding")
104
-
105
- def _create_backup(self, file_path: Path) -> None:
106
- r"""Create a backup of the file if it exists and backup is enabled.
107
-
108
- Args:
109
- file_path (Path): Path to the file to backup.
110
- """
111
- import shutil
112
-
113
- if not self.backup_enabled or not file_path.exists():
114
- return
115
-
116
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
117
- backup_path = file_path.parent / f"{file_path.name}.{timestamp}.bak"
118
- shutil.copy2(file_path, backup_path)
119
- logger.info(f"Created backup at {backup_path}")
120
-
121
- def _write_docx_file(self, file_path: Path, content: str) -> None:
122
- r"""Write text content to a DOCX file with default formatting.
123
-
124
- Args:
125
- file_path (Path): The target file path.
126
- content (str): The text content to write.
127
- """
128
- import docx
129
-
130
- # Use default formatting values
131
- font_name = 'Calibri'
132
- font_size = 11
133
- line_spacing = 1.0
134
-
135
- document = docx.Document()
136
- style = document.styles['Normal']
137
- style.font.name = font_name
138
- style.font.size = docx.shared.Pt(font_size)
139
- style.paragraph_format.line_spacing = line_spacing
140
-
141
- # Split content into paragraphs and add them
142
- for para_text in content.split('\n'):
143
- para = document.add_paragraph(para_text)
144
- para.style = style
145
-
146
- document.save(str(file_path))
147
- logger.debug(f"Wrote DOCX to {file_path} with default formatting")
148
-
149
- @dependencies_required('pylatex', 'fpdf')
150
- def _write_pdf_file(
151
- self, file_path: Path, content: str, use_latex: bool = False
152
- ) -> None:
153
- r"""Write text content to a PDF file with default formatting.
154
-
155
- Args:
156
- file_path (Path): The target file path.
157
- content (str): The text content to write.
158
- use_latex (bool): Whether to use LaTeX for rendering. (requires
159
- LaTeX toolchain). If False, uses FPDF for simpler PDF
160
- generation. (default: :obj: `False`)
161
-
162
- Raises:
163
- RuntimeError: If the 'pylatex' or 'fpdf' library is not installed
164
- when use_latex=True.
165
- """
166
- if use_latex:
167
- from pylatex import (
168
- Command,
169
- Document,
170
- Math,
171
- Section,
172
- )
173
- from pylatex.utils import (
174
- NoEscape,
175
- )
176
-
177
- doc = Document(documentclass="article")
178
- doc.packages.append(Command('usepackage', 'amsmath'))
179
-
180
- with doc.create(Section('Generated Content')):
181
- for line in content.split('\n'):
182
- # Remove leading whitespace
183
- stripped_line = line.strip()
184
- # Check if the line is intended as a standalone math
185
- # expression
186
- if (
187
- stripped_line.startswith('$')
188
- and stripped_line.endswith('$')
189
- and len(stripped_line) > 1
190
- ):
191
- # Extract content between the '$' delimiters
192
- math_data = stripped_line[1:-1]
193
- doc.append(Math(data=math_data))
194
- else:
195
- doc.append(NoEscape(line))
196
- doc.append(NoEscape(r'\par'))
197
-
198
- doc.generate_pdf(str(file_path), clean_tex=False)
199
-
200
- logger.info(f"Wrote PDF (with LaTeX) to {file_path}")
201
- else:
202
- from fpdf import FPDF
203
-
204
- # Use default formatting values
205
- font_family = 'Arial'
206
- font_size = 12
207
- font_style = ''
208
- line_height = 10
209
- margin = 10
210
-
211
- pdf = FPDF()
212
- pdf.set_margins(margin, margin, margin)
213
-
214
- pdf.add_page()
215
- pdf.set_font(font_family, style=font_style, size=font_size)
216
-
217
- # Split content into paragraphs and add them
218
- for para in content.split('\n'):
219
- if para.strip(): # Skip empty paragraphs
220
- pdf.multi_cell(0, line_height, para)
221
- else:
222
- pdf.ln(line_height) # Add empty line
223
-
224
- pdf.output(str(file_path))
225
- logger.debug(f"Wrote PDF to {file_path} with custom formatting")
226
-
227
- def _write_csv_file(
228
- self,
229
- file_path: Path,
230
- content: Union[str, List[List]],
231
- encoding: str = "utf-8",
232
- ) -> None:
233
- r"""Write CSV content to a file.
234
-
235
- Args:
236
- file_path (Path): The target file path.
237
- content (Union[str, List[List]]): The CSV content as a string or
238
- list of lists.
239
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
240
- """
241
- import csv
242
-
243
- with file_path.open("w", encoding=encoding, newline='') as f:
244
- if isinstance(content, str):
245
- f.write(content)
246
- else:
247
- writer = csv.writer(f)
248
- writer.writerows(content)
249
- logger.debug(f"Wrote CSV to {file_path} with {encoding} encoding")
250
-
251
- def _write_json_file(
252
- self,
253
- file_path: Path,
254
- content: str,
255
- encoding: str = "utf-8",
256
- ) -> None:
257
- r"""Write JSON content to a file.
258
-
259
- Args:
260
- file_path (Path): The target file path.
261
- content (str): The JSON content as a string.
262
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
263
- """
264
- import json
265
-
266
- with file_path.open("w", encoding=encoding) as f:
267
- if isinstance(content, str):
268
- try:
269
- # Try parsing as JSON string first
270
- data = json.loads(content)
271
- json.dump(data, f, ensure_ascii=False)
272
- except json.JSONDecodeError:
273
- # If not valid JSON string, write as is
274
- f.write(content)
275
- else:
276
- # If not string, dump as JSON
277
- json.dump(content, f, ensure_ascii=False)
278
- logger.debug(f"Wrote JSON to {file_path} with {encoding} encoding")
279
-
280
- def _write_yaml_file(
281
- self,
282
- file_path: Path,
283
- content: str,
284
- encoding: str = "utf-8",
285
- ) -> None:
286
- r"""Write YAML content to a file.
287
-
288
- Args:
289
- file_path (Path): The target file path.
290
- content (str): The YAML content as a string.
291
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
292
- """
293
- with file_path.open("w", encoding=encoding) as f:
294
- f.write(content)
295
- logger.debug(f"Wrote YAML to {file_path} with {encoding} encoding")
296
-
297
- def _write_html_file(
298
- self, file_path: Path, content: str, encoding: str = "utf-8"
299
- ) -> None:
300
- r"""Write text content to an HTML file.
301
-
302
- Args:
303
- file_path (Path): The target file path.
304
- content (str): The HTML content to write.
305
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
306
- """
307
- with file_path.open("w", encoding=encoding) as f:
308
- f.write(content)
309
- logger.debug(f"Wrote HTML to {file_path} with {encoding} encoding")
310
-
311
- def _write_markdown_file(
312
- self, file_path: Path, content: str, encoding: str = "utf-8"
313
- ) -> None:
314
- r"""Write text content to a Markdown file.
315
-
316
- Args:
317
- file_path (Path): The target file path.
318
- content (str): The Markdown content to write.
319
- encoding (str): Character encoding to use. (default: :obj: `utf-8`)
320
- """
321
- with file_path.open("w", encoding=encoding) as f:
322
- f.write(content)
323
- logger.debug(f"Wrote Markdown to {file_path} with {encoding} encoding")
324
-
325
- def write_to_file(
326
- self,
327
- content: Union[str, List[List[str]]],
328
- filename: str,
329
- encoding: Optional[str] = None,
330
- use_latex: bool = False,
331
- ) -> str:
332
- r"""Write the given content to a file.
333
-
334
- If the file exists, it will be overwritten. Supports multiple formats:
335
- Markdown (.md, .markdown, default), Plaintext (.txt), CSV (.csv),
336
- DOC/DOCX (.doc, .docx), PDF (.pdf), JSON (.json), YAML (.yml, .yaml),
337
- and HTML (.html, .htm).
338
-
339
- Args:
340
- content (Union[str, List[List[str]]]): The content to write to the
341
- file. Content format varies by file type:
342
- - Text formats (txt, md, html, yaml): string
343
- - CSV: string or list of lists
344
- - JSON: string or serializable object
345
- filename (str): The name or path of the file. If a relative path is
346
- supplied, it is resolved to self.output_dir.
347
- encoding (Optional[str]): The character encoding to use. (default:
348
- :obj: `None`)
349
- use_latex (bool): For PDF files, whether to use LaTeX rendering
350
- (True) or simple FPDF rendering (False). (default: :obj:
351
- `False`)
352
-
353
- Returns:
354
- str: A message indicating success or error details.
355
- """
356
- file_path = self._resolve_filepath(filename)
357
- file_path.parent.mkdir(parents=True, exist_ok=True)
358
-
359
- # Create backup if file exists
360
- self._create_backup(file_path)
361
-
362
- extension = file_path.suffix.lower()
363
-
364
- # If no extension is provided, use the default format
365
- if extension == "":
366
- file_path = file_path.with_suffix(DEFAULT_FORMAT)
367
- extension = DEFAULT_FORMAT
368
-
369
- try:
370
- # Get encoding or use default
371
- file_encoding = encoding or self.default_encoding
372
-
373
- if extension in [".doc", ".docx"]:
374
- self._write_docx_file(file_path, str(content))
375
- elif extension == ".pdf":
376
- self._write_pdf_file(
377
- file_path, str(content), use_latex=use_latex
378
- )
379
- elif extension == ".csv":
380
- self._write_csv_file(
381
- file_path, content, encoding=file_encoding
382
- )
383
- elif extension == ".json":
384
- self._write_json_file(
385
- file_path,
386
- content, # type: ignore[arg-type]
387
- encoding=file_encoding,
388
- )
389
- elif extension in [".yml", ".yaml"]:
390
- self._write_yaml_file(
391
- file_path, str(content), encoding=file_encoding
392
- )
393
- elif extension in [".html", ".htm"]:
394
- self._write_html_file(
395
- file_path, str(content), encoding=file_encoding
396
- )
397
- elif extension in [".md", ".markdown"]:
398
- self._write_markdown_file(
399
- file_path, str(content), encoding=file_encoding
400
- )
401
- else:
402
- # Fallback to simple text writing for unknown or .txt
403
- # extensions
404
- self._write_text_file(
405
- file_path, str(content), encoding=file_encoding
406
- )
407
-
408
- msg = f"Content successfully written to file: {file_path}"
409
- logger.info(msg)
410
- return msg
411
- except Exception as e:
412
- error_msg = (
413
- f"Error occurred while writing to file {file_path}: {e}"
414
- )
415
- logger.error(error_msg)
416
- return error_msg
417
-
418
- def get_tools(self) -> List[FunctionTool]:
419
- r"""Return a list of FunctionTool objects representing the functions
420
- in the toolkit.
421
-
422
- Returns:
423
- List[FunctionTool]: A list of FunctionTool objects representing
424
- the available functions in this toolkit.
425
- """
426
- return [
427
- FunctionTool(self.write_to_file),
428
- ]
429
-
430
- def _sanitize_filename(self, filename: str) -> str:
431
- r"""Sanitize a filename by replacing any character that is not
432
- alphanumeric, a dot (.), hyphen (-), or underscore (_) with an
433
- underscore (_).
434
-
435
- Args:
436
- filename (str): The original filename which may contain spaces or
437
- special characters.
438
-
439
- Returns:
440
- str: The sanitized filename with disallowed characters replaced by
441
- underscores.
442
- """
443
- safe = re.sub(r'[^\w\-.]', '_', filename)
444
- return safe
@@ -1,135 +0,0 @@
1
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
- # Licensed under the Apache License, Version 2.0 (the "License");
3
- # you may not use this file except in compliance with the License.
4
- # You may obtain a copy of the License at
5
- #
6
- # http://www.apache.org/licenses/LICENSE-2.0
7
- #
8
- # Unless required by applicable law or agreed to in writing, software
9
- # distributed under the License is distributed on an "AS IS" BASIS,
10
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- # See the License for the specific language governing permissions and
12
- # limitations under the License.
13
- # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
-
15
- import os
16
- from typing import List, Optional
17
-
18
- from openai import OpenAI
19
-
20
- from camel.logger import get_logger
21
- from camel.models import BaseModelBackend, ModelFactory
22
- from camel.toolkits.base import BaseToolkit
23
- from camel.toolkits.function_tool import FunctionTool
24
- from camel.types import ModelPlatformType, ModelType
25
- from camel.utils import api_keys_required
26
-
27
- logger = get_logger(__name__)
28
-
29
-
30
- class OpenAIAgentToolkit(BaseToolkit):
31
- r"""Toolkit for accessing OpenAI's agent tools including web search and
32
- file search.
33
-
34
- Provides access to OpenAI's web search and file search capabilities
35
- through the Responses API, allowing agents to retrieve information from
36
- the web and search through uploaded files.
37
- """
38
-
39
- @api_keys_required(
40
- [
41
- (None, "OPENAI_API_KEY"),
42
- ]
43
- )
44
- def __init__(
45
- self,
46
- model: Optional[BaseModelBackend] = None,
47
- api_key: Optional[str] = None,
48
- timeout: Optional[float] = None,
49
- ) -> None:
50
- r"""Initialize the OpenAI agent toolkit.
51
-
52
- Args:
53
- model (BaseModelBackend): The OpenAI model to use for responses.
54
- If None, defaults to gpt-4o-mini. (default: :obj:`None`)
55
- api_key (str): OpenAI API key. If not provided, will attempt to
56
- use OPENAI_API_KEY environment variable. (default: :obj:`None`)
57
- timeout (Optional[float]): The timeout value for API requests
58
- in seconds. If None, no timeout is applied.
59
- (default: :obj:`None`)
60
- """
61
- super().__init__(timeout=timeout)
62
- self.api_key = api_key or os.getenv("OPENAI_API_KEY")
63
- self.client = OpenAI(api_key=self.api_key)
64
- self.model = model or ModelFactory.create(
65
- model_platform=ModelPlatformType.OPENAI,
66
- model_type=ModelType.GPT_4O_MINI,
67
- )
68
-
69
- def web_search(self, query: str) -> str:
70
- r"""Perform a web search using OpenAI's web search tool.
71
-
72
- Args:
73
- query (str): The search query.
74
-
75
- Returns:
76
- str: The search result or error message.
77
- """
78
- try:
79
- response = self.client.responses.create(
80
- model=str(self.model.model_type),
81
- tools=[{"type": "web_search_preview"}],
82
- input=query,
83
- )
84
- return response.output_text
85
-
86
- except Exception as e:
87
- logger.error(f"Web search failed: {e!s}")
88
- return f"Web search failed: {e!s}"
89
-
90
- def file_search(
91
- self,
92
- query: str,
93
- vector_store_id: str,
94
- ) -> str:
95
- r"""Search through files using OpenAI's file search tool.
96
-
97
- Args:
98
- query (str): The search query.
99
- vector_store_id (str): The vector store ID to search in.
100
-
101
- Returns:
102
- str: The search result or error message.
103
- """
104
- if not vector_store_id.strip():
105
- logger.error("Empty vector store ID provided.")
106
- return "Empty vector store ID provided, it cannot be empty."
107
-
108
- try:
109
- response = self.client.responses.create(
110
- model=str(self.model.model_type),
111
- tools=[
112
- {
113
- "type": "file_search",
114
- "vector_store_ids": [vector_store_id],
115
- }
116
- ],
117
- input=query,
118
- )
119
- return response.output_text
120
-
121
- except Exception as e:
122
- logger.error(f"File search failed: {e!s}")
123
- return f"File search failed: {e!s}"
124
-
125
- def get_tools(self) -> List[FunctionTool]:
126
- r"""Retrieve available toolkit functions as FunctionTool objects.
127
-
128
- Returns:
129
- List[FunctionTool]: Collection of FunctionTool objects representing
130
- the available search functions in this toolkit.
131
- """
132
- return [
133
- FunctionTool(self.web_search),
134
- FunctionTool(self.file_search),
135
- ]