Skip to content

Commit 1066024

Browse files
authored
enhance: PR3123 DingTalk toolkit integration (#3182)
1 parent a20684e commit 1066024

File tree

7 files changed

+92
-93
lines changed

7 files changed

+92
-93
lines changed

camel/toolkits/dingtalk.py

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,8 @@ def dingtalk_send_webhook_message(
420420
msgtype (Literal): Message type (text, markdown, link, actionCard).
421421
title (Optional[str]): Message title (required for markdown).
422422
webhook_url (Optional[str]): Webhook URL. If None, uses env var.
423-
webhook_secret (Optional[str]): Webhook secret. If None, uses env var.
423+
webhook_secret (Optional[str]): Webhook secret. If None, uses env
424+
var.
424425
425426
Returns:
426427
str: Success or error message.
@@ -430,7 +431,9 @@ def dingtalk_send_webhook_message(
430431
"""
431432
# Get webhook configuration
432433
url = webhook_url or os.environ.get("DINGTALK_WEBHOOK_URL", "")
433-
secret = webhook_secret or os.environ.get("DINGTALK_WEBHOOK_SECRET", "")
434+
secret = webhook_secret or os.environ.get(
435+
"DINGTALK_WEBHOOK_SECRET", ""
436+
)
434437

435438
if not url:
436439
return "Error: Webhook URL not provided or set in environment"
@@ -479,7 +482,9 @@ def dingtalk_send_webhook_message(
479482
if result.get("errcode") == 0:
480483
return "Webhook message sent successfully"
481484
else:
482-
return f"Webhook error: {result.get('errmsg', 'Unknown error')}"
485+
return (
486+
f"Webhook error: {result.get('errmsg', 'Unknown error')}"
487+
)
483488

484489
except Exception as e:
485490
return f"Failed to send webhook message: {e!s}"
@@ -691,17 +696,19 @@ def dingtalk_get_user_by_mobile(self, mobile: str) -> Dict[str, Any]:
691696
r"""Gets user information by mobile number.
692697
693698
Args:
694-
mobile (str): User's mobile number. Should be a valid Chinese
699+
mobile (str): User's mobile number. Should be a valid Chinese
695700
mobile number format (11 digits starting with 1).
696701
697702
Returns:
698703
Dict[str, Any]: User information or error information.
699704
"""
700-
# Validate mobile number format (Chinese mobile number: 11 digits starting with 1)
705+
# Validate mobile number format (Chinese mobile number: 11 digits
706+
# starting with 1)
701707
mobile_pattern = r'^1[3-9]\d{9}$'
702708
if not re.match(mobile_pattern, mobile):
703709
return {
704-
"error": "Invalid mobile number format. Expected 11 digits starting with 1 (e.g., 13800000000)."
710+
"error": "Invalid mobile number format. Expected 11 digits "
711+
"starting with 1 (e.g., 13800000000)."
705712
}
706713

707714
payload = {"mobile": mobile}
@@ -727,9 +734,9 @@ def dingtalk_get_user_by_unionid(self, unionid: str) -> Dict[str, Any]:
727734
r"""Gets user information by unionid.
728735
729736
Args:
730-
unionid (str): User's unique identifier across all DingTalk
731-
organizations. This is a global identifier that remains
732-
consistent even if the user belongs to multiple DingTalk
737+
unionid (str): User's unique identifier across all DingTalk
738+
organizations. This is a global identifier that remains
739+
consistent even if the user belongs to multiple DingTalk
733740
organizations, unlike userid which is organization-specific.
734741
735742
Returns:
@@ -891,10 +898,10 @@ def dingtalk_update_group(
891898
name (Optional[str]): New group name.
892899
owner (Optional[str]): New group owner userid.
893900
add_useridlist (Optional[List[str]]): List of user IDs to add.
894-
Note: Internally converted to comma-separated string as
901+
Note: Internally converted to comma-separated string as
895902
required by the DingTalk API.
896903
del_useridlist (Optional[List[str]]): List of user IDs to remove.
897-
Note: Internally converted to comma-separated string as
904+
Note: Internally converted to comma-separated string as
898905
required by the DingTalk API.
899906
900907
Returns:
@@ -909,7 +916,8 @@ def dingtalk_update_group(
909916
payload["name"] = name
910917
if owner:
911918
payload["owner"] = owner
912-
# Note: DingTalk update group API requires comma-separated string format
919+
# Note: DingTalk update group API requires comma-separated string
920+
# format
913921
# This is different from send_work_notification which uses array format
914922
if add_useridlist:
915923
payload["add_useridlist"] = ",".join(add_useridlist)
@@ -991,18 +999,15 @@ def dingtalk_send_work_notification(
991999
(None, "DINGTALK_APP_SECRET"),
9921000
]
9931001
)
994-
def dingtalk_get_userid_by_phone(
995-
self,
996-
phone_number: str
997-
) -> str:
1002+
def dingtalk_get_userid_by_phone(self, phone_number: str) -> str:
9981003
r"""Gets user ID by phone number for LLM agents.
999-
1004+
10001005
Args:
10011006
phone_number (str): User's phone number.
1002-
1007+
10031008
Returns:
10041009
str: User ID or error message.
1005-
1010+
10061011
References:
10071012
https://open.dingtalk.com/document/orgapp-server/query-user-details
10081013
"""
@@ -1021,27 +1026,25 @@ def dingtalk_get_userid_by_phone(
10211026
(None, "DINGTALK_APP_SECRET"),
10221027
]
10231028
)
1024-
def dingtalk_get_userid_by_name(
1025-
self,
1026-
user_name: str
1027-
) -> str:
1029+
def dingtalk_get_userid_by_name(self, user_name: str) -> str:
10281030
r"""Gets user ID by user name for LLM agents.
1029-
1031+
10301032
Args:
10311033
user_name (str): User's display name.
1032-
1034+
10331035
Returns:
10341036
str: User ID or error message.
1035-
1037+
10361038
References:
10371039
https://open.dingtalk.com/document/orgapp-server/query-users
10381040
"""
10391041
try:
10401042
search_result = self.dingtalk_search_users_by_name(user_name)
1041-
if 'result' in search_result and search_result['result']:
1043+
if search_result.get('result'):
10421044
# Return the first match
1043-
return search_result['result'][0].get('userid',
1044-
f"No userid found for user: {user_name}")
1045+
return search_result['result'][0].get(
1046+
'userid', f"No userid found for user: {user_name}"
1047+
)
10451048
else:
10461049
return f"User not found with name: {user_name}"
10471050
except Exception as e:
@@ -1053,15 +1056,12 @@ def dingtalk_get_userid_by_name(
10531056
(None, "DINGTALK_APP_SECRET"),
10541057
]
10551058
)
1056-
def dingtalk_get_department_id_by_name(
1057-
self,
1058-
department_name: str
1059-
) -> str:
1059+
def dingtalk_get_department_id_by_name(self, department_name: str) -> str:
10601060
r"""Gets department ID by department name for LLM agents.
1061-
1061+
10621062
Args:
10631063
department_name (str): Department name to search for.
1064-
1064+
10651065
Returns:
10661066
str: Department ID or error message.
10671067
"""
@@ -1073,23 +1073,20 @@ def dingtalk_get_department_id_by_name(
10731073
return str(dept.get('id', ''))
10741074
return f"Department not found: {department_name}"
10751075
else:
1076-
return f"Failed to get department list"
1076+
return "Failed to get department list"
10771077
except Exception as e:
10781078
return f"Failed to get department ID by name: {e!s}"
10791079

1080-
def dingtalk_get_chatid_by_group_name(
1081-
self,
1082-
group_name: str
1083-
) -> str:
1080+
def dingtalk_get_chatid_by_group_name(self, group_name: str) -> str:
10841081
r"""Gets chat ID by group name for LLM agents.
1085-
1082+
10861083
Note: This function provides guidance as Dingtalk API doesn't directly
10871084
support searching groups by name. Users should use the group creation
10881085
response or group management features to obtain chat IDs.
1089-
1086+
10901087
Args:
10911088
group_name (str): Group name to search for.
1092-
1089+
10931090
Returns:
10941091
str: Guidance message for obtaining chat ID.
10951092
"""
@@ -1135,4 +1132,4 @@ def get_tools(self) -> List[FunctionTool]:
11351132
]
11361133

11371134

1138-
# many other functionalities, cards etc build on top after initial works
1135+
# many other functionalities, cards etc build on top after initial works

camel/types/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
ChatCompletionAssistantMessageParam,
4242
ChatCompletionChunk,
4343
ChatCompletionMessage,
44-
ChatCompletionMessageParam,
4544
ChatCompletionMessageFunctionToolCall,
45+
ChatCompletionMessageParam,
4646
ChatCompletionSystemMessageParam,
4747
ChatCompletionToolMessageParam,
4848
ChatCompletionUserMessageParam,

examples/external_tools/use_external_tools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,5 @@ def main():
7070
Output:
7171
The video game "Portal" was released in 2007 as part of a bundle called The Orange Box for Windows, Xbox 360, and PlayStation 3.
7272
73-
ChatCompletionMessageToolCall(id='call_U5Xju7vYtAQAEW4D1M8R1kgs', function=Function(arguments='{"a": 2007, "b": 1776}', name='sub'), type='function')
73+
ChatCompletionMessageFunctionToolCall(id='call_U5Xju7vYtAQAEW4D1M8R1kgs', function=Function(arguments='{"a": 2007, "b": 1776}', name='sub'), type='function')
7474
"""

examples/toolkits/github_toolkit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
Union,
7171
)
7272
73-
from openai.types.chat import ChatCompletionMessageToolCall
73+
from openai.types.chat import ChatCompletionMessageFunctionToolCall
7474
f
7575
===============================================================================
7676
"""

test/agents/test_chat_agent.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from unittest.mock import AsyncMock, MagicMock
2020

2121
import pytest
22-
from openai.types.chat import ChatCompletionMessageToolCall
22+
from openai.types.chat import ChatCompletionMessageFunctionToolCall
2323
from openai.types.chat.chat_completion import Choice
2424
from openai.types.chat.chat_completion_message import ChatCompletionMessage
2525
from openai.types.chat.chat_completion_message_function_tool_call import (
@@ -267,7 +267,7 @@ def test_chat_agent_step_with_external_tools(step_call_count=3):
267267
audio=None,
268268
function_call=None,
269269
tool_calls=[
270-
ChatCompletionMessageToolCall(
270+
ChatCompletionMessageFunctionToolCall(
271271
id='call_mock_123456',
272272
function=Function(
273273
arguments='{ \
@@ -277,7 +277,7 @@ def test_chat_agent_step_with_external_tools(step_call_count=3):
277277
),
278278
type='function',
279279
),
280-
ChatCompletionMessageToolCall(
280+
ChatCompletionMessageFunctionToolCall(
281281
id='call_mock_123457',
282282
function=Function(
283283
arguments='{ \
@@ -314,7 +314,7 @@ def test_chat_agent_step_with_external_tools(step_call_count=3):
314314
audio=None,
315315
function_call=None,
316316
tool_calls=[
317-
ChatCompletionMessageToolCall(
317+
ChatCompletionMessageFunctionToolCall(
318318
id='call_mock_123456',
319319
function=Function(
320320
arguments='{"a":1776,"b":2007}',
@@ -399,7 +399,7 @@ async def test_chat_agent_astep_with_external_tools(step_call_count=3):
399399
audio=None,
400400
function_call=None,
401401
tool_calls=[
402-
ChatCompletionMessageToolCall(
402+
ChatCompletionMessageFunctionToolCall(
403403
id='call_mock_123456',
404404
function=Function(
405405
arguments='{ \
@@ -409,7 +409,7 @@ async def test_chat_agent_astep_with_external_tools(step_call_count=3):
409409
),
410410
type='function',
411411
),
412-
ChatCompletionMessageToolCall(
412+
ChatCompletionMessageFunctionToolCall(
413413
id='call_mock_123457',
414414
function=Function(
415415
arguments='{ \
@@ -446,7 +446,7 @@ async def test_chat_agent_astep_with_external_tools(step_call_count=3):
446446
audio=None,
447447
function_call=None,
448448
tool_calls=[
449-
ChatCompletionMessageToolCall(
449+
ChatCompletionMessageFunctionToolCall(
450450
id='call_mock_123456',
451451
function=Function(
452452
arguments='{"a":1776,"b":2007}',
@@ -906,7 +906,7 @@ def test_tool_calling_sync(step_call_count=3):
906906
audio=None,
907907
function_call=None,
908908
tool_calls=[
909-
ChatCompletionMessageToolCall(
909+
ChatCompletionMessageFunctionToolCall(
910910
id='call_mock_123456',
911911
function=Function(
912912
arguments='{ \
@@ -918,7 +918,7 @@ def test_tool_calling_sync(step_call_count=3):
918918
),
919919
type='function',
920920
),
921-
ChatCompletionMessageToolCall(
921+
ChatCompletionMessageFunctionToolCall(
922922
id='call_mock_123457',
923923
function=Function(
924924
arguments='{"a": 0, "b": 10}',
@@ -952,7 +952,7 @@ def test_tool_calling_sync(step_call_count=3):
952952
audio=None,
953953
function_call=None,
954954
tool_calls=[
955-
ChatCompletionMessageToolCall(
955+
ChatCompletionMessageFunctionToolCall(
956956
id='call_kIJby7Y6As6gAbWoxDqxD6HG',
957957
function=Function(
958958
arguments='{"a":16,"b":10}',
@@ -1079,7 +1079,7 @@ async def test_tool_calling_math_async(step_call_count=3):
10791079
audio=None,
10801080
function_call=None,
10811081
tool_calls=[
1082-
ChatCompletionMessageToolCall(
1082+
ChatCompletionMessageFunctionToolCall(
10831083
id='call_mock_123456',
10841084
function=Function(
10851085
arguments='{ \
@@ -1186,7 +1186,7 @@ def mock_run_tool_calling_async(*args, **kwargs):
11861186
# Reset tool_calls at the beginning of each new round of step() call
11871187
if model.run.call_count % 2 == 1:
11881188
model_backend_rsp_tool_async.choices[0].message.tool_calls = [
1189-
ChatCompletionMessageToolCall(
1189+
ChatCompletionMessageFunctionToolCall(
11901190
id='call_mock_123456',
11911191
function=Function(
11921192
arguments='{"second":1}', name='async_sleep'

test/models/test_sglang_model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def test_sglang_function_call(sglang_model_cleanup):
9999

100100
# Create a mock response object
101101
from openai.types.chat.chat_completion_message_function_tool_call import (
102-
ChatCompletionMessageToolCall,
102+
ChatCompletionMessageFunctionToolCall,
103103
)
104104

105105
from camel.types import (
@@ -122,7 +122,7 @@ def test_sglang_function_call(sglang_model_cleanup):
122122
role="assistant",
123123
content=None,
124124
tool_calls=[
125-
ChatCompletionMessageToolCall(
125+
ChatCompletionMessageFunctionToolCall(
126126
id="0",
127127
type="function",
128128
function={"name": "test_tool", "arguments": "{}"},

0 commit comments

Comments
 (0)