camel-ai 0.2.59__py3-none-any.whl → 0.2.82__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 +5012 -902
- 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 +39 -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 +94 -0
- camel/benchmarks/mock_website/mock_web.py +299 -0
- camel/benchmarks/mock_website/requirements.txt +3 -0
- camel/benchmarks/mock_website/shopping_mall/app.py +465 -0
- camel/benchmarks/mock_website/task.json +104 -0
- 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 +26 -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 +8 -7
- 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 +3 -3
- camel/configs/cometapi_config.py +106 -0
- camel/configs/crynux_config.py +94 -0
- camel/configs/deepseek_config.py +9 -8
- 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 +3 -3
- 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 +8 -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 +3 -3
- camel/configs/samba_config.py +8 -6
- 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_collector → data_collectors}/__init__.py +2 -2
- camel/{data_collector → data_collectors}/alpaca_collector.py +19 -10
- camel/{data_collector → data_collectors}/base.py +2 -2
- camel/{data_collector → data_collectors}/sharegpt_collector.py +3 -3
- camel/datagen/__init__.py +2 -2
- camel/datagen/cot_datagen.py +32 -37
- camel/datagen/evol_instruct/__init__.py +2 -2
- camel/datagen/evol_instruct/evol_instruct.py +2 -2
- camel/datagen/evol_instruct/scorer.py +24 -25
- camel/datagen/evol_instruct/templates.py +48 -48
- 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 +3 -3
- camel/datasets/self_instruct_generator.py +2 -2
- camel/datasets/static_dataset.py +152 -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 +10 -3
- 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 +4 -4
- camel/embeddings/together_embedding.py +2 -2
- camel/embeddings/vlm_embedding.py +11 -4
- 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 +16 -3
- camel/interpreters/docker/Dockerfile +53 -7
- camel/interpreters/docker_interpreter.py +70 -11
- camel/interpreters/e2b_interpreter.py +59 -11
- camel/interpreters/internal_python_interpreter.py +81 -4
- camel/interpreters/interpreter_error.py +2 -2
- camel/interpreters/ipython_interpreter.py +23 -5
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/interpreters/subprocess_interpreter.py +36 -4
- camel/loaders/__init__.py +17 -5
- 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 +128 -93
- 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 +148 -0
- 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 +126 -9
- camel/memories/blocks/vectordb_block.py +10 -3
- camel/memories/context_creators/__init__.py +2 -2
- camel/memories/context_creators/score_based.py +31 -239
- camel/memories/records.py +98 -13
- camel/messages/__init__.py +2 -2
- camel/messages/base.py +193 -46
- 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 +263 -63
- camel/models/base_audio_model.py +5 -3
- camel/models/base_model.py +195 -26
- camel/models/cerebras_model.py +83 -0
- camel/models/cohere_model.py +81 -21
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +87 -0
- camel/models/deepseek_model.py +61 -59
- camel/models/fish_audio_model.py +8 -2
- camel/models/gemini_model.py +439 -30
- camel/models/groq_model.py +11 -19
- camel/models/internlm_model.py +11 -18
- camel/models/litellm_model.py +94 -34
- camel/models/lmstudio_model.py +17 -20
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +84 -19
- camel/models/model_factory.py +49 -6
- camel/models/model_manager.py +33 -11
- camel/models/modelscope_model.py +13 -193
- camel/models/moonshot_model.py +195 -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 +234 -27
- camel/models/openai_model.py +255 -39
- 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 +90 -21
- 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 +117 -49
- camel/models/sglang_model.py +162 -42
- 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 +16 -20
- camel/models/watsonx_model.py +69 -19
- 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 +23 -3
- camel/retrievers/base.py +2 -2
- camel/retrievers/bm25_retriever.py +3 -4
- camel/retrievers/cohere_rerank_retriever.py +2 -2
- camel/retrievers/hybrid_retrival.py +4 -4
- camel/retrievers/vector_retriever.py +2 -2
- camel/runtimes/Dockerfile.multi-toolkit +90 -0
- camel/{runtime → runtimes}/__init__.py +2 -2
- camel/runtimes/api.py +153 -0
- camel/{runtime → runtimes}/base.py +2 -2
- camel/{runtime → runtimes}/configs.py +13 -13
- camel/{runtime → runtimes}/daytona_runtime.py +18 -19
- camel/{runtime → runtimes}/docker_runtime.py +13 -13
- camel/{runtime → runtimes}/llm_guard_runtime.py +28 -28
- camel/{runtime → runtimes}/remote_http_runtime.py +12 -12
- camel/{runtime → runtimes}/ubuntu_docker_runtime.py +3 -3
- camel/{runtime → runtimes}/utils/__init__.py +2 -2
- camel/{runtime → runtimes}/utils/function_risk_toolkit.py +2 -2
- camel/{runtime → 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 +9 -5
- camel/societies/workforce/events.py +143 -0
- camel/societies/workforce/prompts.py +258 -33
- camel/societies/workforce/role_playing_worker.py +95 -30
- camel/societies/workforce/single_agent_worker.py +659 -30
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +182 -38
- camel/societies/workforce/utils.py +784 -18
- camel/societies/workforce/worker.py +96 -28
- camel/societies/workforce/workflow_memory_manager.py +1746 -0
- camel/societies/workforce/workforce.py +5730 -366
- 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 +10 -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 +12 -2
- camel/storages/vectordb_storages/base.py +2 -2
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/faiss.py +712 -0
- camel/storages/vectordb_storages/milvus.py +2 -2
- camel/storages/vectordb_storages/oceanbase.py +16 -17
- 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 +714 -0
- camel/tasks/__init__.py +2 -2
- camel/tasks/task.py +366 -27
- 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 +58 -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 +174 -575
- camel/toolkits/audio_analysis_toolkit.py +3 -3
- camel/toolkits/base.py +65 -7
- camel/toolkits/bohrium_toolkit.py +318 -0
- camel/toolkits/browser_toolkit.py +306 -566
- camel/toolkits/browser_toolkit_commons.py +568 -0
- camel/toolkits/code_execution.py +67 -11
- 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 +910 -70
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +128 -20
- camel/toolkits/github_toolkit.py +148 -43
- 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 +1973 -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 +1929 -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 +319 -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 -3
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +195 -79
- 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 +841 -600
- 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 +724 -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 +86 -74
- camel/toolkits/playwright_mcp_toolkit.py +27 -32
- camel/toolkits/pptx_toolkit.py +790 -0
- 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 +539 -146
- 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 +134 -0
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +1070 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/thinking_toolkit.py +3 -3
- camel/toolkits/twitter_toolkit.py +8 -3
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +112 -29
- camel/toolkits/video_download_toolkit.py +22 -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 +53 -25
- 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 +454 -35
- camel/types/mcp_registries.py +2 -2
- camel/types/openai_types.py +4 -4
- camel/types/unified_model_type.py +43 -6
- camel/utils/__init__.py +20 -2
- 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 +65 -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 +258 -0
- camel/utils/mcp.py +140 -6
- camel/utils/mcp_client.py +1056 -0
- 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.59.dist-info → camel_ai-0.2.82.dist-info}/METADATA +349 -108
- camel_ai-0.2.82.dist-info/RECORD +507 -0
- {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/WHEEL +1 -1
- {camel_ai-0.2.59.dist-info → camel_ai-0.2.82.dist-info}/licenses/LICENSE +1 -1
- camel/loaders/pandas_reader.py +0 -368
- camel/runtime/api.py +0 -97
- camel/toolkits/dalle_toolkit.py +0 -171
- camel/toolkits/file_write_toolkit.py +0 -395
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- camel_ai-0.2.59.dist-info/RECORD +0 -410
camel/toolkits/search_toolkit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ========= Copyright 2023-
|
|
1
|
+
# ========= Copyright 2023-2025 @ 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,15 +10,23 @@
|
|
|
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-2025 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
import os
|
|
15
|
+
import warnings
|
|
15
16
|
from typing import Any, Dict, List, Literal, Optional, TypeAlias, Union, cast
|
|
16
17
|
|
|
17
18
|
import requests
|
|
18
19
|
|
|
20
|
+
from camel.logger import get_logger
|
|
19
21
|
from camel.toolkits.base import BaseToolkit
|
|
20
22
|
from camel.toolkits.function_tool import FunctionTool
|
|
21
|
-
from camel.utils import
|
|
23
|
+
from camel.utils import (
|
|
24
|
+
MCPServer,
|
|
25
|
+
api_keys_required,
|
|
26
|
+
dependencies_required,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger = get_logger(__name__)
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
@MCPServer()
|
|
@@ -29,6 +37,24 @@ class SearchToolkit(BaseToolkit):
|
|
|
29
37
|
search engines like Google, DuckDuckGo, Wikipedia and Wolfram Alpha, Brave.
|
|
30
38
|
"""
|
|
31
39
|
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
timeout: Optional[float] = None,
|
|
43
|
+
exclude_domains: Optional[List[str]] = None,
|
|
44
|
+
):
|
|
45
|
+
r"""Initializes the SearchToolkit.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
timeout (float): Timeout for API requests in seconds.
|
|
49
|
+
(default: :obj:`None`)
|
|
50
|
+
exclude_domains (Optional[List[str]]): List of domains to
|
|
51
|
+
exclude from search results. Currently only supported
|
|
52
|
+
by the `search_google` function.
|
|
53
|
+
(default: :obj:`None`)
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(timeout=timeout)
|
|
56
|
+
self.exclude_domains = exclude_domains
|
|
57
|
+
|
|
32
58
|
@dependencies_required("wikipedia")
|
|
33
59
|
def search_wiki(self, entity: str) -> str:
|
|
34
60
|
r"""Search the entity in WikiPedia and return the summary of the
|
|
@@ -86,8 +112,8 @@ class SearchToolkit(BaseToolkit):
|
|
|
86
112
|
depth (Literal["standard", "deep"]): The depth of the search.
|
|
87
113
|
"standard" for a straightforward search, "deep" for a more
|
|
88
114
|
comprehensive search.
|
|
89
|
-
output_type (Literal["searchResults", "sourcedAnswer",
|
|
90
|
-
|
|
115
|
+
output_type (Literal["searchResults", "sourcedAnswer", "structured"]):
|
|
116
|
+
The type of output:
|
|
91
117
|
- "searchResults" for raw search results,
|
|
92
118
|
- "sourcedAnswer" for an answer with supporting sources,
|
|
93
119
|
- "structured" for output based on a provided schema.
|
|
@@ -139,9 +165,12 @@ class SearchToolkit(BaseToolkit):
|
|
|
139
165
|
except Exception as e:
|
|
140
166
|
return {"error": f"An unexpected error occurred: {e!s}"}
|
|
141
167
|
|
|
142
|
-
@dependencies_required("
|
|
168
|
+
@dependencies_required("ddgs")
|
|
143
169
|
def search_duckduckgo(
|
|
144
|
-
self,
|
|
170
|
+
self,
|
|
171
|
+
query: str,
|
|
172
|
+
source: str = "text",
|
|
173
|
+
number_of_result_pages: int = 10,
|
|
145
174
|
) -> List[Dict[str, Any]]:
|
|
146
175
|
r"""Use DuckDuckGo search engine to search information for
|
|
147
176
|
the given query.
|
|
@@ -154,76 +183,79 @@ class SearchToolkit(BaseToolkit):
|
|
|
154
183
|
query (str): The query to be searched.
|
|
155
184
|
source (str): The type of information to query (e.g., "text",
|
|
156
185
|
"images", "videos"). Defaults to "text".
|
|
157
|
-
|
|
186
|
+
number_of_result_pages (int): The number of result pages to
|
|
187
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
188
|
+
for focused searches and more for comprehensive searches.
|
|
189
|
+
(default: :obj:`10`)
|
|
158
190
|
|
|
159
191
|
Returns:
|
|
160
192
|
List[Dict[str, Any]]: A list of dictionaries where each dictionary
|
|
161
193
|
represents a search result.
|
|
162
194
|
"""
|
|
163
|
-
from
|
|
164
|
-
from requests.exceptions import RequestException
|
|
195
|
+
from ddgs import DDGS
|
|
165
196
|
|
|
166
197
|
ddgs = DDGS()
|
|
167
198
|
responses: List[Dict[str, Any]] = []
|
|
168
199
|
|
|
169
200
|
if source == "text":
|
|
170
201
|
try:
|
|
171
|
-
results = ddgs.text(
|
|
172
|
-
|
|
202
|
+
results = ddgs.text(query, max_results=number_of_result_pages)
|
|
203
|
+
# Iterate over results found
|
|
204
|
+
for i, result in enumerate(results, start=1):
|
|
205
|
+
# Creating a response object with a similar structure
|
|
206
|
+
response = {
|
|
207
|
+
"result_id": i,
|
|
208
|
+
"title": result["title"],
|
|
209
|
+
"description": result["body"],
|
|
210
|
+
"url": result["href"],
|
|
211
|
+
}
|
|
212
|
+
responses.append(response)
|
|
213
|
+
except Exception as e:
|
|
173
214
|
# Handle specific exceptions or general request exceptions
|
|
174
215
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
175
216
|
|
|
176
|
-
# Iterate over results found
|
|
177
|
-
for i, result in enumerate(results, start=1):
|
|
178
|
-
# Creating a response object with a similar structure
|
|
179
|
-
response = {
|
|
180
|
-
"result_id": i,
|
|
181
|
-
"title": result["title"],
|
|
182
|
-
"description": result["body"],
|
|
183
|
-
"url": result["href"],
|
|
184
|
-
}
|
|
185
|
-
responses.append(response)
|
|
186
|
-
|
|
187
217
|
elif source == "images":
|
|
188
218
|
try:
|
|
189
|
-
results = ddgs.images(
|
|
190
|
-
|
|
219
|
+
results = ddgs.images(
|
|
220
|
+
query, max_results=number_of_result_pages
|
|
221
|
+
)
|
|
222
|
+
# Iterate over results found
|
|
223
|
+
for i, result in enumerate(results, start=1):
|
|
224
|
+
# Creating a response object with a similar structure
|
|
225
|
+
response = {
|
|
226
|
+
"result_id": i,
|
|
227
|
+
"title": result["title"],
|
|
228
|
+
"image": result["image"],
|
|
229
|
+
"url": result["url"],
|
|
230
|
+
"source": result["source"],
|
|
231
|
+
}
|
|
232
|
+
responses.append(response)
|
|
233
|
+
except Exception as e:
|
|
191
234
|
# Handle specific exceptions or general request exceptions
|
|
192
235
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
193
236
|
|
|
194
|
-
# Iterate over results found
|
|
195
|
-
for i, result in enumerate(results, start=1):
|
|
196
|
-
# Creating a response object with a similar structure
|
|
197
|
-
response = {
|
|
198
|
-
"result_id": i,
|
|
199
|
-
"title": result["title"],
|
|
200
|
-
"image": result["image"],
|
|
201
|
-
"url": result["url"],
|
|
202
|
-
"source": result["source"],
|
|
203
|
-
}
|
|
204
|
-
responses.append(response)
|
|
205
|
-
|
|
206
237
|
elif source == "videos":
|
|
207
238
|
try:
|
|
208
|
-
results = ddgs.videos(
|
|
209
|
-
|
|
239
|
+
results = ddgs.videos(
|
|
240
|
+
query, max_results=number_of_result_pages
|
|
241
|
+
)
|
|
242
|
+
# Iterate over results found
|
|
243
|
+
for i, result in enumerate(results, start=1):
|
|
244
|
+
# Creating a response object with a similar structure
|
|
245
|
+
response = {
|
|
246
|
+
"result_id": i,
|
|
247
|
+
"title": result["title"],
|
|
248
|
+
"description": result["description"],
|
|
249
|
+
"embed_url": result["embed_url"],
|
|
250
|
+
"publisher": result["publisher"],
|
|
251
|
+
"duration": result["duration"],
|
|
252
|
+
"published": result["published"],
|
|
253
|
+
}
|
|
254
|
+
responses.append(response)
|
|
255
|
+
except Exception as e:
|
|
210
256
|
# Handle specific exceptions or general request exceptions
|
|
211
257
|
responses.append({"error": f"duckduckgo search failed.{e}"})
|
|
212
258
|
|
|
213
|
-
# Iterate over results found
|
|
214
|
-
for i, result in enumerate(results, start=1):
|
|
215
|
-
# Creating a response object with a similar structure
|
|
216
|
-
response = {
|
|
217
|
-
"result_id": i,
|
|
218
|
-
"title": result["title"],
|
|
219
|
-
"description": result["description"],
|
|
220
|
-
"embed_url": result["embed_url"],
|
|
221
|
-
"publisher": result["publisher"],
|
|
222
|
-
"duration": result["duration"],
|
|
223
|
-
"published": result["published"],
|
|
224
|
-
}
|
|
225
|
-
responses.append(response)
|
|
226
|
-
|
|
227
259
|
# If no answer found, return an empty list
|
|
228
260
|
return responses
|
|
229
261
|
|
|
@@ -238,7 +270,6 @@ class SearchToolkit(BaseToolkit):
|
|
|
238
270
|
country: str = "US",
|
|
239
271
|
search_lang: str = "en",
|
|
240
272
|
ui_lang: str = "en-US",
|
|
241
|
-
count: int = 20,
|
|
242
273
|
offset: int = 0,
|
|
243
274
|
safesearch: str = "moderate",
|
|
244
275
|
freshness: Optional[str] = None,
|
|
@@ -249,6 +280,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
249
280
|
units: Optional[str] = None,
|
|
250
281
|
extra_snippets: Optional[bool] = None,
|
|
251
282
|
summary: Optional[bool] = None,
|
|
283
|
+
number_of_result_pages: int = 10,
|
|
252
284
|
) -> Dict[str, Any]:
|
|
253
285
|
r"""This function queries the Brave search engine API and returns a
|
|
254
286
|
dictionary, representing a search result.
|
|
@@ -262,17 +294,18 @@ class SearchToolkit(BaseToolkit):
|
|
|
262
294
|
The country string is limited to 2 character country codes of
|
|
263
295
|
supported countries. For a list of supported values, see
|
|
264
296
|
Country Codes. (default: :obj:`US `)
|
|
265
|
-
search_lang (str): The search language preference.
|
|
266
|
-
|
|
267
|
-
|
|
297
|
+
search_lang (str): The search language preference.
|
|
298
|
+
Use ONLY these exact values, NOT standard ISO codes:
|
|
299
|
+
'ar', 'eu', 'bn', 'bg', 'ca', 'zh-hans', 'zh-hant', 'hr',
|
|
300
|
+
'cs', 'da', 'nl', 'en', 'en-gb', 'et', 'fi', 'fr', 'gl', 'de',
|
|
301
|
+
'gu', 'he', 'hi', 'hu', 'is', 'it', 'jp', 'kn', 'ko', 'lv',
|
|
302
|
+
'lt', 'ms', 'ml', 'mr', 'nb', 'pl', 'pt-br', 'pt-pt', 'pa',
|
|
303
|
+
'ro', 'ru', 'sr', 'sk', 'sl', 'es', 'sv', 'ta', 'te', 'th',
|
|
304
|
+
'tr', 'uk', 'vi'.
|
|
268
305
|
ui_lang (str): User interface language preferred in response.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
count (int): The number of search results returned in response.
|
|
273
|
-
The maximum is 20. The actual number delivered may be less than
|
|
274
|
-
requested. Combine this parameter with offset to paginate
|
|
275
|
-
search results.
|
|
306
|
+
Format: '<language_code>-<country_code>'. Common examples:
|
|
307
|
+
'en-US', 'en-GB', 'jp-JP', 'zh-hans-CN', 'zh-hant-TW',
|
|
308
|
+
'de-DE', 'fr-FR', 'es-ES', 'pt-BR', 'ru-RU', 'ko-KR'.
|
|
276
309
|
offset (int): The zero based offset that indicates number of search
|
|
277
310
|
results per page (count) to skip before returning the result.
|
|
278
311
|
The maximum is 9. The actual number delivered may be less than
|
|
@@ -334,6 +367,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
334
367
|
summary (Optional[bool]): This parameter enables summary key
|
|
335
368
|
generation in web search results. This is required for
|
|
336
369
|
summarizer to be enabled.
|
|
370
|
+
number_of_result_pages (int): The number of result pages to
|
|
371
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
372
|
+
for focused searches and more for comprehensive searches.
|
|
373
|
+
(default: :obj:`10`)
|
|
337
374
|
|
|
338
375
|
Returns:
|
|
339
376
|
Dict[str, Any]: A dictionary representing a search result.
|
|
@@ -360,7 +397,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
360
397
|
"country": country,
|
|
361
398
|
"search_lang": search_lang,
|
|
362
399
|
"ui_lang": ui_lang,
|
|
363
|
-
"count":
|
|
400
|
+
"count": number_of_result_pages,
|
|
364
401
|
"offset": offset,
|
|
365
402
|
"safesearch": safesearch,
|
|
366
403
|
"freshness": freshness,
|
|
@@ -372,10 +409,36 @@ class SearchToolkit(BaseToolkit):
|
|
|
372
409
|
"extra_snippets": extra_snippets,
|
|
373
410
|
"summary": summary,
|
|
374
411
|
}
|
|
412
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
375
413
|
|
|
376
414
|
response = requests.get(url, headers=headers, params=params)
|
|
377
|
-
|
|
378
|
-
|
|
415
|
+
try:
|
|
416
|
+
response.raise_for_status()
|
|
417
|
+
except requests.HTTPError as e:
|
|
418
|
+
raise RuntimeError(
|
|
419
|
+
f"Brave API HTTP error: {e}, body={response.text!r}"
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
json_data = response.json()
|
|
423
|
+
# Check if response has search results
|
|
424
|
+
content_keys = [
|
|
425
|
+
'web',
|
|
426
|
+
'news',
|
|
427
|
+
'videos',
|
|
428
|
+
'images',
|
|
429
|
+
'locations',
|
|
430
|
+
'discussions',
|
|
431
|
+
'faq',
|
|
432
|
+
'infobox',
|
|
433
|
+
]
|
|
434
|
+
has_results = any(key in json_data for key in content_keys)
|
|
435
|
+
|
|
436
|
+
if not has_results:
|
|
437
|
+
# Return empty results structure if no content found
|
|
438
|
+
json_data['web'] = {'results': []}
|
|
439
|
+
json_data['message'] = 'No search results found for the query'
|
|
440
|
+
|
|
441
|
+
return json_data
|
|
379
442
|
|
|
380
443
|
@api_keys_required(
|
|
381
444
|
[
|
|
@@ -384,25 +447,53 @@ class SearchToolkit(BaseToolkit):
|
|
|
384
447
|
]
|
|
385
448
|
)
|
|
386
449
|
def search_google(
|
|
387
|
-
self,
|
|
450
|
+
self,
|
|
451
|
+
query: str,
|
|
452
|
+
search_type: str = "web",
|
|
453
|
+
number_of_result_pages: int = 10,
|
|
454
|
+
start_page: int = 1,
|
|
388
455
|
) -> List[Dict[str, Any]]:
|
|
389
456
|
r"""Use Google search engine to search information for the given query.
|
|
390
457
|
|
|
391
458
|
Args:
|
|
392
459
|
query (str): The query to be searched.
|
|
393
|
-
|
|
460
|
+
search_type (str): The type of search to perform. Must be either
|
|
461
|
+
"web" for web pages or "image" for image search. Any other
|
|
462
|
+
value will raise a ValueError. (default: "web")
|
|
463
|
+
number_of_result_pages (int): The number of result pages to
|
|
464
|
+
retrieve. Must be a positive integer between 1 and 10.
|
|
465
|
+
Google Custom Search API limits results to 10 per request.
|
|
466
|
+
If a value greater than 10 is provided, it will be capped
|
|
467
|
+
at 10 with a warning. Adjust this based on your task - use
|
|
468
|
+
fewer results for focused searches and more for comprehensive
|
|
469
|
+
searches. (default: :obj:`10`)
|
|
470
|
+
start_page (int): The result page to start from. Must be a
|
|
471
|
+
positive integer (>= 1). Use this for pagination - e.g.,
|
|
472
|
+
start_page=1 for results 1-10, start_page=11 for results
|
|
473
|
+
11-20, etc. This allows agents to check initial results
|
|
474
|
+
and continue searching if needed. (default: :obj:`1`)
|
|
394
475
|
|
|
395
476
|
Returns:
|
|
396
477
|
List[Dict[str, Any]]: A list of dictionaries where each dictionary
|
|
397
|
-
represents a
|
|
398
|
-
|
|
478
|
+
represents a search result.
|
|
479
|
+
|
|
480
|
+
For web search, each dictionary contains:
|
|
399
481
|
- 'result_id': A number in order.
|
|
400
482
|
- 'title': The title of the website.
|
|
401
483
|
- 'description': A brief description of the website.
|
|
402
484
|
- 'long_description': More detail of the website.
|
|
403
485
|
- 'url': The URL of the website.
|
|
404
486
|
|
|
405
|
-
|
|
487
|
+
For image search, each dictionary contains:
|
|
488
|
+
- 'result_id': A number in order.
|
|
489
|
+
- 'title': The title of the image.
|
|
490
|
+
- 'image_url': The URL of the image.
|
|
491
|
+
- 'display_link': The website hosting the image.
|
|
492
|
+
- 'context_url': The URL of the page containing the image.
|
|
493
|
+
- 'width': Image width in pixels (if available).
|
|
494
|
+
- 'height': Image height in pixels (if available).
|
|
495
|
+
|
|
496
|
+
Example web result:
|
|
406
497
|
{
|
|
407
498
|
'result_id': 1,
|
|
408
499
|
'title': 'OpenAI',
|
|
@@ -414,29 +505,80 @@ class SearchToolkit(BaseToolkit):
|
|
|
414
505
|
benefit humanity as a whole',
|
|
415
506
|
'url': 'https://www.openai.com'
|
|
416
507
|
}
|
|
417
|
-
|
|
508
|
+
|
|
509
|
+
Example image result:
|
|
510
|
+
{
|
|
511
|
+
'result_id': 1,
|
|
512
|
+
'title': 'Beautiful Sunset',
|
|
513
|
+
'image_url': 'https://example.com/image.jpg',
|
|
514
|
+
'display_link': 'example.com',
|
|
515
|
+
'context_url': 'https://example.com/page.html',
|
|
516
|
+
'width': 800,
|
|
517
|
+
'height': 600
|
|
518
|
+
}
|
|
418
519
|
"""
|
|
520
|
+
from urllib.parse import quote
|
|
521
|
+
|
|
419
522
|
import requests
|
|
420
523
|
|
|
524
|
+
# Validate input parameters
|
|
525
|
+
if not isinstance(start_page, int) or start_page < 1:
|
|
526
|
+
raise ValueError("start_page must be a positive integer")
|
|
527
|
+
|
|
528
|
+
if (
|
|
529
|
+
not isinstance(number_of_result_pages, int)
|
|
530
|
+
or number_of_result_pages < 1
|
|
531
|
+
):
|
|
532
|
+
raise ValueError(
|
|
533
|
+
"number_of_result_pages must be a positive integer"
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
# Google Custom Search API has a limit of 10 results per request
|
|
537
|
+
if number_of_result_pages > 10:
|
|
538
|
+
logger.warning(
|
|
539
|
+
f"Google API limits results to 10 per request. "
|
|
540
|
+
f"Requested {number_of_result_pages}, using 10 instead."
|
|
541
|
+
)
|
|
542
|
+
number_of_result_pages = 10
|
|
543
|
+
|
|
544
|
+
if search_type not in ["web", "image"]:
|
|
545
|
+
raise ValueError("search_type must be either 'web' or 'image'")
|
|
546
|
+
|
|
421
547
|
# https://developers.google.com/custom-search/v1/overview
|
|
422
548
|
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
|
423
549
|
# https://cse.google.com/cse/all
|
|
424
550
|
SEARCH_ENGINE_ID = os.getenv("SEARCH_ENGINE_ID")
|
|
425
551
|
|
|
426
|
-
# Using the
|
|
427
|
-
start_page_idx =
|
|
552
|
+
# Using the specified start page
|
|
553
|
+
start_page_idx = start_page
|
|
428
554
|
# Different language may get different result
|
|
429
555
|
search_language = "en"
|
|
430
|
-
|
|
431
|
-
|
|
556
|
+
|
|
557
|
+
modified_query = query
|
|
558
|
+
if self.exclude_domains:
|
|
559
|
+
# Use Google's -site: operator to exclude domains
|
|
560
|
+
exclusion_terms = " ".join(
|
|
561
|
+
[f"-site:{domain}" for domain in self.exclude_domains]
|
|
562
|
+
)
|
|
563
|
+
modified_query = f"{query} {exclusion_terms}"
|
|
564
|
+
logger.debug(f"Excluded domains, modified query: {modified_query}")
|
|
565
|
+
|
|
566
|
+
encoded_query = quote(modified_query)
|
|
567
|
+
|
|
432
568
|
# Constructing the URL
|
|
433
569
|
# Doc: https://developers.google.com/custom-search/v1/using_rest
|
|
434
|
-
|
|
570
|
+
base_url = (
|
|
435
571
|
f"https://www.googleapis.com/customsearch/v1?"
|
|
436
|
-
f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={
|
|
437
|
-
f"{start_page_idx}&lr={search_language}&num={
|
|
572
|
+
f"key={GOOGLE_API_KEY}&cx={SEARCH_ENGINE_ID}&q={encoded_query}&start="
|
|
573
|
+
f"{start_page_idx}&lr={search_language}&num={number_of_result_pages}"
|
|
438
574
|
)
|
|
439
575
|
|
|
576
|
+
# Add searchType parameter for image search
|
|
577
|
+
if search_type == "image":
|
|
578
|
+
url = base_url + "&searchType=image"
|
|
579
|
+
else:
|
|
580
|
+
url = base_url
|
|
581
|
+
|
|
440
582
|
responses = []
|
|
441
583
|
# Fetch the results given the URL
|
|
442
584
|
try:
|
|
@@ -448,55 +590,109 @@ class SearchToolkit(BaseToolkit):
|
|
|
448
590
|
if "items" in data:
|
|
449
591
|
search_items = data.get("items")
|
|
450
592
|
|
|
451
|
-
# Iterate over
|
|
593
|
+
# Iterate over results found
|
|
452
594
|
for i, search_item in enumerate(search_items, start=1):
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
595
|
+
if search_type == "image":
|
|
596
|
+
# Process image search results
|
|
597
|
+
title = search_item.get("title")
|
|
598
|
+
image_url = search_item.get("link")
|
|
599
|
+
display_link = search_item.get("displayLink")
|
|
600
|
+
|
|
601
|
+
# Get context URL (page containing the image)
|
|
602
|
+
image_info = search_item.get("image", {})
|
|
603
|
+
context_url = image_info.get("contextLink", "")
|
|
604
|
+
|
|
605
|
+
# Get image dimensions if available
|
|
606
|
+
width = image_info.get("width")
|
|
607
|
+
height = image_info.get("height")
|
|
608
|
+
|
|
609
|
+
response = {
|
|
610
|
+
"result_id": i,
|
|
611
|
+
"title": title,
|
|
612
|
+
"image_url": image_url,
|
|
613
|
+
"display_link": display_link,
|
|
614
|
+
"context_url": context_url,
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if width:
|
|
618
|
+
response["width"] = int(width)
|
|
619
|
+
if height:
|
|
620
|
+
response["height"] = int(height)
|
|
621
|
+
|
|
622
|
+
responses.append(response)
|
|
465
623
|
else:
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
"
|
|
480
|
-
|
|
481
|
-
|
|
624
|
+
if "pagemap" not in search_item:
|
|
625
|
+
continue
|
|
626
|
+
if "metatags" not in search_item["pagemap"]:
|
|
627
|
+
continue
|
|
628
|
+
if (
|
|
629
|
+
"og:description"
|
|
630
|
+
in search_item["pagemap"]["metatags"][0]
|
|
631
|
+
):
|
|
632
|
+
long_description = search_item["pagemap"][
|
|
633
|
+
"metatags"
|
|
634
|
+
][0]["og:description"]
|
|
635
|
+
else:
|
|
636
|
+
long_description = "N/A"
|
|
637
|
+
title = search_item.get("title")
|
|
638
|
+
snippet = search_item.get("snippet")
|
|
639
|
+
|
|
640
|
+
link = search_item.get("link")
|
|
641
|
+
response = {
|
|
642
|
+
"result_id": i,
|
|
643
|
+
"title": title,
|
|
644
|
+
"description": snippet,
|
|
645
|
+
"long_description": long_description,
|
|
646
|
+
"url": link,
|
|
647
|
+
}
|
|
648
|
+
responses.append(response)
|
|
482
649
|
else:
|
|
483
|
-
|
|
650
|
+
if "error" in data:
|
|
651
|
+
error_info = data.get("error", {})
|
|
652
|
+
logger.error(
|
|
653
|
+
f"Google search failed - API response: {error_info}"
|
|
654
|
+
)
|
|
655
|
+
responses.append(
|
|
656
|
+
{
|
|
657
|
+
"error": f"Google search failed - "
|
|
658
|
+
f"API response: {error_info}"
|
|
659
|
+
}
|
|
660
|
+
)
|
|
661
|
+
elif "searchInformation" in data:
|
|
662
|
+
search_info = data.get("searchInformation", {})
|
|
663
|
+
total_results = search_info.get("totalResults", "0")
|
|
664
|
+
if total_results == "0":
|
|
665
|
+
logger.info(f"No results found for query: {query}")
|
|
666
|
+
# Return empty list to indicate no results (not an error)
|
|
667
|
+
responses = []
|
|
668
|
+
else:
|
|
669
|
+
logger.warning(
|
|
670
|
+
f"Google search returned no items but claims {total_results} results"
|
|
671
|
+
)
|
|
672
|
+
responses = []
|
|
673
|
+
else:
|
|
674
|
+
logger.error(
|
|
675
|
+
f"Unexpected Google API response format: {data}"
|
|
676
|
+
)
|
|
677
|
+
responses.append(
|
|
678
|
+
{"error": "Unexpected response format from Google API"}
|
|
679
|
+
)
|
|
484
680
|
|
|
485
|
-
except
|
|
486
|
-
|
|
487
|
-
responses.append({"error": "google search failed."})
|
|
488
|
-
# If no answer found, return an empty list
|
|
681
|
+
except Exception as e:
|
|
682
|
+
responses.append({"error": f"google search failed: {e!s}"})
|
|
489
683
|
return responses
|
|
490
684
|
|
|
491
|
-
def
|
|
492
|
-
self, query: str,
|
|
685
|
+
def search_tavily(
|
|
686
|
+
self, query: str, number_of_result_pages: int = 10, **kwargs
|
|
493
687
|
) -> List[Dict[str, Any]]:
|
|
494
688
|
r"""Use Tavily Search API to search information for the given query.
|
|
495
689
|
|
|
496
690
|
Args:
|
|
497
691
|
query (str): The query to be searched.
|
|
498
|
-
|
|
499
|
-
|
|
692
|
+
number_of_result_pages (int): The number of result pages to
|
|
693
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
694
|
+
for focused searches and more for comprehensive searches.
|
|
695
|
+
(default: :obj:`10`)
|
|
500
696
|
**kwargs: Additional optional parameters supported by Tavily's API:
|
|
501
697
|
- search_depth (str): "basic" or "advanced" search depth.
|
|
502
698
|
- topic (str): The search category, e.g., "general" or "news."
|
|
@@ -532,7 +728,9 @@ class SearchToolkit(BaseToolkit):
|
|
|
532
728
|
client = TavilyClient(Tavily_API_KEY)
|
|
533
729
|
|
|
534
730
|
try:
|
|
535
|
-
results = client.search(
|
|
731
|
+
results = client.search(
|
|
732
|
+
query, max_results=number_of_result_pages, **kwargs
|
|
733
|
+
)
|
|
536
734
|
return results
|
|
537
735
|
except Exception as e:
|
|
538
736
|
return [{"error": f"An unexpected error occurred: {e!s}"}]
|
|
@@ -543,8 +741,8 @@ class SearchToolkit(BaseToolkit):
|
|
|
543
741
|
query: str,
|
|
544
742
|
freshness: str = "noLimit",
|
|
545
743
|
summary: bool = False,
|
|
546
|
-
count: int = 10,
|
|
547
744
|
page: int = 1,
|
|
745
|
+
number_of_result_pages: int = 10,
|
|
548
746
|
) -> Dict[str, Any]:
|
|
549
747
|
r"""Query the Bocha AI search API and return search results.
|
|
550
748
|
|
|
@@ -559,8 +757,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
559
757
|
- 'oneYear': past year.
|
|
560
758
|
summary (bool): Whether to include text summaries in results.
|
|
561
759
|
Default is False.
|
|
562
|
-
count (int): Number of results to return (1-50). Default is 10.
|
|
563
760
|
page (int): Page number of results. Default is 1.
|
|
761
|
+
number_of_result_pages (int): The number of result pages to
|
|
762
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
763
|
+
for focused searches and more for comprehensive searches.
|
|
764
|
+
(default: :obj:`10`)
|
|
564
765
|
|
|
565
766
|
Returns:
|
|
566
767
|
Dict[str, Any]: A dictionary containing search results, including
|
|
@@ -582,7 +783,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
582
783
|
"query": query,
|
|
583
784
|
"freshness": freshness,
|
|
584
785
|
"summary": summary,
|
|
585
|
-
"count":
|
|
786
|
+
"count": number_of_result_pages,
|
|
586
787
|
"page": page,
|
|
587
788
|
},
|
|
588
789
|
ensure_ascii=False,
|
|
@@ -600,15 +801,19 @@ class SearchToolkit(BaseToolkit):
|
|
|
600
801
|
except requests.exceptions.RequestException as e:
|
|
601
802
|
return {"error": f"Bocha AI search failed: {e!s}"}
|
|
602
803
|
|
|
603
|
-
def search_baidu(
|
|
804
|
+
def search_baidu(
|
|
805
|
+
self, query: str, number_of_result_pages: int = 10
|
|
806
|
+
) -> Dict[str, Any]:
|
|
604
807
|
r"""Search Baidu using web scraping to retrieve relevant search
|
|
605
808
|
results. This method queries Baidu's search engine and extracts search
|
|
606
809
|
results including titles, descriptions, and URLs.
|
|
607
810
|
|
|
608
811
|
Args:
|
|
609
812
|
query (str): Search query string to submit to Baidu.
|
|
610
|
-
|
|
611
|
-
|
|
813
|
+
number_of_result_pages (int): The number of result pages to
|
|
814
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
815
|
+
for focused searches and more for comprehensive searches.
|
|
816
|
+
(default: :obj:`10`)
|
|
612
817
|
|
|
613
818
|
Returns:
|
|
614
819
|
Dict[str, Any]: A dictionary containing search results or error
|
|
@@ -626,7 +831,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
626
831
|
),
|
|
627
832
|
"Referer": "https://www.baidu.com",
|
|
628
833
|
}
|
|
629
|
-
params = {"wd": query, "rn": str(
|
|
834
|
+
params = {"wd": query, "rn": str(number_of_result_pages)}
|
|
630
835
|
|
|
631
836
|
response = requests.get(url, headers=headers, params=params)
|
|
632
837
|
response.encoding = "utf-8"
|
|
@@ -655,7 +860,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
655
860
|
"url": link,
|
|
656
861
|
}
|
|
657
862
|
)
|
|
658
|
-
if len(results) >=
|
|
863
|
+
if len(results) >= number_of_result_pages:
|
|
659
864
|
break
|
|
660
865
|
|
|
661
866
|
if not results:
|
|
@@ -669,7 +874,9 @@ class SearchToolkit(BaseToolkit):
|
|
|
669
874
|
except Exception as e:
|
|
670
875
|
return {"error": f"Baidu scraping error: {e!s}"}
|
|
671
876
|
|
|
672
|
-
def search_bing(
|
|
877
|
+
def search_bing(
|
|
878
|
+
self, query: str, number_of_result_pages: int = 10
|
|
879
|
+
) -> Dict[str, Any]:
|
|
673
880
|
r"""Use Bing search engine to search information for the given query.
|
|
674
881
|
|
|
675
882
|
This function queries the Chinese version of Bing search engine (cn.
|
|
@@ -681,8 +888,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
681
888
|
Args:
|
|
682
889
|
query (str): The search query string to submit to Bing. Works best
|
|
683
890
|
with Chinese queries or when Chinese results are preferred.
|
|
684
|
-
|
|
685
|
-
|
|
891
|
+
number_of_result_pages (int): The number of result pages to
|
|
892
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
893
|
+
for focused searches and more for comprehensive searches.
|
|
894
|
+
(default: :obj:`10`)
|
|
686
895
|
|
|
687
896
|
Returns:
|
|
688
897
|
Dict ([str, Any]): A dictionary containing either:
|
|
@@ -732,7 +941,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
732
941
|
result_items = b_results_tag.find_all("li")
|
|
733
942
|
|
|
734
943
|
results: List[Dict[str, Any]] = []
|
|
735
|
-
for i in range(min(len(result_items),
|
|
944
|
+
for i in range(min(len(result_items), number_of_result_pages)):
|
|
736
945
|
row = result_items[i]
|
|
737
946
|
if not isinstance(row, Tag):
|
|
738
947
|
continue
|
|
@@ -797,11 +1006,11 @@ class SearchToolkit(BaseToolkit):
|
|
|
797
1006
|
"financial report",
|
|
798
1007
|
]
|
|
799
1008
|
] = None,
|
|
800
|
-
num_results: int = 10,
|
|
801
1009
|
include_text: Optional[List[str]] = None,
|
|
802
1010
|
exclude_text: Optional[List[str]] = None,
|
|
803
1011
|
use_autoprompt: bool = True,
|
|
804
1012
|
text: bool = False,
|
|
1013
|
+
number_of_result_pages: int = 10,
|
|
805
1014
|
) -> Dict[str, Any]:
|
|
806
1015
|
r"""Use Exa search API to perform intelligent web search with optional
|
|
807
1016
|
content extraction.
|
|
@@ -813,8 +1022,6 @@ class SearchToolkit(BaseToolkit):
|
|
|
813
1022
|
and neural search. (default: :obj:`"auto"`)
|
|
814
1023
|
category (Optional[Literal]): Category to focus the search on, such
|
|
815
1024
|
as "research paper" or "news". (default: :obj:`None`)
|
|
816
|
-
num_results (int): Number of results to return (max 100).
|
|
817
|
-
(default: :obj:`10`)
|
|
818
1025
|
include_text (Optional[List[str]]): Strings that must be present in
|
|
819
1026
|
webpage text. Limited to 1 string of up to 5 words.
|
|
820
1027
|
(default: :obj:`None`)
|
|
@@ -825,6 +1032,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
825
1032
|
enhance the query. (default: :obj:`True`)
|
|
826
1033
|
text (bool): Whether to include webpage contents in results.
|
|
827
1034
|
(default: :obj:`False`)
|
|
1035
|
+
number_of_result_pages (int): The number of result pages to
|
|
1036
|
+
retrieve. Must be between 1 and 100. Adjust this based on
|
|
1037
|
+
your task - use fewer results for focused searches and more
|
|
1038
|
+
for comprehensive searches. (default: :obj:`10`)
|
|
828
1039
|
|
|
829
1040
|
Returns:
|
|
830
1041
|
Dict[str, Any]: A dict containing search results and metadata:
|
|
@@ -843,7 +1054,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
843
1054
|
try:
|
|
844
1055
|
exa = Exa(EXA_API_KEY)
|
|
845
1056
|
|
|
846
|
-
if
|
|
1057
|
+
if (
|
|
1058
|
+
number_of_result_pages is not None
|
|
1059
|
+
and not 0 < number_of_result_pages <= 100
|
|
1060
|
+
):
|
|
847
1061
|
raise ValueError("num_results must be between 1 and 100")
|
|
848
1062
|
|
|
849
1063
|
if include_text is not None:
|
|
@@ -870,7 +1084,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
870
1084
|
query=query,
|
|
871
1085
|
type=search_type,
|
|
872
1086
|
category=category,
|
|
873
|
-
num_results=
|
|
1087
|
+
num_results=number_of_result_pages,
|
|
874
1088
|
include_text=include_text,
|
|
875
1089
|
exclude_text=exclude_text,
|
|
876
1090
|
use_autoprompt=use_autoprompt,
|
|
@@ -884,7 +1098,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
884
1098
|
query=query,
|
|
885
1099
|
type=search_type,
|
|
886
1100
|
category=category,
|
|
887
|
-
num_results=
|
|
1101
|
+
num_results=number_of_result_pages,
|
|
888
1102
|
include_text=include_text,
|
|
889
1103
|
exclude_text=exclude_text,
|
|
890
1104
|
use_autoprompt=use_autoprompt,
|
|
@@ -914,10 +1128,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
914
1128
|
"news_center",
|
|
915
1129
|
]
|
|
916
1130
|
] = None,
|
|
917
|
-
page: int = 1,
|
|
918
1131
|
return_main_text: bool = False,
|
|
919
1132
|
return_markdown_text: bool = True,
|
|
920
1133
|
enable_rerank: bool = True,
|
|
1134
|
+
number_of_result_pages: int = 10,
|
|
921
1135
|
) -> Dict[str, Any]:
|
|
922
1136
|
r"""Query the Alibaba Tongxiao search API and return search results.
|
|
923
1137
|
|
|
@@ -931,17 +1145,14 @@ class SearchToolkit(BaseToolkit):
|
|
|
931
1145
|
|
|
932
1146
|
Args:
|
|
933
1147
|
query (str): The search query string (length >= 1 and <= 100).
|
|
934
|
-
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear",
|
|
935
|
-
|
|
1148
|
+
time_range (Literal["OneDay", "OneWeek", "OneMonth", "OneYear", "NoLimit"]):
|
|
1149
|
+
Time frame filter for search results.
|
|
936
1150
|
(default: :obj:`"NoLimit"`)
|
|
937
|
-
industry (Optional[Literal["finance", "law", "medical",
|
|
938
|
-
"internet", "tax", "news_province", "news_center"]]):
|
|
1151
|
+
industry (Optional[Literal["finance", "law", "medical", "internet", "tax", "news_province", "news_center"]]):
|
|
939
1152
|
Industry-specific search filter. When specified, only returns
|
|
940
1153
|
results from sites in the specified industries. Multiple
|
|
941
1154
|
industries can be comma-separated.
|
|
942
1155
|
(default: :obj:`None`)
|
|
943
|
-
page (int): Page number for results pagination.
|
|
944
|
-
(default: :obj:`1`)
|
|
945
1156
|
return_main_text (bool): Whether to include the main text of the
|
|
946
1157
|
webpage in results. (default: :obj:`True`)
|
|
947
1158
|
return_markdown_text (bool): Whether to include markdown formatted
|
|
@@ -949,6 +1160,10 @@ class SearchToolkit(BaseToolkit):
|
|
|
949
1160
|
enable_rerank (bool): Whether to enable result reranking. If
|
|
950
1161
|
response time is critical, setting this to False can reduce
|
|
951
1162
|
response time by approximately 140ms. (default: :obj:`True`)
|
|
1163
|
+
number_of_result_pages (int): The number of result pages to
|
|
1164
|
+
retrieve. Adjust this based on your task - use fewer results
|
|
1165
|
+
for focused searches and more for comprehensive searches.
|
|
1166
|
+
(default: :obj:`10`)
|
|
952
1167
|
|
|
953
1168
|
Returns:
|
|
954
1169
|
Dict[str, Any]: A dictionary containing either search results with
|
|
@@ -974,7 +1189,7 @@ class SearchToolkit(BaseToolkit):
|
|
|
974
1189
|
params: Dict[str, Union[str, int]] = {
|
|
975
1190
|
"query": query,
|
|
976
1191
|
"timeRange": time_range,
|
|
977
|
-
"page":
|
|
1192
|
+
"page": number_of_result_pages,
|
|
978
1193
|
"returnMainText": str(return_main_text).lower(),
|
|
979
1194
|
"returnMarkdownText": str(return_markdown_text).lower(),
|
|
980
1195
|
"enableRerank": str(enable_rerank).lower(),
|
|
@@ -1062,6 +1277,172 @@ class SearchToolkit(BaseToolkit):
|
|
|
1062
1277
|
f"search: {e!s}"
|
|
1063
1278
|
}
|
|
1064
1279
|
|
|
1280
|
+
@api_keys_required([(None, 'METASO_API_KEY')])
|
|
1281
|
+
def search_metaso(
|
|
1282
|
+
self,
|
|
1283
|
+
query: str,
|
|
1284
|
+
page: int = 1,
|
|
1285
|
+
include_summary: bool = False,
|
|
1286
|
+
include_raw_content: bool = False,
|
|
1287
|
+
concise_snippet: bool = False,
|
|
1288
|
+
scope: Literal[
|
|
1289
|
+
"webpage", "document", "scholar", "image", "video", "podcast"
|
|
1290
|
+
] = "webpage",
|
|
1291
|
+
) -> Dict[str, Any]:
|
|
1292
|
+
r"""Perform a web search using the metaso.cn API.
|
|
1293
|
+
|
|
1294
|
+
Args:
|
|
1295
|
+
query (str): The search query string.
|
|
1296
|
+
page (int): Page number. (default: :obj:`1`)
|
|
1297
|
+
include_summary (bool): Whether to include summary in the result.
|
|
1298
|
+
(default: :obj:`False`)
|
|
1299
|
+
include_raw_content (bool): Whether to include raw content in the
|
|
1300
|
+
result. (default: :obj:`False`)
|
|
1301
|
+
concise_snippet (bool): Whether to return concise snippet.
|
|
1302
|
+
(default: :obj:`False`)
|
|
1303
|
+
scope (Literal["webpage", "document", "scholar", "image", "video",
|
|
1304
|
+
"podcast"]): Search scope. (default: :obj:`"webpage"`)
|
|
1305
|
+
|
|
1306
|
+
Returns:
|
|
1307
|
+
Dict[str, Any]: Search results or error information.
|
|
1308
|
+
"""
|
|
1309
|
+
import http.client
|
|
1310
|
+
import json
|
|
1311
|
+
|
|
1312
|
+
# It is recommended to put the token in environment variable for
|
|
1313
|
+
# security
|
|
1314
|
+
|
|
1315
|
+
METASO_API_KEY = os.getenv("METASO_API_KEY")
|
|
1316
|
+
|
|
1317
|
+
conn = http.client.HTTPSConnection("metaso.cn")
|
|
1318
|
+
payload = json.dumps(
|
|
1319
|
+
{
|
|
1320
|
+
"q": query,
|
|
1321
|
+
"scope": scope,
|
|
1322
|
+
"includeSummary": include_summary,
|
|
1323
|
+
"page": str(page),
|
|
1324
|
+
"includeRawContent": include_raw_content,
|
|
1325
|
+
"conciseSnippet": concise_snippet,
|
|
1326
|
+
}
|
|
1327
|
+
)
|
|
1328
|
+
headers = {
|
|
1329
|
+
'Authorization': f'Bearer {METASO_API_KEY}',
|
|
1330
|
+
'Accept': 'application/json',
|
|
1331
|
+
'Content-Type': 'application/json',
|
|
1332
|
+
}
|
|
1333
|
+
try:
|
|
1334
|
+
conn.request("POST", "/api/v1/search", payload, headers)
|
|
1335
|
+
res = conn.getresponse()
|
|
1336
|
+
data = res.read()
|
|
1337
|
+
result = data.decode("utf-8")
|
|
1338
|
+
try:
|
|
1339
|
+
return json.loads(result)
|
|
1340
|
+
except Exception:
|
|
1341
|
+
return {
|
|
1342
|
+
"error": f"Metaso returned content could not be parsed: {result}"
|
|
1343
|
+
}
|
|
1344
|
+
except Exception as e:
|
|
1345
|
+
return {"error": f"Metaso search failed: {e}"}
|
|
1346
|
+
|
|
1347
|
+
@dependencies_required("google-search-results")
|
|
1348
|
+
@api_keys_required([(None, 'SERPAPI_KEY')])
|
|
1349
|
+
def search_serpapi(
|
|
1350
|
+
self,
|
|
1351
|
+
query: str,
|
|
1352
|
+
engine: str = "google",
|
|
1353
|
+
location: str = "Austin,Texas",
|
|
1354
|
+
google_domain: str = "google.com",
|
|
1355
|
+
gl: str = "us",
|
|
1356
|
+
search_lang: str = "en",
|
|
1357
|
+
device: str = "desktop",
|
|
1358
|
+
number_of_result_pages: int = 1,
|
|
1359
|
+
safe: str = "off",
|
|
1360
|
+
filter: int = 0,
|
|
1361
|
+
custom_params: Optional[Dict[str, Any]] = None,
|
|
1362
|
+
) -> Dict[str, Any]:
|
|
1363
|
+
r"""Use SerpApi search engine to search information for the given query.
|
|
1364
|
+
|
|
1365
|
+
SerpApi provides real-time search engine results from multiple search engines
|
|
1366
|
+
including Google, Bing, Yahoo, DuckDuckGo, Baidu, Yandex, and more.
|
|
1367
|
+
|
|
1368
|
+
Args:
|
|
1369
|
+
query (str): The search query string.
|
|
1370
|
+
engine (str): Search engine to use. Supported engines include:
|
|
1371
|
+
'google', 'bing', 'yahoo', 'duckduckgo', 'baidu', 'yandex',
|
|
1372
|
+
'youtube', 'ebay', 'amazon', etc. (default: :obj:`"google"`)
|
|
1373
|
+
location (str): Location for localized search results. Can be a city,
|
|
1374
|
+
state, country, or coordinates. (default: :obj:`"Austin,Texas"`)
|
|
1375
|
+
google_domain (str): Google domain to use (e.g., 'google.com', 'google.co.uk').
|
|
1376
|
+
Only applicable for Google engine. (default: :obj:`"google.com"`)
|
|
1377
|
+
gl (str): Country code for localized results (e.g., 'us', 'uk', 'ca').
|
|
1378
|
+
Only applicable for Google engine. (default: :obj:`"us"`)
|
|
1379
|
+
search_lang (str): Language code for results (e.g., 'en', 'es', 'fr').
|
|
1380
|
+
Only applicable for Google engine. (default: :obj:`"en"`)
|
|
1381
|
+
device (str): Device type: 'desktop', 'tablet', or 'mobile'.
|
|
1382
|
+
(default: :obj:`"desktop"`)
|
|
1383
|
+
number_of_result_pages (int): Number of organic results to return.
|
|
1384
|
+
Adjust based on task needs. (default: :obj:`1`)
|
|
1385
|
+
safe (str): Safe search level: 'off', 'medium', 'high', 'active'.
|
|
1386
|
+
(default: :obj:`"off"`)
|
|
1387
|
+
filter (int): Filter results: 0 (no filter), 1 (filter similar results).
|
|
1388
|
+
(default: :obj:`0`)
|
|
1389
|
+
custom_params (Optional[Dict[str, Any]]): Additional custom parameters
|
|
1390
|
+
to pass to SerpApi. (default: :obj:`None`)
|
|
1391
|
+
|
|
1392
|
+
Returns:
|
|
1393
|
+
Dict[str, Any]: A dictionary containing search results:
|
|
1394
|
+
- 'results': List of organic search results, each containing:
|
|
1395
|
+
- 'title': The title of the search result
|
|
1396
|
+
- 'link': The URL of the search result
|
|
1397
|
+
- 'snippet': The description snippet
|
|
1398
|
+
- 'keywords': Highlighted keywords in the snippet
|
|
1399
|
+
- 'source': The source of the result
|
|
1400
|
+
- 'error: Error if any
|
|
1401
|
+
"""
|
|
1402
|
+
from serpapi import SerpApiClient
|
|
1403
|
+
|
|
1404
|
+
SerpApiClient.SERP_API_KEY = os.getenv("SERPAPI_KEY")
|
|
1405
|
+
params = {
|
|
1406
|
+
"engine": engine,
|
|
1407
|
+
"q": query,
|
|
1408
|
+
"location": location,
|
|
1409
|
+
"google_domain": google_domain,
|
|
1410
|
+
"gl": gl,
|
|
1411
|
+
"hl": search_lang,
|
|
1412
|
+
"device": device,
|
|
1413
|
+
"num": number_of_result_pages,
|
|
1414
|
+
"safe": safe,
|
|
1415
|
+
"filter": filter,
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if custom_params is not None:
|
|
1419
|
+
params.update(custom_params)
|
|
1420
|
+
try:
|
|
1421
|
+
search = SerpApiClient(params)
|
|
1422
|
+
results = search.get_dict()
|
|
1423
|
+
|
|
1424
|
+
if (
|
|
1425
|
+
"organic_results" not in results
|
|
1426
|
+
or not results["organic_results"]
|
|
1427
|
+
):
|
|
1428
|
+
return {"error": "No organic results found"}
|
|
1429
|
+
|
|
1430
|
+
formatted_results = []
|
|
1431
|
+
for result in results['organic_results']:
|
|
1432
|
+
formatted_result = {
|
|
1433
|
+
"title": result.get("title", ""),
|
|
1434
|
+
"link": result.get("link", ""),
|
|
1435
|
+
"snippet": result.get("snippet", ""),
|
|
1436
|
+
"keywords": result.get("snippet_highlighted_words", []),
|
|
1437
|
+
"source": result.get("source", ""),
|
|
1438
|
+
}
|
|
1439
|
+
formatted_results.append(formatted_result)
|
|
1440
|
+
|
|
1441
|
+
return {"results": formatted_results}
|
|
1442
|
+
|
|
1443
|
+
except Exception as e:
|
|
1444
|
+
return {"error": f"SerpApi search failed: {e!s}"}
|
|
1445
|
+
|
|
1065
1446
|
def get_tools(self) -> List[FunctionTool]:
|
|
1066
1447
|
r"""Returns a list of FunctionTool objects representing the
|
|
1067
1448
|
functions in the toolkit.
|
|
@@ -1075,11 +1456,23 @@ class SearchToolkit(BaseToolkit):
|
|
|
1075
1456
|
FunctionTool(self.search_linkup),
|
|
1076
1457
|
FunctionTool(self.search_google),
|
|
1077
1458
|
FunctionTool(self.search_duckduckgo),
|
|
1078
|
-
FunctionTool(self.
|
|
1459
|
+
FunctionTool(self.search_tavily),
|
|
1079
1460
|
FunctionTool(self.search_brave),
|
|
1080
1461
|
FunctionTool(self.search_bocha),
|
|
1081
1462
|
FunctionTool(self.search_baidu),
|
|
1082
1463
|
FunctionTool(self.search_bing),
|
|
1083
1464
|
FunctionTool(self.search_exa),
|
|
1084
1465
|
FunctionTool(self.search_alibaba_tongxiao),
|
|
1466
|
+
FunctionTool(self.search_metaso),
|
|
1467
|
+
FunctionTool(self.search_serpapi),
|
|
1085
1468
|
]
|
|
1469
|
+
|
|
1470
|
+
# Deprecated method alias for backward compatibility
|
|
1471
|
+
def tavily_search(self, *args, **kwargs):
|
|
1472
|
+
r"""Deprecated: Use search_tavily instead for consistency with other search methods."""
|
|
1473
|
+
warnings.warn(
|
|
1474
|
+
"tavily_search is deprecated. Use search_tavily instead for consistency.",
|
|
1475
|
+
DeprecationWarning,
|
|
1476
|
+
stacklevel=2,
|
|
1477
|
+
)
|
|
1478
|
+
return self.search_tavily(*args, **kwargs)
|