camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- camel/__init__.py +1 -1
- camel/agents/_types.py +6 -2
- camel/agents/_utils.py +38 -0
- camel/agents/chat_agent.py +4014 -410
- camel/agents/mcp_agent.py +30 -27
- camel/agents/repo_agent.py +2 -1
- camel/benchmarks/browsecomp.py +6 -6
- camel/configs/__init__.py +15 -0
- camel/configs/aihubmix_config.py +88 -0
- camel/configs/amd_config.py +70 -0
- camel/configs/cometapi_config.py +104 -0
- camel/configs/minimax_config.py +93 -0
- camel/configs/nebius_config.py +103 -0
- camel/configs/vllm_config.py +2 -0
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/datagen/self_improving_cot.py +1 -1
- camel/datasets/base_generator.py +39 -10
- camel/environments/__init__.py +12 -0
- camel/environments/rlcards_env.py +860 -0
- camel/environments/single_step.py +28 -3
- camel/environments/tic_tac_toe.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker/Dockerfile +4 -16
- camel/interpreters/docker_interpreter.py +3 -2
- camel/interpreters/e2b_interpreter.py +34 -1
- camel/interpreters/internal_python_interpreter.py +51 -2
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/loaders/__init__.py +11 -2
- camel/loaders/base_loader.py +85 -0
- camel/loaders/chunkr_reader.py +9 -0
- camel/loaders/firecrawl_reader.py +4 -4
- camel/logger.py +1 -1
- camel/memories/agent_memories.py +84 -1
- camel/memories/base.py +34 -0
- camel/memories/blocks/chat_history_block.py +122 -4
- camel/memories/blocks/vectordb_block.py +8 -1
- camel/memories/context_creators/score_based.py +29 -237
- camel/memories/records.py +88 -8
- camel/messages/base.py +166 -40
- camel/messages/func_message.py +32 -5
- camel/models/__init__.py +10 -0
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +1 -16
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +117 -18
- camel/models/aws_bedrock_model.py +2 -33
- camel/models/azure_openai_model.py +205 -91
- camel/models/base_audio_model.py +3 -1
- camel/models/base_model.py +189 -24
- camel/models/cohere_model.py +5 -17
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +1 -16
- camel/models/deepseek_model.py +6 -16
- camel/models/fish_audio_model.py +6 -0
- camel/models/gemini_model.py +71 -20
- camel/models/groq_model.py +1 -17
- camel/models/internlm_model.py +1 -16
- camel/models/litellm_model.py +49 -32
- camel/models/lmstudio_model.py +1 -17
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +1 -16
- camel/models/model_factory.py +27 -1
- camel/models/model_manager.py +24 -6
- camel/models/modelscope_model.py +1 -16
- camel/models/moonshot_model.py +185 -19
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +0 -5
- camel/models/netmind_model.py +1 -16
- camel/models/novita_model.py +1 -16
- camel/models/nvidia_model.py +1 -16
- camel/models/ollama_model.py +4 -19
- camel/models/openai_compatible_model.py +171 -46
- camel/models/openai_model.py +205 -77
- camel/models/openrouter_model.py +1 -17
- camel/models/ppio_model.py +1 -16
- camel/models/qianfan_model.py +1 -16
- camel/models/qwen_model.py +1 -16
- camel/models/reka_model.py +1 -16
- camel/models/samba_model.py +34 -47
- camel/models/sglang_model.py +64 -31
- camel/models/siliconflow_model.py +1 -16
- camel/models/stub_model.py +0 -4
- camel/models/togetherai_model.py +1 -16
- camel/models/vllm_model.py +1 -16
- camel/models/volcano_model.py +0 -17
- camel/models/watsonx_model.py +1 -16
- camel/models/yi_model.py +1 -16
- camel/models/zhipuai_model.py +60 -16
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/runtimes/configs.py +11 -11
- camel/runtimes/daytona_runtime.py +15 -16
- camel/runtimes/docker_runtime.py +6 -6
- camel/runtimes/remote_http_runtime.py +5 -5
- camel/services/agent_openapi_server.py +380 -0
- camel/societies/__init__.py +2 -0
- camel/societies/role_playing.py +26 -28
- camel/societies/workforce/__init__.py +2 -0
- camel/societies/workforce/events.py +122 -0
- camel/societies/workforce/prompts.py +249 -38
- camel/societies/workforce/role_playing_worker.py +82 -20
- camel/societies/workforce/single_agent_worker.py +634 -34
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +169 -23
- camel/societies/workforce/utils.py +176 -9
- camel/societies/workforce/worker.py +77 -23
- camel/societies/workforce/workflow_memory_manager.py +772 -0
- camel/societies/workforce/workforce.py +3168 -478
- camel/societies/workforce/workforce_callback.py +74 -0
- camel/societies/workforce/workforce_logger.py +203 -175
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/__init__.py +4 -0
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/key_value_storages/mem0_cloud.py +48 -47
- camel/storages/object_storages/google_cloud.py +1 -1
- camel/storages/vectordb_storages/__init__.py +6 -0
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/oceanbase.py +13 -13
- camel/storages/vectordb_storages/pgvector.py +349 -0
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/storages/vectordb_storages/surreal.py +365 -0
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/tasks/task.py +244 -27
- camel/toolkits/__init__.py +46 -8
- camel/toolkits/aci_toolkit.py +64 -19
- camel/toolkits/arxiv_toolkit.py +6 -6
- camel/toolkits/base.py +63 -5
- camel/toolkits/code_execution.py +28 -1
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/craw4ai_toolkit.py +93 -0
- camel/toolkits/dappier_toolkit.py +10 -6
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
- camel/toolkits/excel_toolkit.py +901 -67
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +30 -6
- camel/toolkits/github_toolkit.py +107 -20
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +38 -4
- camel/toolkits/google_drive_mcp_toolkit.py +54 -0
- camel/toolkits/human_toolkit.py +34 -10
- 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 +3749 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -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 +130 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -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_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +3 -4
- camel/toolkits/klavis_toolkit.py +5 -1
- camel/toolkits/markitdown_toolkit.py +104 -0
- camel/toolkits/math_toolkit.py +64 -10
- camel/toolkits/mcp_toolkit.py +370 -45
- camel/toolkits/memory_toolkit.py +5 -1
- camel/toolkits/message_agent_toolkit.py +608 -0
- camel/toolkits/message_integration.py +724 -0
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/note_taking_toolkit.py +277 -0
- camel/toolkits/notion_mcp_toolkit.py +224 -0
- camel/toolkits/openbb_toolkit.py +5 -1
- camel/toolkits/origene_mcp_toolkit.py +56 -0
- camel/toolkits/playwright_mcp_toolkit.py +12 -31
- camel/toolkits/pptx_toolkit.py +25 -12
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/screenshot_toolkit.py +213 -0
- camel/toolkits/search_toolkit.py +437 -142
- camel/toolkits/slack_toolkit.py +104 -50
- camel/toolkits/sympy_toolkit.py +1 -1
- camel/toolkits/task_planning_toolkit.py +3 -3
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/thinking_toolkit.py +1 -1
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +106 -26
- camel/toolkits/video_download_toolkit.py +17 -14
- camel/toolkits/web_deploy_toolkit.py +1219 -0
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/zapier_toolkit.py +5 -1
- camel/types/__init__.py +2 -2
- camel/types/agents/tool_calling_record.py +4 -1
- camel/types/enums.py +316 -40
- camel/types/openai_types.py +2 -2
- camel/types/unified_model_type.py +31 -4
- camel/utils/commons.py +36 -5
- camel/utils/constants.py +3 -0
- camel/utils/context_utils.py +1003 -0
- camel/utils/mcp.py +138 -4
- camel/utils/mcp_client.py +45 -1
- camel/utils/message_summarizer.py +148 -0
- camel/utils/token_counting.py +43 -20
- camel/utils/tool_result.py +44 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
- 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.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
camel/tasks/task.py
CHANGED
|
@@ -19,16 +19,21 @@ from typing import (
|
|
|
19
19
|
Any,
|
|
20
20
|
Callable,
|
|
21
21
|
Dict,
|
|
22
|
+
Generator,
|
|
22
23
|
List,
|
|
23
24
|
Literal,
|
|
24
25
|
Optional,
|
|
25
26
|
Union,
|
|
26
27
|
)
|
|
27
28
|
|
|
28
|
-
from
|
|
29
|
+
from PIL import Image
|
|
30
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
29
31
|
|
|
30
32
|
if TYPE_CHECKING:
|
|
31
33
|
from camel.agents import ChatAgent
|
|
34
|
+
from camel.agents.chat_agent import StreamingChatAgentResponse
|
|
35
|
+
import uuid
|
|
36
|
+
|
|
32
37
|
from camel.logger import get_logger
|
|
33
38
|
from camel.messages import BaseMessage
|
|
34
39
|
from camel.prompts import TextPrompt
|
|
@@ -43,19 +48,35 @@ from .task_prompt import (
|
|
|
43
48
|
logger = get_logger(__name__)
|
|
44
49
|
|
|
45
50
|
|
|
51
|
+
class TaskValidationMode(Enum):
|
|
52
|
+
r"""Validation modes for different use cases."""
|
|
53
|
+
|
|
54
|
+
INPUT = "input" # For validating task content before processing
|
|
55
|
+
OUTPUT = "output" # For validating task results after completion
|
|
56
|
+
|
|
57
|
+
|
|
46
58
|
def validate_task_content(
|
|
47
|
-
content: str,
|
|
59
|
+
content: str,
|
|
60
|
+
task_id: str = "unknown",
|
|
61
|
+
min_length: int = 1,
|
|
62
|
+
mode: TaskValidationMode = TaskValidationMode.INPUT,
|
|
63
|
+
check_failure_patterns: bool = True,
|
|
48
64
|
) -> bool:
|
|
49
|
-
r"""
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
r"""Unified validation for task content and results to avoid silent
|
|
66
|
+
failures. Performs comprehensive checks to ensure content meets quality
|
|
67
|
+
standards.
|
|
52
68
|
|
|
53
69
|
Args:
|
|
54
|
-
content (str): The task result
|
|
70
|
+
content (str): The task content or result to validate.
|
|
55
71
|
task_id (str): Task ID for logging purposes.
|
|
56
72
|
(default: :obj:`"unknown"`)
|
|
57
73
|
min_length (int): Minimum content length after stripping whitespace.
|
|
58
|
-
(default: :obj:`
|
|
74
|
+
(default: :obj:`1`)
|
|
75
|
+
mode (TaskValidationMode): Validation mode - INPUT for task content,
|
|
76
|
+
OUTPUT for task results. (default: :obj:`TaskValidationMode.INPUT`)
|
|
77
|
+
check_failure_patterns (bool): Whether to check for failure indicators
|
|
78
|
+
in the content. Only effective in OUTPUT mode.
|
|
79
|
+
(default: :obj:`True`)
|
|
59
80
|
|
|
60
81
|
Returns:
|
|
61
82
|
bool: True if content passes validation, False otherwise.
|
|
@@ -78,18 +99,74 @@ def validate_task_content(
|
|
|
78
99
|
logger.warning(
|
|
79
100
|
f"Task {task_id}: Content too short ({len(stripped_content)} "
|
|
80
101
|
f"chars < {min_length} minimum). Content preview: "
|
|
81
|
-
f"'{stripped_content
|
|
102
|
+
f"'{stripped_content}'"
|
|
82
103
|
)
|
|
83
104
|
return False
|
|
84
105
|
|
|
106
|
+
# 4: For OUTPUT mode, check for failure patterns if enabled
|
|
107
|
+
if mode == TaskValidationMode.OUTPUT and check_failure_patterns:
|
|
108
|
+
content_lower = stripped_content.lower()
|
|
109
|
+
|
|
110
|
+
# Check for explicit failure indicators
|
|
111
|
+
failure_indicators = [
|
|
112
|
+
"i cannot complete",
|
|
113
|
+
"i cannot do",
|
|
114
|
+
"task failed",
|
|
115
|
+
"unable to complete",
|
|
116
|
+
"cannot be completed",
|
|
117
|
+
"failed to complete",
|
|
118
|
+
"i cannot",
|
|
119
|
+
"not possible",
|
|
120
|
+
"impossible to",
|
|
121
|
+
"cannot perform",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
if any(indicator in content_lower for indicator in failure_indicators):
|
|
125
|
+
logger.warning(
|
|
126
|
+
f"Task {task_id}: Failure indicator detected in result. "
|
|
127
|
+
f"Content preview: '{stripped_content}'"
|
|
128
|
+
)
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
# Check for responses that are just error messages or refusals
|
|
132
|
+
if content_lower.startswith(("error", "failed", "cannot", "unable")):
|
|
133
|
+
logger.warning(
|
|
134
|
+
f"Task {task_id}: Error/refusal pattern detected at start. "
|
|
135
|
+
f"Content preview: '{stripped_content}'"
|
|
136
|
+
)
|
|
137
|
+
return False
|
|
138
|
+
|
|
85
139
|
# All validation checks passed
|
|
86
140
|
logger.debug(
|
|
87
|
-
f"Task {task_id}:
|
|
141
|
+
f"Task {task_id}: {mode.value} validation passed "
|
|
88
142
|
f"({len(stripped_content)} chars)"
|
|
89
143
|
)
|
|
90
144
|
return True
|
|
91
145
|
|
|
92
146
|
|
|
147
|
+
def is_task_result_insufficient(task: "Task") -> bool:
|
|
148
|
+
r"""Check if a task result is insufficient and should be treated as failed.
|
|
149
|
+
|
|
150
|
+
This is a convenience wrapper around validate_task_content for backward
|
|
151
|
+
compatibility and semantic clarity when checking task results.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
task (Task): The task to check.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
bool: True if the result is insufficient, False otherwise.
|
|
158
|
+
"""
|
|
159
|
+
if not hasattr(task, 'result') or task.result is None:
|
|
160
|
+
return True
|
|
161
|
+
|
|
162
|
+
return not validate_task_content(
|
|
163
|
+
content=task.result,
|
|
164
|
+
task_id=task.id,
|
|
165
|
+
mode=TaskValidationMode.OUTPUT,
|
|
166
|
+
check_failure_patterns=True,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
93
170
|
def parse_response(
|
|
94
171
|
response: str, task_id: Optional[str] = None
|
|
95
172
|
) -> List["Task"]:
|
|
@@ -109,7 +186,7 @@ def parse_response(
|
|
|
109
186
|
tasks = []
|
|
110
187
|
if task_id is None:
|
|
111
188
|
task_id = "0"
|
|
112
|
-
for i, content in enumerate(tasks_content):
|
|
189
|
+
for i, content in enumerate(tasks_content, 1):
|
|
113
190
|
stripped_content = content.strip()
|
|
114
191
|
# validate subtask content before creating the task
|
|
115
192
|
if validate_task_content(stripped_content, f"{task_id}.{i}"):
|
|
@@ -118,7 +195,7 @@ def parse_response(
|
|
|
118
195
|
logger.warning(
|
|
119
196
|
f"Skipping invalid subtask {task_id}.{i} "
|
|
120
197
|
f"during decomposition: "
|
|
121
|
-
f"Content '{stripped_content
|
|
198
|
+
f"Content '{stripped_content}' failed validation"
|
|
122
199
|
)
|
|
123
200
|
return tasks
|
|
124
201
|
|
|
@@ -142,27 +219,42 @@ class Task(BaseModel):
|
|
|
142
219
|
content (str): string content for task.
|
|
143
220
|
id (str): An unique string identifier for the task. This should
|
|
144
221
|
ideally be provided by the provider/model which created the task.
|
|
145
|
-
(default: :obj
|
|
222
|
+
(default: :obj:`uuid.uuid4()`)
|
|
146
223
|
state (TaskState): The state which should be OPEN, RUNNING, DONE or
|
|
147
|
-
DELETED. (default: :obj
|
|
148
|
-
type (Optional[str]): task type. (default: :obj
|
|
224
|
+
DELETED. (default: :obj:`TaskState.FAILED`)
|
|
225
|
+
type (Optional[str]): task type. (default: :obj:`None`)
|
|
149
226
|
parent (Optional[Task]): The parent task, None for root task.
|
|
150
|
-
(default: :obj
|
|
227
|
+
(default: :obj:`None`)
|
|
151
228
|
subtasks (List[Task]): The childrent sub-tasks for the task.
|
|
152
|
-
(default: :obj
|
|
229
|
+
(default: :obj:`[]`)
|
|
153
230
|
result (Optional[str]): The answer for the task.
|
|
154
|
-
(default: :obj
|
|
231
|
+
(default: :obj:`""`)
|
|
155
232
|
failure_count (int): The failure count for the task.
|
|
156
|
-
(default: :obj
|
|
233
|
+
(default: :obj:`0`)
|
|
234
|
+
assigned_worker_id (Optional[str]): The ID of the worker assigned to
|
|
235
|
+
this task. (default: :obj:`None`)
|
|
236
|
+
dependencies (List[Task]): The dependencies for the task.
|
|
237
|
+
(default: :obj:`[]`)
|
|
157
238
|
additional_info (Optional[Dict[str, Any]]): Additional information for
|
|
158
|
-
the task. (default: :obj
|
|
239
|
+
the task. (default: :obj:`None`)
|
|
240
|
+
image_list (Optional[List[Union[Image.Image, str]]]): Optional list
|
|
241
|
+
of PIL Image objects or image URLs (strings) associated with the
|
|
242
|
+
task. (default: :obj:`None`)
|
|
243
|
+
image_detail (Literal["auto", "low", "high"]): Detail level of the
|
|
244
|
+
images associated with the task. (default: :obj:`auto`)
|
|
245
|
+
video_bytes (Optional[bytes]): Optional bytes of a video associated
|
|
246
|
+
with the task. (default: :obj:`None`)
|
|
247
|
+
video_detail (Literal["auto", "low", "high"]): Detail level of the
|
|
248
|
+
videos associated with the task. (default: :obj:`auto`)
|
|
159
249
|
"""
|
|
160
250
|
|
|
161
251
|
content: str
|
|
162
252
|
|
|
163
|
-
id: str =
|
|
253
|
+
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
164
254
|
|
|
165
|
-
state: TaskState =
|
|
255
|
+
state: TaskState = (
|
|
256
|
+
TaskState.FAILED
|
|
257
|
+
) # TODO: Add logic for OPEN in workforce.py
|
|
166
258
|
|
|
167
259
|
type: Optional[str] = None
|
|
168
260
|
|
|
@@ -174,8 +266,22 @@ class Task(BaseModel):
|
|
|
174
266
|
|
|
175
267
|
failure_count: int = 0
|
|
176
268
|
|
|
269
|
+
assigned_worker_id: Optional[str] = None
|
|
270
|
+
|
|
271
|
+
dependencies: List["Task"] = []
|
|
272
|
+
|
|
177
273
|
additional_info: Optional[Dict[str, Any]] = None
|
|
178
274
|
|
|
275
|
+
image_list: Optional[List[Union[Image.Image, str]]] = None
|
|
276
|
+
|
|
277
|
+
image_detail: Literal["auto", "low", "high"] = "auto"
|
|
278
|
+
|
|
279
|
+
video_bytes: Optional[bytes] = None
|
|
280
|
+
|
|
281
|
+
video_detail: Literal["auto", "low", "high"] = "auto"
|
|
282
|
+
|
|
283
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
284
|
+
|
|
179
285
|
def __repr__(self) -> str:
|
|
180
286
|
r"""Return a string representation of the task."""
|
|
181
287
|
content_preview = self.content
|
|
@@ -204,7 +310,9 @@ class Task(BaseModel):
|
|
|
204
310
|
|
|
205
311
|
def reset(self):
|
|
206
312
|
r"""Reset Task to initial state."""
|
|
207
|
-
self.state =
|
|
313
|
+
self.state = (
|
|
314
|
+
TaskState.FAILED
|
|
315
|
+
) # TODO: Add logic for OPEN in workforce.py
|
|
208
316
|
self.result = ""
|
|
209
317
|
|
|
210
318
|
def update_result(self, result: str):
|
|
@@ -301,9 +409,9 @@ class Task(BaseModel):
|
|
|
301
409
|
agent: "ChatAgent",
|
|
302
410
|
prompt: Optional[str] = None,
|
|
303
411
|
task_parser: Callable[[str, str], List["Task"]] = parse_response,
|
|
304
|
-
) -> List["Task"]:
|
|
305
|
-
r"""Decompose a task to a list of sub-tasks.
|
|
306
|
-
|
|
412
|
+
) -> Union[List["Task"], Generator[List["Task"], None, None]]:
|
|
413
|
+
r"""Decompose a task to a list of sub-tasks. Automatically detects
|
|
414
|
+
streaming or non-streaming based on agent configuration.
|
|
307
415
|
|
|
308
416
|
Args:
|
|
309
417
|
agent (ChatAgent): An agent that used to decompose the task.
|
|
@@ -314,7 +422,10 @@ class Task(BaseModel):
|
|
|
314
422
|
the default parse_response will be used.
|
|
315
423
|
|
|
316
424
|
Returns:
|
|
317
|
-
List[Task]
|
|
425
|
+
Union[List[Task], Generator[List[Task], None, None]]: If agent is
|
|
426
|
+
configured for streaming, returns a generator that yields lists
|
|
427
|
+
of new tasks as they are parsed. Otherwise returns a list of
|
|
428
|
+
all tasks.
|
|
318
429
|
"""
|
|
319
430
|
|
|
320
431
|
role_name = agent.role_name
|
|
@@ -326,9 +437,106 @@ class Task(BaseModel):
|
|
|
326
437
|
role_name=role_name, content=content
|
|
327
438
|
)
|
|
328
439
|
response = agent.step(msg)
|
|
440
|
+
|
|
441
|
+
# Auto-detect streaming based on response type
|
|
442
|
+
from camel.agents.chat_agent import StreamingChatAgentResponse
|
|
443
|
+
|
|
444
|
+
if isinstance(response, StreamingChatAgentResponse):
|
|
445
|
+
return self._decompose_streaming(response, task_parser)
|
|
446
|
+
else:
|
|
447
|
+
return self._decompose_non_streaming(response, task_parser)
|
|
448
|
+
|
|
449
|
+
def _decompose_streaming(
|
|
450
|
+
self,
|
|
451
|
+
response: "StreamingChatAgentResponse",
|
|
452
|
+
task_parser: Callable[[str, str], List["Task"]],
|
|
453
|
+
) -> Generator[List["Task"], None, None]:
|
|
454
|
+
r"""Handle streaming response for task decomposition.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
response: Streaming response from agent
|
|
458
|
+
task_parser: Function to parse tasks from response
|
|
459
|
+
|
|
460
|
+
Yields:
|
|
461
|
+
List[Task]: New tasks as they are parsed from streaming response
|
|
462
|
+
"""
|
|
463
|
+
accumulated_content = ""
|
|
464
|
+
yielded_count = 0
|
|
465
|
+
|
|
466
|
+
# Process streaming response
|
|
467
|
+
for chunk in response:
|
|
468
|
+
accumulated_content = chunk.msg.content
|
|
469
|
+
|
|
470
|
+
# Try to parse partial tasks from accumulated content
|
|
471
|
+
try:
|
|
472
|
+
current_tasks = self._parse_partial_tasks(accumulated_content)
|
|
473
|
+
|
|
474
|
+
# Yield new tasks if we have more than previously yielded
|
|
475
|
+
if len(current_tasks) > yielded_count:
|
|
476
|
+
new_tasks = current_tasks[yielded_count:]
|
|
477
|
+
for task in new_tasks:
|
|
478
|
+
task.additional_info = self.additional_info
|
|
479
|
+
task.parent = self
|
|
480
|
+
yield new_tasks
|
|
481
|
+
yielded_count = len(current_tasks)
|
|
482
|
+
|
|
483
|
+
except Exception:
|
|
484
|
+
# If parsing fails, continue accumulating
|
|
485
|
+
continue
|
|
486
|
+
|
|
487
|
+
# Final complete parsing
|
|
488
|
+
final_tasks = task_parser(accumulated_content, self.id)
|
|
489
|
+
for task in final_tasks:
|
|
490
|
+
task.additional_info = self.additional_info
|
|
491
|
+
task.parent = self
|
|
492
|
+
self.subtasks = final_tasks
|
|
493
|
+
|
|
494
|
+
def _decompose_non_streaming(
|
|
495
|
+
self, response, task_parser: Callable[[str, str], List["Task"]]
|
|
496
|
+
) -> List["Task"]:
|
|
497
|
+
r"""Handle non-streaming response for task decomposition.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
response: Regular response from agent
|
|
501
|
+
task_parser: Function to parse tasks from response
|
|
502
|
+
|
|
503
|
+
Returns:
|
|
504
|
+
List[Task]: All parsed tasks
|
|
505
|
+
"""
|
|
329
506
|
tasks = task_parser(response.msg.content, self.id)
|
|
330
507
|
for task in tasks:
|
|
331
508
|
task.additional_info = self.additional_info
|
|
509
|
+
task.parent = self
|
|
510
|
+
self.subtasks = tasks
|
|
511
|
+
return tasks
|
|
512
|
+
|
|
513
|
+
def _parse_partial_tasks(self, response: str) -> List["Task"]:
|
|
514
|
+
r"""Parse tasks from potentially incomplete response.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
response: Partial response content
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
List[Task]: Tasks parsed from complete <task></task> blocks
|
|
521
|
+
"""
|
|
522
|
+
pattern = r"<task>(.*?)</task>"
|
|
523
|
+
tasks_content = re.findall(pattern, response, re.DOTALL)
|
|
524
|
+
|
|
525
|
+
tasks = []
|
|
526
|
+
task_id = self.id or "0"
|
|
527
|
+
|
|
528
|
+
for i, content in enumerate(tasks_content, 1):
|
|
529
|
+
stripped_content = content.strip()
|
|
530
|
+
if validate_task_content(stripped_content, f"{task_id}.{i}"):
|
|
531
|
+
tasks.append(
|
|
532
|
+
Task(content=stripped_content, id=f"{task_id}.{i}")
|
|
533
|
+
)
|
|
534
|
+
else:
|
|
535
|
+
logger.warning(
|
|
536
|
+
f"Skipping invalid subtask {task_id}.{i} "
|
|
537
|
+
f"during streaming decomposition: "
|
|
538
|
+
f"Content '{stripped_content}' failed validation"
|
|
539
|
+
)
|
|
332
540
|
return tasks
|
|
333
541
|
|
|
334
542
|
def compose(
|
|
@@ -357,6 +565,10 @@ class Task(BaseModel):
|
|
|
357
565
|
role_name=role_name,
|
|
358
566
|
content=self.content,
|
|
359
567
|
additional_info=self.additional_info,
|
|
568
|
+
image_list=self.image_list,
|
|
569
|
+
image_detail=self.image_detail,
|
|
570
|
+
video_bytes=self.video_bytes,
|
|
571
|
+
video_detail=self.video_detail,
|
|
360
572
|
other_results=sub_tasks_result,
|
|
361
573
|
)
|
|
362
574
|
msg = BaseMessage.make_user_message(
|
|
@@ -507,7 +719,12 @@ class TaskManager:
|
|
|
507
719
|
role_name = agent.role_name
|
|
508
720
|
content = template.format(role_name=role_name, content=task.content)
|
|
509
721
|
msg = BaseMessage.make_user_message(
|
|
510
|
-
role_name=role_name,
|
|
722
|
+
role_name=role_name,
|
|
723
|
+
content=content,
|
|
724
|
+
image_list=task.image_list,
|
|
725
|
+
image_detail=task.image_detail,
|
|
726
|
+
video_bytes=task.video_bytes,
|
|
727
|
+
video_detail=task.video_detail,
|
|
511
728
|
)
|
|
512
729
|
response = agent.step(msg)
|
|
513
730
|
if task_parser is None:
|
camel/toolkits/__init__.py
CHANGED
|
@@ -23,7 +23,7 @@ from .open_api_specs.security_config import openapi_security_config
|
|
|
23
23
|
from .math_toolkit import MathToolkit
|
|
24
24
|
from .search_toolkit import SearchToolkit
|
|
25
25
|
from .weather_toolkit import WeatherToolkit
|
|
26
|
-
from .
|
|
26
|
+
from .image_generation_toolkit import ImageGenToolkit, OpenAIImageToolkit
|
|
27
27
|
from .ask_news_toolkit import AskNewsToolkit, AsyncAskNewsToolkit
|
|
28
28
|
from .linkedin_toolkit import LinkedInToolkit
|
|
29
29
|
from .reddit_toolkit import RedditToolkit
|
|
@@ -31,15 +31,18 @@ from .meshy_toolkit import MeshyToolkit
|
|
|
31
31
|
from .openbb_toolkit import OpenBBToolkit
|
|
32
32
|
from .bohrium_toolkit import BohriumToolkit
|
|
33
33
|
|
|
34
|
-
from .base import BaseToolkit
|
|
34
|
+
from .base import BaseToolkit, RegisteredAgentToolkit
|
|
35
35
|
from .google_maps_toolkit import GoogleMapsToolkit
|
|
36
36
|
from .code_execution import CodeExecutionToolkit
|
|
37
37
|
from .github_toolkit import GithubToolkit
|
|
38
38
|
from .google_scholar_toolkit import GoogleScholarToolkit
|
|
39
39
|
from .google_calendar_toolkit import GoogleCalendarToolkit
|
|
40
|
+
from .gmail_toolkit import GmailToolkit
|
|
40
41
|
from .arxiv_toolkit import ArxivToolkit
|
|
41
42
|
from .slack_toolkit import SlackToolkit
|
|
42
43
|
from .whatsapp_toolkit import WhatsAppToolkit
|
|
44
|
+
from .wechat_official_toolkit import WeChatOfficialToolkit
|
|
45
|
+
from .dingtalk import DingtalkToolkit
|
|
43
46
|
from .twitter_toolkit import TwitterToolkit
|
|
44
47
|
from .open_api_toolkit import OpenAPIToolkit
|
|
45
48
|
from .retrieval_toolkit import RetrievalToolkit
|
|
@@ -61,23 +64,37 @@ from .image_analysis_toolkit import ImageAnalysisToolkit
|
|
|
61
64
|
from .mcp_toolkit import MCPToolkit
|
|
62
65
|
from .browser_toolkit import BrowserToolkit
|
|
63
66
|
from .async_browser_toolkit import AsyncBrowserToolkit
|
|
64
|
-
from .
|
|
67
|
+
from .file_toolkit import FileToolkit, FileWriteToolkit
|
|
65
68
|
from .pptx_toolkit import PPTXToolkit
|
|
66
69
|
from .terminal_toolkit import TerminalToolkit
|
|
67
70
|
from .pubmed_toolkit import PubMedToolkit
|
|
68
71
|
from .data_commons_toolkit import DataCommonsToolkit
|
|
69
72
|
from .thinking_toolkit import ThinkingToolkit
|
|
70
73
|
from .pyautogui_toolkit import PyAutoGUIToolkit
|
|
71
|
-
from .openai_agent_toolkit import OpenAIAgentToolkit
|
|
72
74
|
from .searxng_toolkit import SearxNGToolkit
|
|
73
75
|
from .jina_reranker_toolkit import JinaRerankerToolkit
|
|
74
76
|
from .pulse_mcp_search_toolkit import PulseMCPSearchToolkit
|
|
75
77
|
from .klavis_toolkit import KlavisToolkit
|
|
76
78
|
from .aci_toolkit import ACIToolkit
|
|
79
|
+
from .origene_mcp_toolkit import OrigeneToolkit
|
|
77
80
|
from .playwright_mcp_toolkit import PlaywrightMCPToolkit
|
|
81
|
+
from .resend_toolkit import ResendToolkit
|
|
78
82
|
from .wolfram_alpha_toolkit import WolframAlphaToolkit
|
|
79
83
|
from .task_planning_toolkit import TaskPlanningToolkit
|
|
80
|
-
|
|
84
|
+
from .hybrid_browser_toolkit import HybridBrowserToolkit
|
|
85
|
+
from .edgeone_pages_mcp_toolkit import EdgeOnePagesMCPToolkit
|
|
86
|
+
from .google_drive_mcp_toolkit import GoogleDriveMCPToolkit
|
|
87
|
+
from .craw4ai_toolkit import Crawl4AIToolkit
|
|
88
|
+
from .markitdown_toolkit import MarkItDownToolkit
|
|
89
|
+
from .note_taking_toolkit import NoteTakingToolkit
|
|
90
|
+
from .message_agent_toolkit import AgentCommunicationToolkit
|
|
91
|
+
from .web_deploy_toolkit import WebDeployToolkit
|
|
92
|
+
from .screenshot_toolkit import ScreenshotToolkit
|
|
93
|
+
from .message_integration import ToolkitMessageIntegration
|
|
94
|
+
from .context_summarizer_toolkit import ContextSummarizerToolkit
|
|
95
|
+
from .notion_mcp_toolkit import NotionMCPToolkit
|
|
96
|
+
from .vertex_ai_veo_toolkit import VertexAIVeoToolkit
|
|
97
|
+
from .minimax_mcp_toolkit import MinimaxMCPToolkit
|
|
81
98
|
|
|
82
99
|
__all__ = [
|
|
83
100
|
'BaseToolkit',
|
|
@@ -92,7 +109,9 @@ __all__ = [
|
|
|
92
109
|
'SearchToolkit',
|
|
93
110
|
'SlackToolkit',
|
|
94
111
|
'WhatsAppToolkit',
|
|
95
|
-
'
|
|
112
|
+
'WeChatOfficialToolkit',
|
|
113
|
+
'DingtalkToolkit',
|
|
114
|
+
'ImageGenToolkit',
|
|
96
115
|
'TwitterToolkit',
|
|
97
116
|
'WeatherToolkit',
|
|
98
117
|
'RetrievalToolkit',
|
|
@@ -104,6 +123,7 @@ __all__ = [
|
|
|
104
123
|
'AsyncAskNewsToolkit',
|
|
105
124
|
'GoogleScholarToolkit',
|
|
106
125
|
'GoogleCalendarToolkit',
|
|
126
|
+
'GmailToolkit',
|
|
107
127
|
'NotionToolkit',
|
|
108
128
|
'ArxivToolkit',
|
|
109
129
|
'HumanToolkit',
|
|
@@ -125,21 +145,39 @@ __all__ = [
|
|
|
125
145
|
'ImageAnalysisToolkit',
|
|
126
146
|
'BrowserToolkit',
|
|
127
147
|
'AsyncBrowserToolkit',
|
|
128
|
-
'
|
|
148
|
+
'FileToolkit',
|
|
149
|
+
'FileWriteToolkit', # Deprecated, use FileToolkit instead
|
|
129
150
|
'PPTXToolkit',
|
|
130
151
|
'TerminalToolkit',
|
|
131
152
|
'PubMedToolkit',
|
|
132
153
|
'DataCommonsToolkit',
|
|
133
154
|
'ThinkingToolkit',
|
|
134
155
|
'PyAutoGUIToolkit',
|
|
135
|
-
'OpenAIAgentToolkit',
|
|
136
156
|
'SearxNGToolkit',
|
|
137
157
|
'JinaRerankerToolkit',
|
|
158
|
+
'OrigeneToolkit',
|
|
138
159
|
'PulseMCPSearchToolkit',
|
|
139
160
|
'KlavisToolkit',
|
|
140
161
|
'ACIToolkit',
|
|
141
162
|
'PlaywrightMCPToolkit',
|
|
163
|
+
'ResendToolkit',
|
|
142
164
|
'WolframAlphaToolkit',
|
|
143
165
|
'BohriumToolkit',
|
|
166
|
+
'OpenAIImageToolkit', # Backward compatibility
|
|
144
167
|
'TaskPlanningToolkit',
|
|
168
|
+
'HybridBrowserToolkit',
|
|
169
|
+
'EdgeOnePagesMCPToolkit',
|
|
170
|
+
'GoogleDriveMCPToolkit',
|
|
171
|
+
'Crawl4AIToolkit',
|
|
172
|
+
'MarkItDownToolkit',
|
|
173
|
+
'NoteTakingToolkit',
|
|
174
|
+
'AgentCommunicationToolkit',
|
|
175
|
+
'WebDeployToolkit',
|
|
176
|
+
'ScreenshotToolkit',
|
|
177
|
+
'RegisteredAgentToolkit',
|
|
178
|
+
'ToolkitMessageIntegration',
|
|
179
|
+
'ContextSummarizerToolkit',
|
|
180
|
+
'NotionMCPToolkit',
|
|
181
|
+
'VertexAIVeoToolkit',
|
|
182
|
+
'MinimaxMCPToolkit',
|
|
145
183
|
]
|
camel/toolkits/aci_toolkit.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
14
|
|
|
15
|
+
import asyncio
|
|
15
16
|
import os
|
|
16
17
|
from typing import TYPE_CHECKING, Dict, List, Optional, Union
|
|
17
18
|
|
|
@@ -48,14 +49,14 @@ class ACIToolkit(BaseToolkit):
|
|
|
48
49
|
|
|
49
50
|
Args:
|
|
50
51
|
api_key (Optional[str]): The API key for authentication.
|
|
51
|
-
(default: :obj
|
|
52
|
+
(default: :obj:`None`)
|
|
52
53
|
base_url (Optional[str]): The base URL for the ACI API.
|
|
53
|
-
(default: :obj
|
|
54
|
+
(default: :obj:`None`)
|
|
54
55
|
linked_account_owner_id (Optional[str]): ID of the owner of the
|
|
55
56
|
linked account, e.g., "johndoe"
|
|
56
|
-
(default: :obj
|
|
57
|
+
(default: :obj:`None`)
|
|
57
58
|
timeout (Optional[float]): Request timeout.
|
|
58
|
-
(default: :obj
|
|
59
|
+
(default: :obj:`None`)
|
|
59
60
|
"""
|
|
60
61
|
from aci import ACI
|
|
61
62
|
|
|
@@ -80,20 +81,20 @@ class ACIToolkit(BaseToolkit):
|
|
|
80
81
|
Args:
|
|
81
82
|
intent (Optional[str]): Search results will be sorted by relevance
|
|
82
83
|
to this intent.
|
|
83
|
-
(default: :obj
|
|
84
|
+
(default: :obj:`None`)
|
|
84
85
|
allowed_app_only (bool): If true, only return apps that
|
|
85
86
|
are allowed by the agent/accessor, identified by the api key.
|
|
86
|
-
(default: :obj
|
|
87
|
+
(default: :obj:`True`)
|
|
87
88
|
include_functions (bool): If true, include functions
|
|
88
89
|
(name and description) in the search results.
|
|
89
|
-
(default: :obj
|
|
90
|
+
(default: :obj:`False`)
|
|
90
91
|
categories (Optional[List[str]]): List of categories to filter the
|
|
91
92
|
search results. Defaults to an empty list.
|
|
92
|
-
(default: :obj
|
|
93
|
+
(default: :obj:`None`)
|
|
93
94
|
limit (Optional[int]): Maximum number of results to return.
|
|
94
|
-
(default: :obj
|
|
95
|
+
(default: :obj:`10`)
|
|
95
96
|
offset (Optional[int]): Offset for pagination.
|
|
96
|
-
(default: :obj
|
|
97
|
+
(default: :obj:`0`)
|
|
97
98
|
|
|
98
99
|
Returns:
|
|
99
100
|
Optional[List[AppBasic]]: List of matching apps if successful,
|
|
@@ -123,10 +124,10 @@ class ACIToolkit(BaseToolkit):
|
|
|
123
124
|
|
|
124
125
|
Args:
|
|
125
126
|
app_names (Optional[List[str]]): List of app names to filter the
|
|
126
|
-
results. (default: :obj
|
|
127
|
+
results. (default: :obj:`None`)
|
|
127
128
|
limit (Optional[int]): Maximum number of results to return.
|
|
128
|
-
(default: :obj
|
|
129
|
-
offset (Optional[int]): Offset for pagination. (default: :obj
|
|
129
|
+
(default: :obj:`10`)
|
|
130
|
+
offset (Optional[int]): Offset for pagination. (default: :obj:`0`)
|
|
130
131
|
|
|
131
132
|
Returns:
|
|
132
133
|
Union[List[AppConfiguration], str]: List of configured apps if
|
|
@@ -356,15 +357,15 @@ class ACIToolkit(BaseToolkit):
|
|
|
356
357
|
|
|
357
358
|
Args:
|
|
358
359
|
app_names (Optional[List[str]]): List of app names to filter the
|
|
359
|
-
search results. (default: :obj
|
|
360
|
+
search results. (default: :obj:`None`)
|
|
360
361
|
intent (Optional[str]): The search query/intent.
|
|
361
|
-
(default: :obj
|
|
362
|
+
(default: :obj:`None`)
|
|
362
363
|
allowed_apps_only (bool): If true, only return
|
|
363
|
-
functions from allowed apps. (default: :obj
|
|
364
|
+
functions from allowed apps. (default: :obj:`True`)
|
|
364
365
|
limit (Optional[int]): Maximum number of results to return.
|
|
365
|
-
(default: :obj
|
|
366
|
+
(default: :obj:`10`)
|
|
366
367
|
offset (Optional[int]): Offset for pagination.
|
|
367
|
-
(default: :obj
|
|
368
|
+
(default: :obj:`0`)
|
|
368
369
|
|
|
369
370
|
Returns:
|
|
370
371
|
List[Dict]: List of matching functions
|
|
@@ -395,7 +396,7 @@ class ACIToolkit(BaseToolkit):
|
|
|
395
396
|
owner id in the ACI dashboard (https://platform.aci.dev).
|
|
396
397
|
allowed_apps_only (bool): If true, only returns functions/apps
|
|
397
398
|
that are allowed to be used by the agent/accessor, identified
|
|
398
|
-
by the api key. (default: :obj
|
|
399
|
+
by the api key. (default: :obj:`False`)
|
|
399
400
|
|
|
400
401
|
Returns:
|
|
401
402
|
Dict: Result of the function execution
|
|
@@ -408,6 +409,38 @@ class ACIToolkit(BaseToolkit):
|
|
|
408
409
|
)
|
|
409
410
|
return result
|
|
410
411
|
|
|
412
|
+
async def aexecute_function(
|
|
413
|
+
self,
|
|
414
|
+
function_name: str,
|
|
415
|
+
function_arguments: Dict,
|
|
416
|
+
linked_account_owner_id: str,
|
|
417
|
+
allowed_apps_only: bool = False,
|
|
418
|
+
) -> Dict:
|
|
419
|
+
r"""Execute a function call asynchronously.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
function_name (str): Name of the function to execute.
|
|
423
|
+
function_arguments (Dict): Arguments to pass to the function.
|
|
424
|
+
linked_account_owner_id (str): To specify the end-user (account
|
|
425
|
+
owner) on behalf of whom you want to execute functions
|
|
426
|
+
You need to first link corresponding account with the same
|
|
427
|
+
owner id in the ACI dashboard (https://platform.aci.dev).
|
|
428
|
+
allowed_apps_only (bool): If true, only returns functions/apps
|
|
429
|
+
that are allowed to be used by the agent/accessor, identified
|
|
430
|
+
by the api key. (default: :obj:`False`)
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
Dict: Result of the function execution
|
|
434
|
+
"""
|
|
435
|
+
result = await asyncio.to_thread(
|
|
436
|
+
self.client.handle_function_call,
|
|
437
|
+
function_name,
|
|
438
|
+
function_arguments,
|
|
439
|
+
linked_account_owner_id,
|
|
440
|
+
allowed_apps_only,
|
|
441
|
+
)
|
|
442
|
+
return result
|
|
443
|
+
|
|
411
444
|
def get_tools(self) -> List[FunctionTool]:
|
|
412
445
|
r"""Get a list of tools (functions) available in the configured apps.
|
|
413
446
|
|
|
@@ -434,6 +467,8 @@ class ACIToolkit(BaseToolkit):
|
|
|
434
467
|
FunctionTool(self.delete_linked_account),
|
|
435
468
|
FunctionTool(self.function_definition),
|
|
436
469
|
FunctionTool(self.search_function),
|
|
470
|
+
FunctionTool(self.execute_function),
|
|
471
|
+
FunctionTool(self.aexecute_function),
|
|
437
472
|
]
|
|
438
473
|
|
|
439
474
|
for function in _all_function:
|
|
@@ -448,6 +483,16 @@ class ACIToolkit(BaseToolkit):
|
|
|
448
483
|
linked_account_owner_id=self.linked_account_owner_id,
|
|
449
484
|
)
|
|
450
485
|
|
|
486
|
+
async def async_dummy_func(*, schema=schema, **kwargs):
|
|
487
|
+
return await self.aexecute_function(
|
|
488
|
+
function_name=schema['function']['name'],
|
|
489
|
+
function_arguments=kwargs,
|
|
490
|
+
linked_account_owner_id=self.linked_account_owner_id,
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
# Add async_call method to the sync function for compatibility
|
|
494
|
+
dummy_func.async_call = async_dummy_func # type: ignore[attr-defined]
|
|
495
|
+
|
|
451
496
|
tool = FunctionTool(
|
|
452
497
|
func=dummy_func,
|
|
453
498
|
openai_tool_schema=schema,
|