camel-ai 0.2.65__py3-none-any.whl → 0.2.83a6__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.
- camel/__init__.py +3 -3
- camel/agents/__init__.py +2 -2
- camel/agents/_types.py +9 -4
- camel/agents/_utils.py +40 -2
- camel/agents/base.py +2 -2
- camel/agents/chat_agent.py +5107 -995
- camel/agents/critic_agent.py +2 -2
- camel/agents/deductive_reasoner_agent.py +56 -56
- camel/agents/embodied_agent.py +2 -2
- camel/agents/knowledge_graph_agent.py +20 -20
- camel/agents/mcp_agent.py +35 -36
- camel/agents/multi_hop_generator_agent.py +3 -3
- camel/agents/programmed_agent_instruction.py +2 -2
- camel/agents/repo_agent.py +4 -3
- camel/agents/role_assignment_agent.py +2 -2
- camel/agents/search_agent.py +2 -2
- camel/agents/task_agent.py +2 -2
- camel/agents/tool_agents/__init__.py +2 -2
- camel/agents/tool_agents/base.py +2 -2
- camel/agents/tool_agents/hugging_face_tool_agent.py +3 -3
- camel/benchmarks/__init__.py +2 -2
- camel/benchmarks/apibank.py +5 -5
- camel/benchmarks/apibench.py +2 -2
- camel/benchmarks/base.py +2 -2
- camel/benchmarks/browsecomp.py +44 -33
- camel/benchmarks/gaia.py +17 -13
- camel/benchmarks/mock_website/README.md +1 -3
- camel/benchmarks/mock_website/mock_web.py +2 -2
- camel/benchmarks/mock_website/requirements.txt +1 -1
- camel/benchmarks/mock_website/shopping_mall/app.py +2 -2
- camel/benchmarks/mock_website/task.json +1 -1
- camel/benchmarks/nexus.py +3 -3
- camel/benchmarks/ragbench.py +2 -2
- camel/bots/__init__.py +2 -2
- camel/bots/discord/__init__.py +2 -2
- camel/bots/discord/discord_app.py +2 -2
- camel/bots/discord/discord_installation.py +2 -2
- camel/bots/discord/discord_store.py +3 -3
- camel/bots/slack/__init__.py +2 -2
- camel/bots/slack/models.py +4 -4
- camel/bots/slack/slack_app.py +2 -2
- camel/bots/telegram_bot.py +2 -2
- camel/configs/__init__.py +29 -2
- camel/configs/aihubmix_config.py +90 -0
- camel/configs/aiml_config.py +2 -2
- camel/configs/amd_config.py +70 -0
- camel/configs/anthropic_config.py +2 -2
- camel/configs/base_config.py +2 -2
- camel/configs/bedrock_config.py +5 -3
- camel/configs/cerebras_config.py +98 -0
- camel/configs/cohere_config.py +2 -2
- camel/configs/cometapi_config.py +106 -0
- camel/configs/crynux_config.py +2 -2
- camel/configs/deepseek_config.py +9 -8
- camel/configs/function_gemma_config.py +59 -0
- camel/configs/gemini_config.py +6 -4
- camel/configs/groq_config.py +6 -4
- camel/configs/internlm_config.py +6 -4
- camel/configs/litellm_config.py +2 -2
- camel/configs/lmstudio_config.py +6 -4
- camel/configs/minimax_config.py +95 -0
- camel/configs/mistral_config.py +2 -2
- camel/configs/modelscope_config.py +5 -3
- camel/configs/moonshot_config.py +2 -2
- camel/configs/nebius_config.py +105 -0
- camel/configs/netmind_config.py +2 -2
- camel/configs/novita_config.py +2 -2
- camel/configs/nvidia_config.py +2 -2
- camel/configs/ollama_config.py +2 -2
- camel/configs/openai_config.py +5 -3
- camel/configs/openrouter_config.py +6 -4
- camel/configs/ppio_config.py +2 -2
- camel/configs/qianfan_config.py +85 -0
- camel/configs/qwen_config.py +2 -2
- camel/configs/reka_config.py +2 -2
- camel/configs/samba_config.py +6 -4
- camel/configs/sglang_config.py +2 -2
- camel/configs/siliconflow_config.py +2 -2
- camel/configs/togetherai_config.py +2 -2
- camel/configs/vllm_config.py +4 -2
- camel/configs/watsonx_config.py +2 -2
- camel/configs/yi_config.py +6 -4
- camel/configs/zhipuai_config.py +6 -4
- camel/data_collectors/__init__.py +2 -2
- camel/data_collectors/alpaca_collector.py +18 -9
- camel/data_collectors/base.py +2 -2
- camel/data_collectors/sharegpt_collector.py +2 -2
- camel/datagen/__init__.py +2 -2
- camel/datagen/cot_datagen.py +3 -3
- camel/datagen/evol_instruct/__init__.py +2 -2
- camel/datagen/evol_instruct/evol_instruct.py +2 -2
- camel/datagen/evol_instruct/scorer.py +12 -12
- camel/datagen/evol_instruct/templates.py +16 -16
- camel/datagen/self_improving_cot.py +5 -5
- camel/datagen/self_instruct/__init__.py +2 -2
- camel/datagen/self_instruct/filter/__init__.py +2 -2
- camel/datagen/self_instruct/filter/filter_function.py +2 -2
- camel/datagen/self_instruct/filter/filter_registry.py +2 -2
- camel/datagen/self_instruct/filter/instruction_filter.py +2 -2
- camel/datagen/self_instruct/self_instruct.py +2 -2
- camel/datagen/self_instruct/templates.py +47 -47
- camel/datagen/source2synth/__init__.py +2 -2
- camel/datagen/source2synth/data_processor.py +2 -2
- camel/datagen/source2synth/models.py +2 -2
- camel/datagen/source2synth/user_data_processor_config.py +2 -2
- camel/datahubs/__init__.py +2 -2
- camel/datahubs/base.py +2 -2
- camel/datahubs/huggingface.py +2 -2
- camel/datahubs/models.py +2 -2
- camel/datasets/__init__.py +2 -2
- camel/datasets/base_generator.py +41 -12
- camel/datasets/few_shot_generator.py +18 -18
- camel/datasets/models.py +2 -2
- camel/datasets/self_instruct_generator.py +2 -2
- camel/datasets/static_dataset.py +2 -2
- camel/embeddings/__init__.py +2 -2
- camel/embeddings/azure_embedding.py +2 -2
- camel/embeddings/base.py +2 -2
- camel/embeddings/gemini_embedding.py +2 -2
- camel/embeddings/jina_embedding.py +2 -2
- camel/embeddings/mistral_embedding.py +2 -2
- camel/embeddings/openai_compatible_embedding.py +2 -2
- camel/embeddings/openai_embedding.py +2 -2
- camel/embeddings/sentence_transformers_embeddings.py +2 -2
- camel/embeddings/together_embedding.py +2 -2
- camel/embeddings/vlm_embedding.py +2 -2
- camel/environments/__init__.py +14 -2
- camel/environments/models.py +2 -2
- camel/environments/multi_step.py +2 -2
- camel/environments/rlcards_env.py +860 -0
- camel/environments/single_step.py +30 -5
- camel/environments/tic_tac_toe.py +3 -3
- camel/extractors/__init__.py +2 -2
- camel/extractors/base.py +2 -2
- camel/extractors/python_strategies.py +2 -2
- camel/generators.py +2 -2
- camel/human.py +2 -2
- camel/interpreters/__init__.py +4 -2
- camel/interpreters/base.py +2 -2
- camel/interpreters/docker/Dockerfile +14 -24
- camel/interpreters/docker_interpreter.py +5 -4
- camel/interpreters/e2b_interpreter.py +36 -3
- camel/interpreters/internal_python_interpreter.py +53 -4
- camel/interpreters/interpreter_error.py +2 -2
- camel/interpreters/ipython_interpreter.py +2 -2
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/interpreters/subprocess_interpreter.py +2 -2
- camel/loaders/__init__.py +13 -4
- camel/loaders/apify_reader.py +2 -2
- camel/loaders/base_io.py +2 -2
- camel/loaders/base_loader.py +85 -0
- camel/loaders/chunkr_reader.py +11 -2
- camel/loaders/crawl4ai_reader.py +2 -2
- camel/loaders/firecrawl_reader.py +6 -6
- camel/loaders/jina_url_reader.py +2 -2
- camel/loaders/markitdown.py +2 -2
- camel/loaders/mineru_extractor.py +2 -2
- camel/loaders/mistral_reader.py +2 -2
- camel/loaders/scrapegraph_reader.py +2 -2
- camel/loaders/unstructured_io.py +2 -2
- camel/logger.py +5 -5
- camel/memories/__init__.py +2 -2
- camel/memories/agent_memories.py +86 -3
- camel/memories/base.py +36 -2
- camel/memories/blocks/__init__.py +2 -2
- camel/memories/blocks/chat_history_block.py +125 -7
- camel/memories/blocks/vectordb_block.py +10 -3
- camel/memories/context_creators/__init__.py +2 -2
- camel/memories/context_creators/score_based.py +109 -230
- camel/memories/records.py +90 -10
- camel/messages/__init__.py +2 -2
- camel/messages/base.py +178 -43
- camel/messages/conversion/__init__.py +2 -2
- camel/messages/conversion/alpaca.py +2 -2
- camel/messages/conversion/conversation_models.py +2 -2
- camel/messages/conversion/sharegpt/__init__.py +2 -2
- camel/messages/conversion/sharegpt/function_call_formatter.py +2 -2
- camel/messages/conversion/sharegpt/hermes/__init__.py +2 -2
- camel/messages/conversion/sharegpt/hermes/hermes_function_formatter.py +2 -2
- camel/messages/func_message.py +54 -17
- camel/models/__init__.py +18 -2
- camel/models/_utils.py +3 -3
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +11 -18
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +127 -20
- camel/models/aws_bedrock_model.py +12 -35
- camel/models/azure_openai_model.py +214 -115
- camel/models/base_audio_model.py +5 -3
- camel/models/base_model.py +378 -31
- camel/models/cerebras_model.py +83 -0
- camel/models/cohere_model.py +18 -49
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +11 -18
- camel/models/deepseek_model.py +20 -84
- camel/models/fish_audio_model.py +8 -2
- camel/models/function_gemma_model.py +889 -0
- camel/models/gemini_model.py +391 -52
- camel/models/groq_model.py +11 -19
- camel/models/internlm_model.py +11 -18
- camel/models/litellm_model.py +57 -49
- camel/models/lmstudio_model.py +17 -20
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +20 -47
- camel/models/model_factory.py +39 -3
- camel/models/model_manager.py +26 -8
- camel/models/modelscope_model.py +13 -193
- camel/models/moonshot_model.py +183 -21
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +19 -9
- camel/models/netmind_model.py +11 -18
- camel/models/novita_model.py +11 -18
- camel/models/nvidia_model.py +11 -18
- camel/models/ollama_model.py +14 -21
- camel/models/openai_audio_models.py +2 -2
- camel/models/openai_compatible_model.py +190 -71
- camel/models/openai_model.py +192 -86
- camel/models/openrouter_model.py +11 -19
- camel/models/ppio_model.py +11 -18
- camel/models/qianfan_model.py +89 -0
- camel/models/qwen_model.py +13 -193
- camel/models/reka_model.py +23 -49
- camel/models/reward/__init__.py +2 -2
- camel/models/reward/base_reward_model.py +2 -2
- camel/models/reward/evaluator.py +2 -2
- camel/models/reward/nemotron_model.py +2 -2
- camel/models/reward/skywork_model.py +2 -2
- camel/models/samba_model.py +50 -75
- camel/models/sglang_model.py +90 -68
- camel/models/siliconflow_model.py +12 -35
- camel/models/stub_model.py +10 -7
- camel/models/togetherai_model.py +11 -18
- camel/models/vllm_model.py +10 -18
- camel/models/volcano_model.py +158 -19
- camel/models/watsonx_model.py +9 -47
- camel/models/yi_model.py +11 -18
- camel/models/zhipuai_model.py +70 -18
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/personas/__init__.py +2 -2
- camel/personas/persona.py +2 -2
- camel/personas/persona_hub.py +2 -2
- camel/prompts/__init__.py +2 -2
- camel/prompts/ai_society.py +2 -2
- camel/prompts/base.py +2 -2
- camel/prompts/code.py +2 -2
- camel/prompts/evaluation.py +2 -2
- camel/prompts/generate_text_embedding_data.py +2 -2
- camel/prompts/image_craft.py +2 -2
- camel/prompts/misalignment.py +2 -2
- camel/prompts/multi_condition_image_craft.py +2 -2
- camel/prompts/object_recognition.py +2 -2
- camel/prompts/persona_hub.py +3 -3
- camel/prompts/prompt_templates.py +2 -2
- camel/prompts/role_description_prompt_template.py +2 -2
- camel/prompts/solution_extraction.py +8 -8
- camel/prompts/task_prompt_template.py +2 -2
- camel/prompts/translation.py +2 -2
- camel/prompts/video_description_prompt.py +3 -3
- camel/responses/__init__.py +2 -2
- camel/responses/agent_responses.py +2 -2
- camel/retrievers/__init__.py +2 -2
- camel/retrievers/auto_retriever.py +3 -2
- camel/retrievers/base.py +2 -2
- camel/retrievers/bm25_retriever.py +2 -2
- camel/retrievers/cohere_rerank_retriever.py +2 -2
- camel/retrievers/hybrid_retrival.py +2 -2
- camel/retrievers/vector_retriever.py +2 -2
- camel/runtimes/Dockerfile.multi-toolkit +90 -0
- camel/runtimes/__init__.py +2 -2
- camel/runtimes/api.py +79 -23
- camel/runtimes/base.py +2 -2
- camel/runtimes/configs.py +13 -13
- camel/runtimes/daytona_runtime.py +17 -18
- camel/runtimes/docker_runtime.py +12 -12
- camel/runtimes/llm_guard_runtime.py +26 -26
- camel/runtimes/remote_http_runtime.py +11 -11
- camel/runtimes/ubuntu_docker_runtime.py +2 -2
- camel/runtimes/utils/__init__.py +2 -2
- camel/runtimes/utils/function_risk_toolkit.py +2 -2
- camel/runtimes/utils/ignore_risk_toolkit.py +2 -2
- camel/schemas/__init__.py +2 -2
- camel/schemas/base.py +2 -2
- camel/schemas/openai_converter.py +3 -3
- camel/schemas/outlines_converter.py +2 -2
- camel/services/agent_openapi_server.py +380 -0
- camel/societies/__init__.py +4 -2
- camel/societies/babyagi_playing.py +2 -2
- camel/societies/role_playing.py +201 -80
- camel/societies/workforce/__init__.py +10 -3
- camel/societies/workforce/base.py +2 -2
- camel/societies/workforce/events.py +145 -0
- camel/societies/workforce/prompts.py +259 -33
- camel/societies/workforce/role_playing_worker.py +88 -31
- camel/societies/workforce/single_agent_worker.py +638 -40
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +182 -38
- camel/societies/workforce/utils.py +780 -65
- camel/societies/workforce/worker.py +92 -26
- camel/societies/workforce/workflow_memory_manager.py +1746 -0
- camel/societies/workforce/workforce.py +5354 -372
- camel/societies/workforce/workforce_callback.py +103 -0
- camel/societies/workforce/workforce_logger.py +647 -0
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/__init__.py +6 -2
- camel/storages/graph_storages/__init__.py +2 -2
- camel/storages/graph_storages/base.py +2 -2
- camel/storages/graph_storages/graph_element.py +2 -2
- camel/storages/graph_storages/nebula_graph.py +4 -4
- camel/storages/graph_storages/neo4j_graph.py +7 -7
- camel/storages/key_value_storages/__init__.py +2 -2
- camel/storages/key_value_storages/base.py +2 -2
- camel/storages/key_value_storages/in_memory.py +2 -2
- camel/storages/key_value_storages/json.py +17 -4
- camel/storages/key_value_storages/mem0_cloud.py +50 -49
- camel/storages/key_value_storages/redis.py +2 -2
- camel/storages/object_storages/__init__.py +2 -2
- camel/storages/object_storages/amazon_s3.py +2 -2
- camel/storages/object_storages/azure_blob.py +2 -2
- camel/storages/object_storages/base.py +2 -2
- camel/storages/object_storages/google_cloud.py +3 -3
- camel/storages/vectordb_storages/__init__.py +8 -2
- camel/storages/vectordb_storages/base.py +2 -2
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/faiss.py +2 -2
- camel/storages/vectordb_storages/milvus.py +2 -2
- camel/storages/vectordb_storages/oceanbase.py +15 -15
- camel/storages/vectordb_storages/pgvector.py +349 -0
- camel/storages/vectordb_storages/qdrant.py +6 -6
- camel/storages/vectordb_storages/surreal.py +372 -0
- camel/storages/vectordb_storages/tidb.py +11 -8
- camel/storages/vectordb_storages/weaviate.py +2 -2
- camel/tasks/__init__.py +2 -2
- camel/tasks/task.py +348 -26
- camel/tasks/task_prompt.py +3 -3
- camel/terminators/__init__.py +2 -2
- camel/terminators/base.py +2 -2
- camel/terminators/response_terminator.py +2 -2
- camel/terminators/token_limit_terminator.py +2 -2
- camel/toolkits/__init__.py +57 -10
- camel/toolkits/aci_toolkit.py +66 -21
- camel/toolkits/arxiv_toolkit.py +8 -8
- camel/toolkits/ask_news_toolkit.py +2 -2
- camel/toolkits/async_browser_toolkit.py +4 -4
- camel/toolkits/audio_analysis_toolkit.py +3 -3
- camel/toolkits/base.py +106 -6
- camel/toolkits/bohrium_toolkit.py +2 -2
- camel/toolkits/browser_toolkit.py +34 -21
- camel/toolkits/browser_toolkit_commons.py +4 -4
- camel/toolkits/code_execution.py +31 -4
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/craw4ai_toolkit.py +93 -0
- camel/toolkits/dappier_toolkit.py +12 -8
- camel/toolkits/data_commons_toolkit.py +2 -2
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/earth_science_toolkit.py +5367 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
- camel/toolkits/excel_toolkit.py +905 -71
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +205 -27
- camel/toolkits/github_toolkit.py +109 -22
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +40 -6
- camel/toolkits/google_drive_mcp_toolkit.py +54 -0
- camel/toolkits/google_maps_toolkit.py +2 -2
- camel/toolkits/google_scholar_toolkit.py +2 -2
- camel/toolkits/human_toolkit.py +36 -12
- camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1958 -0
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +4589 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +33 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1940 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +589 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +129 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +27 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +325 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1037 -0
- camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
- camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
- camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
- camel/toolkits/image_analysis_toolkit.py +3 -6
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +5 -6
- camel/toolkits/klavis_toolkit.py +7 -3
- camel/toolkits/linkedin_toolkit.py +2 -2
- camel/toolkits/markitdown_toolkit.py +104 -0
- camel/toolkits/math_toolkit.py +66 -12
- camel/toolkits/mcp_toolkit.py +412 -36
- camel/toolkits/memory_toolkit.py +7 -3
- camel/toolkits/meshy_toolkit.py +2 -2
- camel/toolkits/message_agent_toolkit.py +608 -0
- camel/toolkits/message_integration.py +728 -0
- camel/toolkits/microsoft_outlook_mail_toolkit.py +1885 -0
- camel/toolkits/mineru_toolkit.py +2 -2
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/networkx_toolkit.py +2 -2
- camel/toolkits/note_taking_toolkit.py +277 -0
- camel/toolkits/notion_mcp_toolkit.py +224 -0
- camel/toolkits/notion_toolkit.py +2 -2
- camel/toolkits/open_api_specs/biztoc/__init__.py +2 -2
- camel/toolkits/open_api_specs/biztoc/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/coursera/__init__.py +2 -2
- camel/toolkits/open_api_specs/create_qr_code/__init__.py +2 -2
- camel/toolkits/open_api_specs/klarna/__init__.py +2 -2
- camel/toolkits/open_api_specs/nasa_apod/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/outschool/openapi.yaml +1 -1
- camel/toolkits/open_api_specs/outschool/paths/__init__.py +2 -2
- camel/toolkits/open_api_specs/outschool/paths/get_classes.py +2 -2
- camel/toolkits/open_api_specs/outschool/paths/search_teachers.py +2 -2
- camel/toolkits/open_api_specs/security_config.py +2 -2
- camel/toolkits/open_api_specs/speak/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/ai-plugin.json +1 -1
- camel/toolkits/open_api_specs/web_scraper/paths/__init__.py +2 -2
- camel/toolkits/open_api_specs/web_scraper/paths/scraper.py +2 -2
- camel/toolkits/open_api_toolkit.py +2 -2
- camel/toolkits/openbb_toolkit.py +7 -3
- camel/toolkits/origene_mcp_toolkit.py +56 -0
- camel/toolkits/page_script.js +53 -53
- camel/toolkits/playwright_mcp_toolkit.py +13 -31
- camel/toolkits/pptx_toolkit.py +36 -23
- camel/toolkits/pubmed_toolkit.py +2 -2
- camel/toolkits/pulse_mcp_search_toolkit.py +2 -2
- camel/toolkits/pyautogui_toolkit.py +2 -2
- camel/toolkits/reddit_toolkit.py +2 -2
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/retrieval_toolkit.py +2 -2
- camel/toolkits/screenshot_toolkit.py +213 -0
- camel/toolkits/search_toolkit.py +606 -156
- camel/toolkits/searxng_toolkit.py +2 -2
- camel/toolkits/semantic_scholar_toolkit.py +2 -2
- camel/toolkits/slack_toolkit.py +108 -58
- camel/toolkits/sql_toolkit.py +712 -0
- camel/toolkits/stripe_toolkit.py +2 -2
- camel/toolkits/sympy_toolkit.py +3 -3
- camel/toolkits/task_planning_toolkit.py +5 -5
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +1281 -0
- camel/toolkits/terminal_toolkit/utils.py +659 -0
- camel/toolkits/thinking_toolkit.py +3 -3
- camel/toolkits/twitter_toolkit.py +2 -2
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +109 -29
- camel/toolkits/video_download_toolkit.py +19 -16
- camel/toolkits/weather_toolkit.py +2 -2
- camel/toolkits/web_deploy_toolkit.py +1219 -0
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/whatsapp_toolkit.py +2 -2
- camel/toolkits/wolfram_alpha_toolkit.py +2 -2
- camel/toolkits/zapier_toolkit.py +7 -3
- camel/types/__init__.py +4 -4
- camel/types/agents/__init__.py +2 -2
- camel/types/agents/tool_calling_record.py +6 -3
- camel/types/enums.py +381 -41
- camel/types/mcp_registries.py +2 -2
- camel/types/openai_types.py +4 -4
- camel/types/unified_model_type.py +46 -10
- camel/utils/__init__.py +5 -2
- camel/utils/agent_context.py +41 -0
- camel/utils/async_func.py +2 -2
- camel/utils/chunker/__init__.py +2 -2
- camel/utils/chunker/base.py +2 -2
- camel/utils/chunker/code_chunker.py +2 -2
- camel/utils/chunker/uio_chunker.py +2 -2
- camel/utils/commons.py +38 -7
- camel/utils/constants.py +5 -2
- camel/utils/context_utils.py +1134 -0
- camel/utils/deduplication.py +2 -2
- camel/utils/filename.py +2 -2
- camel/utils/langfuse.py +18 -10
- camel/utils/mcp.py +140 -6
- camel/utils/mcp_client.py +48 -38
- camel/utils/message_summarizer.py +148 -0
- camel/utils/response_format.py +2 -2
- camel/utils/token_counting.py +45 -22
- camel/utils/tool_result.py +44 -0
- camel/verifiers/__init__.py +2 -2
- camel/verifiers/base.py +2 -2
- camel/verifiers/math_verifier.py +2 -2
- camel/verifiers/models.py +2 -2
- camel/verifiers/physics_verifier.py +2 -2
- camel/verifiers/python_verifier.py +2 -2
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.83a6.dist-info}/METADATA +355 -117
- camel_ai-0.2.83a6.dist-info/RECORD +511 -0
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.83a6.dist-info}/WHEEL +1 -1
- {camel_ai-0.2.65.dist-info → camel_ai-0.2.83a6.dist-info}/licenses/LICENSE +1 -1
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/dalle_toolkit.py +0 -175
- camel/toolkits/file_write_toolkit.py +0 -444
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- camel_ai-0.2.65.dist-info/RECORD +0 -426
camel/toolkits/mcp_toolkit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
1
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
2
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
@@ -10,20 +10,29 @@
|
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
# ========= Copyright 2023-
|
|
13
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
16
|
import os
|
|
17
|
+
import warnings
|
|
17
18
|
from contextlib import AsyncExitStack
|
|
18
19
|
from typing import Any, Dict, List, Optional
|
|
19
20
|
|
|
21
|
+
from typing_extensions import TypeGuard
|
|
22
|
+
|
|
20
23
|
from camel.logger import get_logger
|
|
21
|
-
from camel.toolkits import BaseToolkit
|
|
24
|
+
from camel.toolkits.base import BaseToolkit
|
|
25
|
+
from camel.toolkits.function_tool import FunctionTool
|
|
22
26
|
from camel.utils.commons import run_async
|
|
23
27
|
from camel.utils.mcp_client import MCPClient, create_mcp_client
|
|
24
28
|
|
|
25
29
|
logger = get_logger(__name__)
|
|
26
30
|
|
|
31
|
+
# Suppress parameter description warnings for MCP tools
|
|
32
|
+
warnings.filterwarnings(
|
|
33
|
+
"ignore", message="Parameter description is missing", category=UserWarning
|
|
34
|
+
)
|
|
35
|
+
|
|
27
36
|
|
|
28
37
|
class MCPConnectionError(Exception):
|
|
29
38
|
r"""Raised when MCP connection fails."""
|
|
@@ -37,6 +46,187 @@ class MCPToolError(Exception):
|
|
|
37
46
|
pass
|
|
38
47
|
|
|
39
48
|
|
|
49
|
+
_EMPTY_SCHEMA = {
|
|
50
|
+
"additionalProperties": False,
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {},
|
|
53
|
+
"required": [],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def ensure_strict_json_schema(schema: dict[str, Any]) -> dict[str, Any]:
|
|
58
|
+
r"""Mutates the given JSON schema to ensure it conforms to the
|
|
59
|
+
`strict` standard that the OpenAI API expects.
|
|
60
|
+
"""
|
|
61
|
+
if schema == {}:
|
|
62
|
+
return _EMPTY_SCHEMA
|
|
63
|
+
return _ensure_strict_json_schema(schema, path=(), root=schema)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _ensure_strict_json_schema(
|
|
67
|
+
json_schema: object,
|
|
68
|
+
*,
|
|
69
|
+
path: tuple[str, ...],
|
|
70
|
+
root: dict[str, object],
|
|
71
|
+
) -> dict[str, Any]:
|
|
72
|
+
if not is_dict(json_schema):
|
|
73
|
+
raise TypeError(
|
|
74
|
+
f"Expected {json_schema} to be a dictionary; path={path}"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
defs = json_schema.get("$defs")
|
|
78
|
+
if is_dict(defs):
|
|
79
|
+
for def_name, def_schema in defs.items():
|
|
80
|
+
_ensure_strict_json_schema(
|
|
81
|
+
def_schema, path=(*path, "$defs", def_name), root=root
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
definitions = json_schema.get("definitions")
|
|
85
|
+
if is_dict(definitions):
|
|
86
|
+
for definition_name, definition_schema in definitions.items():
|
|
87
|
+
_ensure_strict_json_schema(
|
|
88
|
+
definition_schema,
|
|
89
|
+
path=(*path, "definitions", definition_name),
|
|
90
|
+
root=root,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
typ = json_schema.get("type")
|
|
94
|
+
if typ == "object" and "additionalProperties" not in json_schema:
|
|
95
|
+
json_schema["additionalProperties"] = False
|
|
96
|
+
elif (
|
|
97
|
+
typ == "object"
|
|
98
|
+
and "additionalProperties" in json_schema
|
|
99
|
+
and json_schema["additionalProperties"]
|
|
100
|
+
):
|
|
101
|
+
raise ValueError(
|
|
102
|
+
"additionalProperties should not be set for object types. This "
|
|
103
|
+
"could be because you're using an older version of Pydantic, or "
|
|
104
|
+
"because you configured additional properties to be allowed. If "
|
|
105
|
+
"you really need this, update the function or output tool "
|
|
106
|
+
"to not use a strict schema."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# object types
|
|
110
|
+
# { 'type': 'object', 'properties': { 'a': {...} } }
|
|
111
|
+
properties = json_schema.get("properties")
|
|
112
|
+
if is_dict(properties):
|
|
113
|
+
json_schema["required"] = list(properties.keys())
|
|
114
|
+
json_schema["properties"] = {
|
|
115
|
+
key: _ensure_strict_json_schema(
|
|
116
|
+
prop_schema, path=(*path, "properties", key), root=root
|
|
117
|
+
)
|
|
118
|
+
for key, prop_schema in properties.items()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# arrays
|
|
122
|
+
# { 'type': 'array', 'items': {...} }
|
|
123
|
+
items = json_schema.get("items")
|
|
124
|
+
if is_dict(items):
|
|
125
|
+
json_schema["items"] = _ensure_strict_json_schema(
|
|
126
|
+
items, path=(*path, "items"), root=root
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# unions
|
|
130
|
+
any_of = json_schema.get("anyOf")
|
|
131
|
+
if is_list(any_of):
|
|
132
|
+
json_schema["anyOf"] = [
|
|
133
|
+
_ensure_strict_json_schema(
|
|
134
|
+
variant, path=(*path, "anyOf", str(i)), root=root
|
|
135
|
+
)
|
|
136
|
+
for i, variant in enumerate(any_of)
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
# intersections
|
|
140
|
+
all_of = json_schema.get("allOf")
|
|
141
|
+
if is_list(all_of):
|
|
142
|
+
if len(all_of) == 1:
|
|
143
|
+
json_schema.update(
|
|
144
|
+
_ensure_strict_json_schema(
|
|
145
|
+
all_of[0], path=(*path, "allOf", "0"), root=root
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
json_schema.pop("allOf")
|
|
149
|
+
else:
|
|
150
|
+
json_schema["allOf"] = [
|
|
151
|
+
_ensure_strict_json_schema(
|
|
152
|
+
entry, path=(*path, "allOf", str(i)), root=root
|
|
153
|
+
)
|
|
154
|
+
for i, entry in enumerate(all_of)
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
# strip `None` defaults as there's no meaningful distinction here
|
|
158
|
+
# the schema will still be `nullable` and the model will default
|
|
159
|
+
# to using `None` anyway
|
|
160
|
+
if json_schema.get("default", None) is None:
|
|
161
|
+
json_schema.pop("default", None)
|
|
162
|
+
|
|
163
|
+
# we can't use `$ref`s if there are also other properties defined, e.g.
|
|
164
|
+
# `{"$ref": "...", "description": "my description"}`
|
|
165
|
+
#
|
|
166
|
+
# so we unravel the ref
|
|
167
|
+
# `{"type": "string", "description": "my description"}`
|
|
168
|
+
ref = json_schema.get("$ref")
|
|
169
|
+
if ref and has_more_than_n_keys(json_schema, 1):
|
|
170
|
+
assert isinstance(ref, str), f"Received non-string $ref - {ref}"
|
|
171
|
+
|
|
172
|
+
resolved = resolve_ref(root=root, ref=ref)
|
|
173
|
+
if not is_dict(resolved):
|
|
174
|
+
raise ValueError(
|
|
175
|
+
f"Expected `$ref: {ref}` to resolved to a dictionary but got "
|
|
176
|
+
f"{resolved}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# properties from the json schema take priority
|
|
180
|
+
# over the ones on the `$ref`
|
|
181
|
+
json_schema.update({**resolved, **json_schema})
|
|
182
|
+
json_schema.pop("$ref")
|
|
183
|
+
# Since the schema expanded from `$ref` might not
|
|
184
|
+
# have `additionalProperties: false` applied
|
|
185
|
+
# we call `_ensure_strict_json_schema` again to fix the inlined
|
|
186
|
+
# schema and ensure it's valid
|
|
187
|
+
return _ensure_strict_json_schema(json_schema, path=path, root=root)
|
|
188
|
+
|
|
189
|
+
return json_schema
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def resolve_ref(*, root: dict[str, object], ref: str) -> object:
|
|
193
|
+
if not ref.startswith("#/"):
|
|
194
|
+
raise ValueError(
|
|
195
|
+
f"Unexpected $ref format {ref!r}; Does not start with #/"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
path = ref[2:].split("/")
|
|
199
|
+
resolved = root
|
|
200
|
+
for key in path:
|
|
201
|
+
value = resolved[key]
|
|
202
|
+
assert is_dict(value), (
|
|
203
|
+
f"encountered non-dictionary entry while resolving {ref} - "
|
|
204
|
+
f"{resolved}"
|
|
205
|
+
)
|
|
206
|
+
resolved = value
|
|
207
|
+
|
|
208
|
+
return resolved
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def is_dict(obj: object) -> TypeGuard[dict[str, object]]:
|
|
212
|
+
# just pretend that we know there are only `str` keys
|
|
213
|
+
# as that check is not worth the performance cost
|
|
214
|
+
return isinstance(obj, dict)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def is_list(obj: object) -> TypeGuard[list[object]]:
|
|
218
|
+
return isinstance(obj, list)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def has_more_than_n_keys(obj: dict[str, object], n: int) -> bool:
|
|
222
|
+
i = 0
|
|
223
|
+
for _ in obj.keys():
|
|
224
|
+
i += 1
|
|
225
|
+
if i > n:
|
|
226
|
+
return True
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
|
|
40
230
|
class MCPToolkit(BaseToolkit):
|
|
41
231
|
r"""MCPToolkit provides a unified interface for managing multiple
|
|
42
232
|
MCP server connections and their tools.
|
|
@@ -98,8 +288,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
98
288
|
timeout (Optional[float], optional): Timeout for connection attempts
|
|
99
289
|
in seconds. This timeout applies to individual client connections.
|
|
100
290
|
(default: :obj:`None`)
|
|
101
|
-
strict (Optional[bool], optional): Flag to indicate strict mode.
|
|
102
|
-
(default: :obj:`False`)
|
|
103
291
|
|
|
104
292
|
Note:
|
|
105
293
|
At least one of :obj:`clients`, :obj:`config_path`, or
|
|
@@ -148,7 +336,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
148
336
|
config_path: Optional[str] = None,
|
|
149
337
|
config_dict: Optional[Dict[str, Any]] = None,
|
|
150
338
|
timeout: Optional[float] = None,
|
|
151
|
-
strict: Optional[bool] = False,
|
|
152
339
|
):
|
|
153
340
|
# Call parent constructor first
|
|
154
341
|
super().__init__(timeout=timeout)
|
|
@@ -165,7 +352,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
165
352
|
raise ValueError(error_msg)
|
|
166
353
|
|
|
167
354
|
self.clients: List[MCPClient] = clients or []
|
|
168
|
-
self.strict = strict # Store strict parameter
|
|
169
355
|
self._is_connected = False
|
|
170
356
|
self._exit_stack: Optional[AsyncExitStack] = None
|
|
171
357
|
|
|
@@ -218,26 +404,34 @@ class MCPToolkit(BaseToolkit):
|
|
|
218
404
|
self._exit_stack = AsyncExitStack()
|
|
219
405
|
|
|
220
406
|
try:
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
except Exception as e:
|
|
229
|
-
logger.error(f"Failed to connect to client {i+1}: {e}")
|
|
230
|
-
# AsyncExitStack will handle cleanup of already connected
|
|
231
|
-
await self._exit_stack.aclose()
|
|
232
|
-
self._exit_stack = None
|
|
233
|
-
error_msg = f"Failed to connect to client {i+1}: {e}"
|
|
234
|
-
raise MCPConnectionError(error_msg) from e
|
|
407
|
+
# Apply timeout to the entire connection process
|
|
408
|
+
import asyncio
|
|
409
|
+
|
|
410
|
+
timeout_seconds = self.timeout or 30.0
|
|
411
|
+
await asyncio.wait_for(
|
|
412
|
+
self._connect_all_clients(), timeout=timeout_seconds
|
|
413
|
+
)
|
|
235
414
|
|
|
236
415
|
self._is_connected = True
|
|
237
416
|
msg = f"Successfully connected to {len(self.clients)} MCP servers"
|
|
238
417
|
logger.info(msg)
|
|
239
418
|
return self
|
|
240
419
|
|
|
420
|
+
except (asyncio.TimeoutError, asyncio.CancelledError):
|
|
421
|
+
self._is_connected = False
|
|
422
|
+
if self._exit_stack:
|
|
423
|
+
await self._exit_stack.aclose()
|
|
424
|
+
self._exit_stack = None
|
|
425
|
+
|
|
426
|
+
timeout_seconds = self.timeout or 30.0
|
|
427
|
+
error_msg = (
|
|
428
|
+
f"Connection timeout after {timeout_seconds}s. "
|
|
429
|
+
f"One or more MCP servers are not responding. "
|
|
430
|
+
f"Please check if the servers are running and accessible."
|
|
431
|
+
)
|
|
432
|
+
logger.error(error_msg)
|
|
433
|
+
raise MCPConnectionError(error_msg)
|
|
434
|
+
|
|
241
435
|
except Exception:
|
|
242
436
|
self._is_connected = False
|
|
243
437
|
if self._exit_stack:
|
|
@@ -245,6 +439,23 @@ class MCPToolkit(BaseToolkit):
|
|
|
245
439
|
self._exit_stack = None
|
|
246
440
|
raise
|
|
247
441
|
|
|
442
|
+
async def _connect_all_clients(self):
|
|
443
|
+
r"""Connect to all clients sequentially."""
|
|
444
|
+
# Connect to all clients using AsyncExitStack
|
|
445
|
+
for i, client in enumerate(self.clients):
|
|
446
|
+
try:
|
|
447
|
+
# Use MCPClient directly as async context manager
|
|
448
|
+
await self._exit_stack.enter_async_context(client)
|
|
449
|
+
msg = f"Connected to client {i+1}/{len(self.clients)}"
|
|
450
|
+
logger.debug(msg)
|
|
451
|
+
except Exception as e:
|
|
452
|
+
logger.error(f"Failed to connect to client {i+1}: {e}")
|
|
453
|
+
# AsyncExitStack will cleanup already connected clients
|
|
454
|
+
await self._exit_stack.aclose()
|
|
455
|
+
self._exit_stack = None
|
|
456
|
+
error_msg = f"Failed to connect to client {i+1}: {e}"
|
|
457
|
+
raise MCPConnectionError(error_msg) from e
|
|
458
|
+
|
|
248
459
|
async def disconnect(self):
|
|
249
460
|
r"""Disconnect from all MCP servers."""
|
|
250
461
|
if not self._is_connected:
|
|
@@ -313,7 +524,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
313
524
|
config_path: Optional[str] = None,
|
|
314
525
|
config_dict: Optional[Dict[str, Any]] = None,
|
|
315
526
|
timeout: Optional[float] = None,
|
|
316
|
-
strict: Optional[bool] = False,
|
|
317
527
|
) -> "MCPToolkit":
|
|
318
528
|
r"""Factory method that creates and connects to all MCP servers.
|
|
319
529
|
|
|
@@ -331,8 +541,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
331
541
|
config file. (default: :obj:`None`)
|
|
332
542
|
timeout (Optional[float], optional): Timeout for connection
|
|
333
543
|
attempts in seconds. (default: :obj:`None`)
|
|
334
|
-
strict (Optional[bool], optional): Flag to indicate strict mode.
|
|
335
|
-
(default: :obj:`False`)
|
|
336
544
|
|
|
337
545
|
Returns:
|
|
338
546
|
MCPToolkit: A fully initialized and connected :obj:`MCPToolkit`
|
|
@@ -361,7 +569,6 @@ class MCPToolkit(BaseToolkit):
|
|
|
361
569
|
config_path=config_path,
|
|
362
570
|
config_dict=config_dict,
|
|
363
571
|
timeout=timeout,
|
|
364
|
-
strict=strict,
|
|
365
572
|
)
|
|
366
573
|
try:
|
|
367
574
|
await toolkit.connect()
|
|
@@ -381,11 +588,10 @@ class MCPToolkit(BaseToolkit):
|
|
|
381
588
|
config_path: Optional[str] = None,
|
|
382
589
|
config_dict: Optional[Dict[str, Any]] = None,
|
|
383
590
|
timeout: Optional[float] = None,
|
|
384
|
-
strict: Optional[bool] = False,
|
|
385
591
|
) -> "MCPToolkit":
|
|
386
592
|
r"""Synchronously create and connect to all MCP servers."""
|
|
387
593
|
return run_async(cls.create)(
|
|
388
|
-
clients, config_path, config_dict, timeout
|
|
594
|
+
clients, config_path, config_dict, timeout
|
|
389
595
|
)
|
|
390
596
|
|
|
391
597
|
def _load_clients_from_config(self, config_path: str) -> List[MCPClient]:
|
|
@@ -442,12 +648,10 @@ class MCPToolkit(BaseToolkit):
|
|
|
442
648
|
|
|
443
649
|
try:
|
|
444
650
|
# Use the new mcp_client factory function
|
|
445
|
-
# Pass timeout
|
|
651
|
+
# Pass timeout from toolkit if available
|
|
446
652
|
kwargs = {}
|
|
447
653
|
if hasattr(self, "timeout") and self.timeout is not None:
|
|
448
654
|
kwargs["timeout"] = self.timeout
|
|
449
|
-
if hasattr(self, "strict") and self.strict is not None:
|
|
450
|
-
kwargs["strict"] = self.strict
|
|
451
655
|
|
|
452
656
|
client = create_mcp_client(cfg, **kwargs)
|
|
453
657
|
return client
|
|
@@ -455,17 +659,169 @@ class MCPToolkit(BaseToolkit):
|
|
|
455
659
|
error_msg = f"Failed to create client for server '{name}': {e}"
|
|
456
660
|
raise ValueError(error_msg) from e
|
|
457
661
|
|
|
662
|
+
def _ensure_strict_tool_schema(self, tool: FunctionTool) -> FunctionTool:
|
|
663
|
+
r"""Ensure a tool has a strict schema compatible with
|
|
664
|
+
OpenAI's requirements.
|
|
665
|
+
|
|
666
|
+
Strategy:
|
|
667
|
+
- Ensure parameters exist with at least an empty properties object
|
|
668
|
+
(OpenAI requirement).
|
|
669
|
+
- Try converting parameters to strict using ensure_strict_json_schema.
|
|
670
|
+
- If conversion fails, mark function.strict = False and
|
|
671
|
+
keep best-effort parameters.
|
|
672
|
+
"""
|
|
673
|
+
try:
|
|
674
|
+
schema = tool.get_openai_tool_schema()
|
|
675
|
+
|
|
676
|
+
def _has_strict_mode_incompatible_features(json_schema):
|
|
677
|
+
r"""Check if schema has features incompatible
|
|
678
|
+
with OpenAI strict mode."""
|
|
679
|
+
|
|
680
|
+
def _check_incompatible(obj, path=""):
|
|
681
|
+
if not isinstance(obj, dict):
|
|
682
|
+
return False
|
|
683
|
+
|
|
684
|
+
# Check for allOf in array items (known to cause issues)
|
|
685
|
+
if "items" in obj and isinstance(obj["items"], dict):
|
|
686
|
+
items_schema = obj["items"]
|
|
687
|
+
if "allOf" in items_schema:
|
|
688
|
+
logger.debug(
|
|
689
|
+
f"Found allOf in array items at {path}"
|
|
690
|
+
)
|
|
691
|
+
return True
|
|
692
|
+
# Recursively check items schema
|
|
693
|
+
if _check_incompatible(items_schema, f"{path}.items"):
|
|
694
|
+
return True
|
|
695
|
+
|
|
696
|
+
# Check for other potentially problematic patterns
|
|
697
|
+
# anyOf/oneOf in certain contexts can also cause issues
|
|
698
|
+
if (
|
|
699
|
+
"anyOf" in obj and len(obj["anyOf"]) > 10
|
|
700
|
+
): # Large unions can be problematic
|
|
701
|
+
return True
|
|
702
|
+
|
|
703
|
+
# Recursively check nested objects
|
|
704
|
+
for key in [
|
|
705
|
+
"properties",
|
|
706
|
+
"additionalProperties",
|
|
707
|
+
"patternProperties",
|
|
708
|
+
]:
|
|
709
|
+
if key in obj and isinstance(obj[key], dict):
|
|
710
|
+
if key == "properties":
|
|
711
|
+
for prop_name, prop_schema in obj[key].items():
|
|
712
|
+
if isinstance(
|
|
713
|
+
prop_schema, dict
|
|
714
|
+
) and _check_incompatible(
|
|
715
|
+
prop_schema,
|
|
716
|
+
f"{path}.{key}.{prop_name}",
|
|
717
|
+
):
|
|
718
|
+
return True
|
|
719
|
+
elif _check_incompatible(
|
|
720
|
+
obj[key], f"{path}.{key}"
|
|
721
|
+
):
|
|
722
|
+
return True
|
|
723
|
+
|
|
724
|
+
# Check arrays and unions
|
|
725
|
+
for key in ["allOf", "anyOf", "oneOf"]:
|
|
726
|
+
if key in obj and isinstance(obj[key], list):
|
|
727
|
+
for i, item in enumerate(obj[key]):
|
|
728
|
+
if isinstance(
|
|
729
|
+
item, dict
|
|
730
|
+
) and _check_incompatible(
|
|
731
|
+
item, f"{path}.{key}[{i}]"
|
|
732
|
+
):
|
|
733
|
+
return True
|
|
734
|
+
|
|
735
|
+
return False
|
|
736
|
+
|
|
737
|
+
return _check_incompatible(json_schema)
|
|
738
|
+
|
|
739
|
+
# Apply sanitization if available
|
|
740
|
+
if "function" in schema:
|
|
741
|
+
try:
|
|
742
|
+
from camel.toolkits.function_tool import (
|
|
743
|
+
sanitize_and_enforce_required,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
schema = sanitize_and_enforce_required(schema)
|
|
747
|
+
except ImportError:
|
|
748
|
+
logger.debug("sanitize_and_enforce_required not available")
|
|
749
|
+
|
|
750
|
+
parameters = schema["function"].get("parameters", {})
|
|
751
|
+
if not parameters:
|
|
752
|
+
# Empty parameters - use minimal valid schema
|
|
753
|
+
parameters = {
|
|
754
|
+
"type": "object",
|
|
755
|
+
"properties": {},
|
|
756
|
+
"additionalProperties": False,
|
|
757
|
+
}
|
|
758
|
+
schema["function"]["parameters"] = parameters
|
|
759
|
+
|
|
760
|
+
# MCP spec doesn't require 'properties', but OpenAI spec does
|
|
761
|
+
if (
|
|
762
|
+
parameters.get("type") == "object"
|
|
763
|
+
and "properties" not in parameters
|
|
764
|
+
):
|
|
765
|
+
parameters["properties"] = {}
|
|
766
|
+
|
|
767
|
+
try:
|
|
768
|
+
# _check_schema_limits(parameters)
|
|
769
|
+
|
|
770
|
+
# Check for OpenAI strict mode incompatible features
|
|
771
|
+
if _has_strict_mode_incompatible_features(parameters):
|
|
772
|
+
raise ValueError(
|
|
773
|
+
"Schema contains features "
|
|
774
|
+
"incompatible with strict mode"
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
strict_params = ensure_strict_json_schema(parameters)
|
|
778
|
+
schema["function"]["parameters"] = strict_params
|
|
779
|
+
schema["function"]["strict"] = True
|
|
780
|
+
except Exception as e:
|
|
781
|
+
# Fallback to non-strict mode on any failure
|
|
782
|
+
schema["function"]["strict"] = False
|
|
783
|
+
logger.warning(
|
|
784
|
+
f"Tool '{tool.get_function_name()}' "
|
|
785
|
+
f"cannot use strict mode: {e}"
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
tool.set_openai_tool_schema(schema)
|
|
789
|
+
|
|
790
|
+
except Exception as e:
|
|
791
|
+
# Final fallback - ensure tool still works
|
|
792
|
+
try:
|
|
793
|
+
current_schema = tool.get_openai_tool_schema()
|
|
794
|
+
if "function" in current_schema:
|
|
795
|
+
current_schema["function"]["strict"] = False
|
|
796
|
+
tool.set_openai_tool_schema(current_schema)
|
|
797
|
+
logger.warning(
|
|
798
|
+
f"Error processing schema for tool "
|
|
799
|
+
f"'{tool.get_function_name()}': {str(e)[:100]}. "
|
|
800
|
+
f"Using non-strict mode."
|
|
801
|
+
)
|
|
802
|
+
except Exception as inner_e:
|
|
803
|
+
logger.error(
|
|
804
|
+
f"Critical error processing tool "
|
|
805
|
+
f"'{tool.get_function_name()}': {inner_e}. "
|
|
806
|
+
f"Tool may not function correctly."
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
return tool
|
|
810
|
+
|
|
458
811
|
def get_tools(self) -> List[FunctionTool]:
|
|
459
812
|
r"""Aggregates all tools from the managed MCP client instances.
|
|
460
813
|
|
|
461
814
|
Collects and combines tools from all connected MCP clients into a
|
|
462
815
|
single unified list. Each tool is converted to a CAMEL-compatible
|
|
463
|
-
:obj:`FunctionTool` that can be used with CAMEL agents.
|
|
816
|
+
:obj:`FunctionTool` that can be used with CAMEL agents. All tools
|
|
817
|
+
are ensured to have strict schemas compatible with OpenAI's
|
|
818
|
+
requirements.
|
|
464
819
|
|
|
465
820
|
Returns:
|
|
466
821
|
List[FunctionTool]: Combined list of all available function tools
|
|
467
|
-
from all connected MCP servers. Returns an
|
|
468
|
-
clients are connected or if no tools are
|
|
822
|
+
from all connected MCP servers with strict schemas. Returns an
|
|
823
|
+
empty list if no clients are connected or if no tools are
|
|
824
|
+
available.
|
|
469
825
|
|
|
470
826
|
Note:
|
|
471
827
|
This method can be called even when the toolkit is not connected,
|
|
@@ -489,17 +845,37 @@ class MCPToolkit(BaseToolkit):
|
|
|
489
845
|
)
|
|
490
846
|
|
|
491
847
|
all_tools = []
|
|
848
|
+
seen_names: set[str] = set()
|
|
492
849
|
for i, client in enumerate(self.clients):
|
|
493
850
|
try:
|
|
494
851
|
client_tools = client.get_tools()
|
|
495
|
-
|
|
852
|
+
|
|
853
|
+
# Ensure all tools have strict schemas
|
|
854
|
+
strict_tools = []
|
|
855
|
+
for tool in client_tools:
|
|
856
|
+
strict_tool = self._ensure_strict_tool_schema(tool)
|
|
857
|
+
name = strict_tool.get_function_name()
|
|
858
|
+
if name in seen_names:
|
|
859
|
+
logger.warning(
|
|
860
|
+
f"Duplicate tool name detected and "
|
|
861
|
+
f"skipped: '{name}' from client {i+1}"
|
|
862
|
+
)
|
|
863
|
+
continue
|
|
864
|
+
seen_names.add(name)
|
|
865
|
+
strict_tools.append(strict_tool)
|
|
866
|
+
|
|
867
|
+
all_tools.extend(strict_tools)
|
|
496
868
|
logger.debug(
|
|
497
|
-
f"Client {i+1} contributed {len(
|
|
869
|
+
f"Client {i+1} contributed {len(strict_tools)} "
|
|
870
|
+
f"tools (strict mode enabled)"
|
|
498
871
|
)
|
|
499
872
|
except Exception as e:
|
|
500
873
|
logger.error(f"Failed to get tools from client {i+1}: {e}")
|
|
501
874
|
|
|
502
|
-
logger.info(
|
|
875
|
+
logger.info(
|
|
876
|
+
f"Total tools available: {len(all_tools)} (all with strict "
|
|
877
|
+
f"schemas)"
|
|
878
|
+
)
|
|
503
879
|
return all_tools
|
|
504
880
|
|
|
505
881
|
def get_text_tools(self) -> str:
|
camel/toolkits/memory_toolkit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
1
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
2
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
# ========= Copyright 2023-
|
|
13
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import json
|
|
15
15
|
from typing import TYPE_CHECKING, Optional
|
|
16
16
|
|
|
@@ -43,7 +43,11 @@ class MemoryToolkit(BaseToolkit):
|
|
|
43
43
|
(default: :obj:`None`)
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
|
-
def __init__(
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
agent: 'ChatAgent',
|
|
49
|
+
timeout: Optional[float] = None,
|
|
50
|
+
):
|
|
47
51
|
super().__init__(timeout=timeout)
|
|
48
52
|
self.agent = agent
|
|
49
53
|
|
camel/toolkits/meshy_toolkit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
1
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
2
2
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
|
-
# ========= Copyright 2023-
|
|
13
|
+
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
16
|
from typing import Any, Dict, List, Optional
|