camel-ai 0.2.62__py3-none-any.whl → 0.2.65__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.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (59) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +95 -24
  3. camel/agents/mcp_agent.py +5 -1
  4. camel/benchmarks/mock_website/README.md +96 -0
  5. camel/benchmarks/mock_website/mock_web.py +299 -0
  6. camel/benchmarks/mock_website/requirements.txt +3 -0
  7. camel/benchmarks/mock_website/shopping_mall/app.py +465 -0
  8. camel/benchmarks/mock_website/task.json +104 -0
  9. camel/configs/__init__.py +3 -0
  10. camel/configs/crynux_config.py +94 -0
  11. camel/datasets/models.py +1 -1
  12. camel/datasets/static_dataset.py +6 -0
  13. camel/interpreters/base.py +14 -1
  14. camel/interpreters/docker/Dockerfile +63 -7
  15. camel/interpreters/docker_interpreter.py +65 -7
  16. camel/interpreters/e2b_interpreter.py +23 -8
  17. camel/interpreters/internal_python_interpreter.py +30 -2
  18. camel/interpreters/ipython_interpreter.py +21 -3
  19. camel/interpreters/subprocess_interpreter.py +34 -2
  20. camel/memories/records.py +5 -3
  21. camel/models/__init__.py +2 -0
  22. camel/models/azure_openai_model.py +101 -25
  23. camel/models/cohere_model.py +65 -0
  24. camel/models/crynux_model.py +94 -0
  25. camel/models/deepseek_model.py +43 -1
  26. camel/models/gemini_model.py +50 -4
  27. camel/models/litellm_model.py +38 -0
  28. camel/models/mistral_model.py +66 -0
  29. camel/models/model_factory.py +10 -1
  30. camel/models/openai_compatible_model.py +81 -17
  31. camel/models/openai_model.py +87 -16
  32. camel/models/reka_model.py +69 -0
  33. camel/models/samba_model.py +69 -2
  34. camel/models/sglang_model.py +74 -2
  35. camel/models/watsonx_model.py +62 -0
  36. camel/societies/workforce/role_playing_worker.py +11 -3
  37. camel/societies/workforce/single_agent_worker.py +31 -1
  38. camel/societies/workforce/utils.py +51 -0
  39. camel/societies/workforce/workforce.py +409 -7
  40. camel/storages/__init__.py +2 -0
  41. camel/storages/vectordb_storages/__init__.py +2 -0
  42. camel/storages/vectordb_storages/weaviate.py +714 -0
  43. camel/tasks/task.py +27 -10
  44. camel/toolkits/async_browser_toolkit.py +97 -54
  45. camel/toolkits/browser_toolkit.py +65 -18
  46. camel/toolkits/code_execution.py +37 -8
  47. camel/toolkits/function_tool.py +2 -2
  48. camel/toolkits/mcp_toolkit.py +13 -2
  49. camel/toolkits/playwright_mcp_toolkit.py +16 -3
  50. camel/toolkits/task_planning_toolkit.py +134 -0
  51. camel/types/enums.py +61 -2
  52. camel/types/unified_model_type.py +5 -0
  53. camel/utils/__init__.py +16 -0
  54. camel/utils/langfuse.py +258 -0
  55. camel/utils/mcp_client.py +84 -17
  56. {camel_ai-0.2.62.dist-info → camel_ai-0.2.65.dist-info}/METADATA +9 -12
  57. {camel_ai-0.2.62.dist-info → camel_ai-0.2.65.dist-info}/RECORD +59 -49
  58. {camel_ai-0.2.62.dist-info → camel_ai-0.2.65.dist-info}/WHEEL +0 -0
  59. {camel_ai-0.2.62.dist-info → camel_ai-0.2.65.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,465 @@
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 argparse
15
+ import json
16
+ import logging
17
+ import os
18
+ import sys # Import the sys module
19
+ from logging.handlers import RotatingFileHandler
20
+ from typing import Any, Dict, List
21
+
22
+ app = None
23
+ products: List[Dict[str, Any]] = []
24
+ products_by_id: Dict[int, Dict[str, Any]] = {}
25
+ cart: List[Dict[str, Any]] = []
26
+ ACTION_COUNT: int = 0
27
+
28
+
29
+ def load_products(file_path: str = 'products.json') -> None:
30
+ global products, products_by_id
31
+ try:
32
+ # The products.json is expected to be
33
+ # in the same directory as this app.py
34
+ # or given by mock_web.py
35
+ script_dir = os.path.dirname(__file__)
36
+ abs_file_path = os.path.join(script_dir, file_path)
37
+ with open(abs_file_path, 'r') as f:
38
+ products = json.load(f)
39
+ products_by_id = {product['id']: product for product in products}
40
+ except FileNotFoundError:
41
+ sys.stderr.write(f"Error: {file_path} not found.\n")
42
+ products = []
43
+ products_by_id = {}
44
+ except json.JSONDecodeError:
45
+ sys.stderr.write(f"Error: Could not decode JSON from {file_path}.\n")
46
+ products = []
47
+ products_by_id = {}
48
+
49
+
50
+ # --- Logging Setup ---
51
+ def setup_logging(application):
52
+ log_formatter = logging.Formatter(
53
+ '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
54
+ )
55
+ # Log to a file in the same directory as this script
56
+ script_dir = os.path.dirname(__file__)
57
+ log_file = os.path.join(script_dir, 'app.log')
58
+
59
+ # File Handler
60
+ file_handler = RotatingFileHandler(
61
+ log_file, maxBytes=1024 * 1024 * 10, backupCount=5
62
+ ) # 10MB per file, 5 backups
63
+ file_handler.setFormatter(log_formatter)
64
+ file_handler.setLevel(logging.INFO)
65
+
66
+ # Stream Handler (for console output)
67
+ stream_handler = logging.StreamHandler(
68
+ sys.stdout
69
+ ) # Explicitly set to stdout
70
+ stream_handler.setFormatter(log_formatter)
71
+ stream_handler.setLevel(logging.INFO)
72
+
73
+ application.logger.addHandler(file_handler)
74
+ application.logger.addHandler(stream_handler)
75
+ application.logger.setLevel(logging.INFO)
76
+ application.logger.info(
77
+ f"Logging setup complete. Logs will be saved to {log_file}"
78
+ )
79
+
80
+
81
+ # --- End Logging Setup ---
82
+
83
+
84
+ # --- Task Mode Helper ---
85
+ def check_task_completion(current_cart_raw, ground_truth_spec):
86
+ if not ground_truth_spec: # No ground truth defined
87
+ return False
88
+
89
+ # Group current cart by product ID and count quantity
90
+ current_cart_grouped = {}
91
+ for item in current_cart_raw:
92
+ pid = item['id']
93
+ current_cart_grouped[pid] = current_cart_grouped.get(pid, 0) + 1
94
+
95
+ # Convert ground truth spec to a comparable dictionary {product_id:
96
+ # quantity}
97
+ ground_truth_dict = {}
98
+ for item_spec in ground_truth_spec:
99
+ ground_truth_dict[item_spec['id']] = item_spec['quantity']
100
+
101
+ # Check if current cart exactly matches ground truth
102
+ # 1. Same number of unique product types
103
+ if len(current_cart_grouped) != len(ground_truth_dict):
104
+ return False
105
+
106
+ # 2. Each product in current cart matches ground truth quantity, and all
107
+ # ground truth items are present
108
+ for pid, qty_spec in ground_truth_dict.items():
109
+ if (
110
+ pid not in current_cart_grouped
111
+ or current_cart_grouped[pid] != qty_spec
112
+ ):
113
+ return False
114
+
115
+ # Ensure no extra items in current_cart_grouped that are not in
116
+ # ground_truth_dict (already covered by length check if all ground truth
117
+ # items are found)
118
+ # For robustness, explicitly check this too:
119
+ for pid_current in current_cart_grouped.keys():
120
+ if pid_current not in ground_truth_dict:
121
+ return False
122
+
123
+ return True
124
+
125
+
126
+ # --- End Task Mode Helper ---
127
+
128
+
129
+ # --- Task Completion Helper ---
130
+ def _trigger_task_completion_check():
131
+ r"""Checks for task completion if in task mode and not already signaled."""
132
+ # Uses global `app` and `cart`
133
+ if app.config.get('TASK_ACTIVE') and not app.config.get(
134
+ 'TASK_COMPLETION_SIGNALED'
135
+ ):
136
+ if check_task_completion(cart, app.config.get('GROUND_TRUTH_CART')):
137
+ app.config['TASK_COMPLETION_SIGNALED'] = True
138
+ app.logger.info(
139
+ "TASK COMPLETED: Ground truth cart state achieved."
140
+ )
141
+
142
+
143
+ # --- End Task Completion Helper ---
144
+ def create_app():
145
+ global app
146
+ try:
147
+ from flask import Flask, jsonify, render_template, request
148
+ except ImportError:
149
+ raise ImportError(
150
+ "Flask not installed. Please install it with `pip install Flask`"
151
+ )
152
+
153
+ # Adjust template and static folder paths
154
+ script_dir = os.path.dirname(os.path.abspath(__file__))
155
+ app = Flask(
156
+ __name__,
157
+ template_folder=os.path.join(script_dir, 'templates'),
158
+ static_folder=os.path.join(script_dir, 'static'),
159
+ )
160
+ setup_logging(app)
161
+
162
+ # --- Global Task Config ---
163
+ app.config['TASK_ACTIVE'] = False
164
+ app.config['GROUND_TRUTH_CART'] = []
165
+ app.config['TASK_COMPLETION_SIGNALED'] = False
166
+
167
+ @app.route('/')
168
+ def home():
169
+ global ACTION_COUNT
170
+ ACTION_COUNT += 1
171
+ unique_categories = sorted({p["category"] for p in products})
172
+ products_by_category = {}
173
+ for product in products:
174
+ category = product["category"]
175
+ if category not in products_by_category:
176
+ products_by_category[category] = []
177
+ products_by_category[category].append(product)
178
+
179
+ app.logger.info(
180
+ "Home page requested. "
181
+ f"Categories: {unique_categories}. Cart count: {len(cart)}"
182
+ )
183
+ # Pass products_by_category to the template instead of the flat
184
+ # products list for main display
185
+ return render_template(
186
+ 'index.html',
187
+ products_by_category=products_by_category,
188
+ categories=unique_categories,
189
+ cart_count=len(cart),
190
+ all_products=products,
191
+ )
192
+
193
+ @app.route('/product/<int:product_id>')
194
+ def product_detail(product_id):
195
+ global ACTION_COUNT
196
+ ACTION_COUNT += 1
197
+ product = products_by_id.get(product_id)
198
+ app.logger.info(
199
+ f"Product detail page requested for ID: {product_id}. "
200
+ f"Cart count: {len(cart)}"
201
+ )
202
+ if product:
203
+ return render_template(
204
+ 'product-detail.html', product=product, cart_count=len(cart)
205
+ )
206
+ return "Product not found", 404
207
+
208
+ @app.route('/cart')
209
+ def view_cart():
210
+ global ACTION_COUNT
211
+ ACTION_COUNT += 1
212
+ total_price = sum(
213
+ item['price'] * item.get('quantity', 1) for item in cart
214
+ )
215
+ app.logger.info(f"Cart page requested. Cart count: {len(cart)}")
216
+ return render_template(
217
+ 'cart.html', cart_items=cart, total_price=total_price
218
+ )
219
+
220
+ @app.route('/api/products')
221
+ def get_products():
222
+ return jsonify(products)
223
+
224
+ @app.route('/api/cart', methods=['GET'])
225
+ def get_cart_api():
226
+ total_price = sum(
227
+ item['price'] * item.get('quantity', 1) for item in cart
228
+ )
229
+ return jsonify({'cart': cart, 'total_price': total_price})
230
+
231
+ @app.route('/api/cart/add', methods=['POST'])
232
+ def add_to_cart_api():
233
+ global ACTION_COUNT
234
+ data = request.json
235
+ product_id = data.get('productId')
236
+
237
+ if not product_id:
238
+ return jsonify(
239
+ {'success': False, 'message': 'Product ID is required'}
240
+ ), 400
241
+
242
+ product = products_by_id.get(product_id)
243
+ if not product:
244
+ return jsonify(
245
+ {'success': False, 'message': 'Product not found'}
246
+ ), 404
247
+
248
+ # Check if product is already in cart
249
+ for item in cart:
250
+ if item['id'] == product_id:
251
+ # If yes, just increment quantity
252
+ item.get('quantity', 1)
253
+ item['quantity'] = item.get('quantity', 1) + 1
254
+ app.logger.info(
255
+ f"Incremented quantity for product {product_id} in cart."
256
+ )
257
+ return jsonify(
258
+ {'success': True, 'cart': cart, 'cart_count': len(cart)}
259
+ )
260
+
261
+ # If not, add new item to cart
262
+ cart_item = product.copy()
263
+ cart_item['quantity'] = 1 # Start with quantity 1
264
+ cart.append(cart_item)
265
+ ACTION_COUNT += 1 # Increment on successful add
266
+
267
+ _trigger_task_completion_check()
268
+
269
+ app.logger.info(f"Added product {product_id} to cart.")
270
+ return jsonify(
271
+ {'success': True, 'cart': cart, 'cart_count': len(cart)}
272
+ )
273
+
274
+ @app.route('/api/cart/update', methods=['POST'])
275
+ def update_cart_item_api():
276
+ data = request.json
277
+ product_id = data.get('productId')
278
+ quantity = data.get('quantity')
279
+
280
+ if not product_id:
281
+ return jsonify(
282
+ {'success': False, 'message': 'Product ID is required'}
283
+ ), 400
284
+
285
+ try:
286
+ # Ensure quantity is a non-negative integer
287
+ quantity = int(quantity)
288
+ if quantity < 0:
289
+ raise ValueError
290
+ except (ValueError, TypeError):
291
+ return jsonify(
292
+ {'success': False, 'message': 'Invalid quantity'}
293
+ ), 400
294
+
295
+ found_item = False
296
+ for item in cart:
297
+ if item['id'] == product_id:
298
+ if quantity > 0:
299
+ item['quantity'] = quantity
300
+ app.logger.info(
301
+ "Updated quantity for product "
302
+ f"{product_id} to {quantity}."
303
+ )
304
+ else:
305
+ # If quantity is 0, remove the item
306
+ cart.remove(item)
307
+ app.logger.info(f"Removed product {product_id} from cart.")
308
+ found_item = True
309
+ break
310
+
311
+ if not found_item:
312
+ return jsonify(
313
+ {'success': False, 'message': 'Product not in cart'}
314
+ ), 404
315
+
316
+ _trigger_task_completion_check()
317
+
318
+ total_price = sum(
319
+ item['price'] * item.get('quantity', 1) for item in cart
320
+ )
321
+ return jsonify(
322
+ {
323
+ 'success': True,
324
+ 'cart': cart,
325
+ 'cart_count': len(cart),
326
+ 'total_price': total_price,
327
+ }
328
+ )
329
+
330
+ @app.route('/api/cart/remove', methods=['POST'])
331
+ def remove_from_cart_api():
332
+ global cart, ACTION_COUNT
333
+ data = request.json
334
+ product_id = data.get('productId')
335
+
336
+ if not product_id:
337
+ return jsonify(
338
+ {'success': False, 'message': 'Product ID is required'}
339
+ ), 400
340
+
341
+ original_cart_len = len(cart)
342
+ # List comprehension to create a new list excluding the item to be
343
+ # removed This is simpler than finding index and deleting
344
+ cart[:] = [item for item in cart if item['id'] != product_id]
345
+
346
+ if len(cart) < original_cart_len:
347
+ ACTION_COUNT += 1 # Increment on successful remove
348
+ app.logger.info(f"Removed product {product_id} from cart.")
349
+
350
+ _trigger_task_completion_check()
351
+
352
+ total_price = sum(
353
+ item['price'] * item.get('quantity', 1) for item in cart
354
+ )
355
+ return jsonify(
356
+ {
357
+ 'success': True,
358
+ 'cart': cart,
359
+ 'cart_count': len(cart),
360
+ 'total_price': total_price,
361
+ }
362
+ )
363
+
364
+ return jsonify(
365
+ {'success': False, 'message': 'Product not in cart'}
366
+ ), 404
367
+
368
+ @app.route('/task/start', methods=['POST'])
369
+ def start_task():
370
+ global cart, ACTION_COUNT
371
+ ACTION_COUNT = 0 # Reset action counter
372
+ data = request.json
373
+ ground_truth = data.get('ground_truth_cart')
374
+
375
+ if not isinstance(ground_truth, list):
376
+ return jsonify(
377
+ {
378
+ 'success': False,
379
+ 'message': '`ground_truth_cart` must be a list.',
380
+ }
381
+ ), 400
382
+
383
+ # Validate ground truth spec
384
+ for item_spec in ground_truth:
385
+ if not all(k in item_spec for k in ['id', 'quantity']):
386
+ return jsonify(
387
+ {
388
+ 'success': False,
389
+ 'message': (
390
+ 'Each item in `ground_truth_cart` must have '
391
+ '`id` and `quantity`.'
392
+ ),
393
+ }
394
+ ), 400
395
+
396
+ app.config['TASK_ACTIVE'] = True
397
+ app.config['GROUND_TRUTH_CART'] = ground_truth
398
+ app.config['TASK_COMPLETION_SIGNALED'] = False # Reset signal
399
+ cart = [] # Reset cart
400
+ app.logger.info(f"TASK MODE STARTED. Ground truth: {ground_truth}")
401
+ return jsonify(
402
+ {'success': True, 'message': 'Task mode started. Cart reset.'}
403
+ )
404
+
405
+ @app.route('/task/check', methods=['GET'])
406
+ def check_task():
407
+ global ACTION_COUNT
408
+ if not app.config.get('TASK_ACTIVE'):
409
+ return jsonify(
410
+ {'success': False, 'message': 'Task mode is not active.'}
411
+ ), 400
412
+
413
+ completed = app.config.get('TASK_COMPLETION_SIGNALED', False)
414
+ if completed:
415
+ message = "Task completed successfully."
416
+ else:
417
+ message = "Task not yet completed."
418
+
419
+ return jsonify(
420
+ {
421
+ 'success': True,
422
+ 'completed': completed,
423
+ 'steps': ACTION_COUNT,
424
+ 'message': message,
425
+ }
426
+ )
427
+
428
+ @app.route('/task/stop', methods=['POST'])
429
+ def stop_task():
430
+ global cart
431
+ app.config['TASK_ACTIVE'] = False
432
+ app.config['GROUND_TRUTH_CART'] = []
433
+ app.config['TASK_COMPLETION_SIGNALED'] = False
434
+ cart = [] # Reset cart
435
+ app.logger.info("TASK MODE STOPPED. Cart reset.")
436
+ return jsonify(
437
+ {'success': True, 'message': 'Task mode stopped. Cart reset.'}
438
+ )
439
+
440
+ return app
441
+
442
+
443
+ def main():
444
+ parser = argparse.ArgumentParser(
445
+ description="Run the mock website server."
446
+ )
447
+ parser.add_argument(
448
+ '--port', type=int, default=5000, help='Port to run the server on.'
449
+ )
450
+ args = parser.parse_args()
451
+
452
+ # Load products specific to this app
453
+ load_products()
454
+ flask_app = create_app()
455
+
456
+ if flask_app:
457
+ # Use 0.0.0.0 to make it accessible from the dispatcher
458
+ # Disable the reloader to prevent state loss on logging
459
+ flask_app.run(
460
+ debug=True, port=args.port, host='0.0.0.0', use_reloader=False
461
+ )
462
+
463
+
464
+ if __name__ == "__main__":
465
+ main()
@@ -0,0 +1,104 @@
1
+ {
2
+ "products": [
3
+ {
4
+ "id": 1,
5
+ "name": "Gaming Laptop",
6
+ "price": 1200,
7
+ "image": "assets/img/products/laptop.jpg",
8
+ "category": "Electronics",
9
+ "rating": 4.5,
10
+ "description": "High-performance gaming laptop with latest specs."
11
+ },
12
+ {
13
+ "id": 2,
14
+ "name": "Wireless Mouse",
15
+ "price": 25,
16
+ "image": "assets/img/products/mouse.jpg",
17
+ "category": "Electronics",
18
+ "rating": 4.0,
19
+ "description": "Ergonomic wireless mouse with long battery life."
20
+ },
21
+ {
22
+ "id": 3,
23
+ "name": "Mechanical Keyboard",
24
+ "price": 75,
25
+ "image": "assets/img/products/keyboard.jpg",
26
+ "category": "Electronics",
27
+ "rating": 4.8,
28
+ "description": "RGB mechanical keyboard with customizable keys."
29
+ },
30
+ {
31
+ "id": 4,
32
+ "name": "Coffee Maker",
33
+ "price": 50,
34
+ "image": "assets/img/products/coffeemaker.jpg",
35
+ "category": "Home Goods",
36
+ "rating": 3.9,
37
+ "description": "Drip coffee maker with programmable timer."
38
+ },
39
+ {
40
+ "id": 5,
41
+ "name": "Bluetooth Speaker",
42
+ "price": 45,
43
+ "image": "assets/img/products/speaker.jpg",
44
+ "category": "Electronics",
45
+ "rating": 4.2,
46
+ "description": "Portable Bluetooth speaker with rich sound."
47
+ },
48
+ {
49
+ "id": 6,
50
+ "name": "Smartphone",
51
+ "price": 699,
52
+ "image": "assets/img/products/smartphone.jpg",
53
+ "category": "Electronics",
54
+ "rating": 4.6,
55
+ "description": "Latest-gen smartphone with stunning display and fast performance."
56
+ },
57
+ {
58
+ "id": 7,
59
+ "name": "Air Purifier",
60
+ "price": 130,
61
+ "image": "assets/img/products/airpurifier.jpg",
62
+ "category": "Home Goods",
63
+ "rating": 4.3,
64
+ "description": "HEPA air purifier with quiet operation and multiple fan speeds."
65
+ },
66
+ {
67
+ "id": 8,
68
+ "name": "Fitness Tracker",
69
+ "price": 85,
70
+ "image": "assets/img/products/fitnesstracker.jpg",
71
+ "category": "Electronics",
72
+ "rating": 4.1,
73
+ "description": "Waterproof fitness tracker with heart rate and sleep monitoring."
74
+ },
75
+ {
76
+ "id": 9,
77
+ "name": "Electric Kettle",
78
+ "price": 35,
79
+ "image": "assets/img/products/kettle.jpg",
80
+ "category": "Home Goods",
81
+ "rating": 4.0,
82
+ "description": "Stainless steel electric kettle with auto shut-off feature."
83
+ },
84
+ {
85
+ "id": 10,
86
+ "name": "Noise Cancelling Headphones",
87
+ "price": 150,
88
+ "image": "assets/img/products/headphones.jpg",
89
+ "category": "Electronics",
90
+ "rating": 4.7,
91
+ "description": "Over-ear headphones with active noise cancellation and long battery life."
92
+ }
93
+ ],
94
+ "ground_truth_cart": [
95
+ {
96
+ "id": 1,
97
+ "quantity": 1
98
+ },
99
+ {
100
+ "id": 2,
101
+ "quantity": 1
102
+ }
103
+ ]
104
+ }
camel/configs/__init__.py CHANGED
@@ -16,6 +16,7 @@ from .anthropic_config import ANTHROPIC_API_PARAMS, AnthropicConfig
16
16
  from .base_config import BaseConfig
17
17
  from .bedrock_config import BEDROCK_API_PARAMS, BedrockConfig
18
18
  from .cohere_config import COHERE_API_PARAMS, CohereConfig
19
+ from .crynux_config import CRYNUX_API_PARAMS, CrynuxConfig
19
20
  from .deepseek_config import DEEPSEEK_API_PARAMS, DeepSeekConfig
20
21
  from .gemini_config import Gemini_API_PARAMS, GeminiConfig
21
22
  from .groq_config import GROQ_API_PARAMS, GroqConfig
@@ -112,4 +113,6 @@ __all__ = [
112
113
  'LMStudioConfig',
113
114
  'WatsonXConfig',
114
115
  'WATSONX_API_PARAMS',
116
+ 'CrynuxConfig',
117
+ 'CRYNUX_API_PARAMS',
115
118
  ]
@@ -0,0 +1,94 @@
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
+ from __future__ import annotations
15
+
16
+ from typing import Dict, Optional, Sequence, Type, Union
17
+
18
+ from pydantic import BaseModel
19
+
20
+ from camel.configs.base_config import BaseConfig
21
+
22
+
23
+ class CrynuxConfig(BaseConfig):
24
+ r"""Defines the parameters for generating chat completions using the
25
+ OpenAI API.
26
+
27
+ Args:
28
+ temperature (float, optional): Sampling temperature to use, between
29
+ :obj:`0` and :obj:`2`. Higher values make the output more random,
30
+ while lower values make it more focused and deterministic.
31
+ (default: :obj:`None`)
32
+ top_p (float, optional): An alternative to sampling with temperature,
33
+ called nucleus sampling, where the model considers the results of
34
+ the tokens with top_p probability mass. So :obj:`0.1` means only
35
+ the tokens comprising the top 10% probability mass are considered.
36
+ (default: :obj:`None`)
37
+ n (int, optional): How many chat completion choices to generate for
38
+ each input message. (default: :obj:`None`)
39
+ response_format (object, optional): An object specifying the format
40
+ that the model must output. Compatible with GPT-4 Turbo and all
41
+ GPT-3.5 Turbo models newer than gpt-3.5-turbo-1106. Setting to
42
+ {"type": "json_object"} enables JSON mode, which guarantees the
43
+ message the model generates is valid JSON. Important: when using
44
+ JSON mode, you must also instruct the model to produce JSON
45
+ yourself via a system or user message. Without this, the model
46
+ may generate an unending stream of whitespace until the generation
47
+ reaches the token limit, resulting in a long-running and seemingly
48
+ "stuck" request. Also note that the message content may be
49
+ partially cut off if finish_reason="length", which indicates the
50
+ generation exceeded max_tokens or the conversation exceeded the
51
+ max context length.
52
+ stream (bool, optional): If True, partial message deltas will be sent
53
+ as data-only server-sent events as they become available.
54
+ (default: :obj:`None`)
55
+ stop (str or list, optional): Up to :obj:`4` sequences where the API
56
+ will stop generating further tokens. (default: :obj:`None`)
57
+ max_tokens (int, optional): The maximum number of tokens to generate
58
+ in the chat completion. The total length of input tokens and
59
+ generated tokens is limited by the model's context length.
60
+ (default: :obj:`None`)
61
+ presence_penalty (float, optional): Number between :obj:`-2.0` and
62
+ :obj:`2.0`. Positive values penalize new tokens based on whether
63
+ they appear in the text so far, increasing the model's likelihood
64
+ to talk about new topics. See more information about frequency and
65
+ presence penalties. (default: :obj:`None`)
66
+ frequency_penalty (float, optional): Number between :obj:`-2.0` and
67
+ :obj:`2.0`. Positive values penalize new tokens based on their
68
+ existing frequency in the text so far, decreasing the model's
69
+ likelihood to repeat the same line verbatim. See more information
70
+ about frequency and presence penalties. (default: :obj:`None`)
71
+ logit_bias (dict, optional): Modify the likelihood of specified tokens
72
+ appearing in the completion. Accepts a json object that maps tokens
73
+ (specified by their token ID in the tokenizer) to an associated
74
+ bias value from :obj:`-100` to :obj:`100`. Mathematically, the bias
75
+ is added to the logits generated by the model prior to sampling.
76
+ The exact effect will vary per model, but values between:obj:` -1`
77
+ and :obj:`1` should decrease or increase likelihood of selection;
78
+ values like :obj:`-100` or :obj:`100` should result in a ban or
79
+ exclusive selection of the relevant token. (default: :obj:`None`)
80
+ """
81
+
82
+ temperature: Optional[float] = None
83
+ top_p: Optional[float] = None
84
+ n: Optional[int] = None
85
+ stream: Optional[bool] = None
86
+ stop: Optional[Union[str, Sequence[str]]] = None
87
+ max_tokens: Optional[int] = None
88
+ presence_penalty: Optional[float] = None
89
+ response_format: Optional[Union[Type[BaseModel], Dict]] = None
90
+ frequency_penalty: Optional[float] = None
91
+ logit_bias: Optional[Dict] = None
92
+
93
+
94
+ CRYNUX_API_PARAMS = {param for param in CrynuxConfig.model_fields.keys()}
camel/datasets/models.py CHANGED
@@ -46,7 +46,7 @@ class DataPoint(BaseModel):
46
46
  Returns:
47
47
  Dict[str, Any]: Dictionary representation of the DataPoint.
48
48
  """
49
- return self.dict()
49
+ return self.model_dump()
50
50
 
51
51
  @classmethod
52
52
  def from_dict(cls, data: Dict[str, Any]) -> 'DataPoint':