pycityagent 1.0.0__py3-none-any.whl → 1.1.0__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.
pycityagent/__init__.py CHANGED
@@ -1,4 +1,6 @@
1
1
  from .simulator import Simulator
2
2
  from .agent import Agent
3
+ from .agent_citizen import CitizenAgent
4
+ from .agent_func import FuncAgent
3
5
 
4
- __all__ = [Simulator, Agent]
6
+ __all__ = [Simulator, Agent, CitizenAgent, FuncAgent]
@@ -2,5 +2,7 @@
2
2
 
3
3
  from .ac import *
4
4
  from .action import *
5
+ from .hub_actions import *
6
+ from .sim_actions import *
5
7
 
6
- __all__ = [ActionController, Action]
8
+ __all__ = [ActionController, Action, HubAction, SimAction, SendUserMessage, SendStreetview, SendPop, PositionUpdate, ShowPath, ShowPosition, SetSchedule, SendAgentMessage]
pycityagent/ac/ac.py CHANGED
@@ -1,9 +1,10 @@
1
- from typing import Any
2
- from .trip import TripAction
3
- from .shop import ShopAction
4
- from .converse import ConverseAction
5
- from .controled import ControledAction
6
- from .idle import IdleAction
1
+ from typing import Any, Optional, Union
2
+ from .action import Action
3
+ from .citizen_actions.trip import TripAction
4
+ from .citizen_actions.shop import ShopAction
5
+ from .citizen_actions.converse import ConverseAction
6
+ from .citizen_actions.controled import ControledAction
7
+ from .citizen_actions.idle import IdleAction
7
8
 
8
9
  class ActionController:
9
10
  """
@@ -11,40 +12,56 @@ class ActionController:
11
12
  Agent Controller: Connect with AppHub and Simulator
12
13
  Note: Actions are predefined. By now, user defined actions are not supported
13
14
  """
14
- def __init__(self, agent, config=None) -> None:
15
+ def __init__(self, agent) -> None:
15
16
  self._agent = agent
16
- self._trip = TripAction(agent)
17
- self._shop = ShopAction(agent)
18
- self._converse = ConverseAction(agent)
19
- self._control = ControledAction(agent)
20
- self._idle = IdleAction(agent)
21
- self._config = config
17
+ self.action_chain = {}
18
+ self.reset_ac()
19
+ self._init_actions()
22
20
 
23
21
  async def Run(self):
24
- # TODO: 后期补充相关扩展接口,应该根据state-action关联模块进行(为了方便用户定义更加丰富的状态)
25
- if self._agent.state == 'idle':
26
- await self._idle()
27
- elif self._agent.state == 'trip':
28
- await self._trip()
29
- elif self._agent.state == 'conve':
30
- await self._converse()
31
- elif self._agent.state == 'shop':
32
- await self._shop()
33
- elif self._agent.state == 'controled':
34
- await self._control()
22
+ agent_state = self._agent.state
23
+ if agent_state in self.action_chain.keys():
24
+ for action in self.action_chain[agent_state]:
25
+ await action.Forward()
35
26
 
36
- @property
37
- def TripAction(self):
38
- return self._trip
39
-
40
- @property
41
- def ShopAction(self):
42
- return self._shop
43
-
44
- @property
45
- def ConveAction(self):
46
- return self._converse
47
-
48
- @property
49
- def ControlAction(self):
50
- return self._controls
27
+ def clear_ac(self):
28
+ """
29
+ 清空AC
30
+ """
31
+ self.action_chain.clear()
32
+
33
+ def reset_ac(self):
34
+ """
35
+ 重置Action Controller
36
+ Reset action controller
37
+ """
38
+ self.action_chain.clear()
39
+ for state in self._agent._st.machine.states.keys():
40
+ self.action_chain[state] = []
41
+
42
+ def set_ac(self, states:list[str]):
43
+ """
44
+ 设置ac
45
+ """
46
+ self.action_chain.clear()
47
+ for state in states:
48
+ self.action_chain[state] = []
49
+
50
+ def add_actions(self, state:str, actions:Union[Action, list[Action]]):
51
+ """
52
+ 添加Action到目标动作链
53
+ """
54
+ if issubclass(type(actions), Action) or isinstance(actions, Action):
55
+ self.action_chain[state].append(actions)
56
+ else:
57
+ self.action_chain[state] += actions
58
+
59
+ def _init_actions(self):
60
+ """
61
+ 构建初始化动作链——适用于citizen类型的agent
62
+ """
63
+ self.action_chain['trip'] = [TripAction(self._agent)]
64
+ self.action_chain['shop'] = [ShopAction(self._agent)]
65
+ self.action_chain['conve'] = [ConverseAction(self._agent)]
66
+ self.action_chain['controled'] = [ControledAction(self._agent)]
67
+ self.action_chain['idle'] = [IdleAction(self._agent)]
pycityagent/ac/action.py CHANGED
@@ -1,14 +1,55 @@
1
1
  from abc import ABC, abstractclassmethod
2
- from typing import Any
2
+ from typing import Callable, Any
3
3
 
4
+ class ActionType:
5
+ """
6
+ 行动类型枚举 所有行动本质上为数据推送
7
+ Action Type enumeration, all actions are essentially data push
8
+
9
+ Types:
10
+ - Sim = 1, 用于表示与模拟器对接的行动
11
+ - Hub = 2, 用于表示与AppHub(前端)对接的行动
12
+ - Comp = 3, 表示综合类型 (可能同时包含与Sim以及Hub的交互)
13
+ """
14
+ Sim = 1
15
+ Hub = 2
16
+ Comp = 3
4
17
  class Action:
5
- def __init__(self, agent) -> None:
6
- '''默认初始化'''
18
+ def __init__(self, agent, type:ActionType, source: str = None, before:Callable[[list], Any] = None) -> None:
19
+ '''
20
+ 默认初始化
21
+
22
+ Args:
23
+ - agent (Agent): the related agent
24
+ - type (ActionType)
25
+ - source (str): 数据来源, 默认为None, 如果为None则会从接收用户传入的数据作为Forward函数参数, 否则从WM.Reason数据缓存中取对应数据作为参数
26
+ - before (function): 数据处理方法, 用于当Reason缓存中的参数与标准格式不符时使用
27
+ '''
7
28
  self._agent = agent
29
+ self._type = type
30
+ self._source = source
31
+ self._before = before
32
+
33
+ def get_source(self):
34
+ """
35
+ 获取source数据
36
+ """
37
+ if self._source != None:
38
+ source = self._agent.Brain.Memory.Working.Reason[self._source]
39
+ if self._before != None:
40
+ source = self._before(source)
41
+ return source
42
+ else:
43
+ return None
8
44
 
9
45
  @abstractclassmethod
10
46
  async def Forward(self):
11
47
  '''接口函数'''
12
48
 
13
- async def __call__(self) -> Any:
14
- await self.Forward()
49
+ class SimAction(Action):
50
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
51
+ super().__init__(agent, ActionType.Sim, source, before)
52
+
53
+ class HubAction(Action):
54
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
55
+ super().__init__(agent, ActionType.Hub, source, before)
@@ -0,0 +1,25 @@
1
+ from abc import ABC, abstractclassmethod
2
+ from typing import Any, Optional
3
+ from action import Action
4
+
5
+ class ActionStream:
6
+ """
7
+ 可以将多个Action聚合在一起构成一个ActionStream, Stream中的Action会顺序执行
8
+ You can collect multiple Actions into a ActionStream, actions in stream will be activated in sequence
9
+ 注意: 该部分内容目前没有使用
10
+ """
11
+ def __init__(self, actions:Optional[list[Action]]=[]) -> None:
12
+ self.actions = actions
13
+
14
+ def add_actions(self, actions:list[Action]):
15
+ """
16
+ 添加Action至当前stream
17
+
18
+ Args:
19
+ - actions (list(Action)): a list of action
20
+ """
21
+ self.actions += actions
22
+
23
+ def __call__(self) -> Any:
24
+ for action in self.actions:
25
+ action()
@@ -0,0 +1,16 @@
1
+ import time
2
+ from typing import Callable, Any
3
+
4
+ from pycityagent.ac.action import ActionType
5
+ from ..action import Action
6
+ from pycitysim.apphub import AgentMessage
7
+
8
+ class ControledAction(Action):
9
+ '''Converse行为控制器'''
10
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
11
+ super().__init__(agent, ActionType.Comp, sources, before)
12
+
13
+ async def Forward(self):
14
+ req = {'person_id': self._agent._id, 'schedules': []}
15
+ await self._agent._client.person_service.SetSchedule(req)
16
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '我已理解您的意思,正在修改我的行程', None, None)])
@@ -0,0 +1,34 @@
1
+ import time
2
+ from typing import Callable, Any
3
+
4
+ from pycityagent.ac.action import ActionType
5
+ from ..action import Action
6
+ from pycitysim.apphub import AgentMessage
7
+
8
+ class ConverseAction(Action):
9
+ '''Converse行为控制器'''
10
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
11
+ super().__init__(agent, ActionType.Comp, sources, before)
12
+
13
+ async def Forward(self):
14
+ target_agent_ids = self._agent.Brain.Memory.Working.Reason['agent_message_handle_resp'][0]
15
+ if len(target_agent_ids) == 0:
16
+ return
17
+ messages = self._agent.Brain.Memory.Working.Reason['agent_message_handle_resp'][1]
18
+ req = {'messages': []}
19
+ if len(target_agent_ids) != len(messages):
20
+ print("Warning: the number of target agent and message are not aligned, only sends matched messages")
21
+ rng = min(len(target_agent_ids), len(messages))
22
+ for i in range(rng):
23
+ dic = {}
24
+ dic['from'] = self._agent._id
25
+ dic['to'] = target_agent_ids[i]
26
+ dic['message'] = messages[i]
27
+ req['messages'].append(dic)
28
+ # * 发送至模拟器
29
+ await self._agent._client.social_service.Send(req=req)
30
+
31
+ # * 发送至AppHub
32
+ if self._agent.Hub != None and messages[0] != 'End':
33
+ # * 将信息中的第一条不同至pop
34
+ self._agent.Hub.Update(pop=messages[0])
@@ -0,0 +1,20 @@
1
+ import time
2
+ from typing import Callable, Any
3
+
4
+ from pycityagent.ac.action import ActionType
5
+ from ..action import Action
6
+ from pycitysim.apphub import AgentMessage
7
+
8
+ class IdleAction(Action):
9
+ '''idle行为控制器'''
10
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
11
+ super().__init__(agent, ActionType.Comp, sources, before)
12
+
13
+ async def Forward(self):
14
+ if len(self._agent.base['schedules']) > 0:
15
+ req = {'person_id': self._agent._id, 'schedules': []}
16
+ await self._agent._client.person_service.SetSchedule(req)
17
+ if self._agent.Hub != None:
18
+ self._agent.Hub.Update()
19
+
20
+
@@ -0,0 +1,82 @@
1
+ from typing import Callable, Any
2
+ from pycityagent.ac.action import ActionType
3
+ from ..action import Action
4
+ from pycitysim.apphub import AgentMessage
5
+ import time
6
+
7
+ def encap_msg(msg, role='user', **kwargs):
8
+ dialog = {'role': role, 'content': msg}
9
+ dialog.update(kwargs)
10
+ return dialog
11
+
12
+ class ShopAction(Action):
13
+ '''Shop行为控制器'''
14
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
15
+ super().__init__(agent, ActionType.Comp, sources, before)
16
+
17
+ async def Forward(self):
18
+ # * 与模拟器对接 - 暂时没有
19
+ # * 与AppHub对接
20
+ profile = self._agent.Image.get_profile()
21
+ self.consumption(profile)
22
+
23
+ def consumption(self, profile, mall_info):
24
+ dialogs = []
25
+ system_prompt = f'''
26
+ 你是一个在北京工作和生活的人。
27
+ {profile}
28
+ 现在是2024年1月。
29
+ 你需要为下一周的基本生活购买必需品。
30
+ '''
31
+ dialogs.append(encap_msg(system_prompt, 'system'))
32
+ actions_format = ['''{{'商品': 购买的商品的列表,'购买量': 每个商品的购买量,一个列表, '解释': '这种购买方式的原因'}}''']
33
+ actions_candidates = ['''【食品】
34
+ 米:10元/公斤
35
+ 面粉:7.5元/公斤
36
+ 新鲜蔬菜(如菠菜):7元/500克
37
+ 水果(如苹果):15元/公斤
38
+ 猪肉:30元/公斤
39
+ 鸡肉:20元/公斤
40
+ 鸡蛋:1.5元/个
41
+ 牛奶:10元/升''',
42
+ '''【清洁用品】
43
+ 洗衣液:30元/瓶
44
+ 洗洁精:20元/瓶
45
+ 垃圾袋:0.3元/个''',
46
+ '''【个人护理用品】
47
+ 牙膏:10元/支
48
+ 洗发水:30元/瓶
49
+ 沐浴露:35元/瓶
50
+ 面巾纸:5元/包''',
51
+ '''【其他】
52
+ 矿泉水:1.7元/瓶
53
+ 面包:8元/个
54
+ 辣条:3元/包''']
55
+
56
+ user_prompt = f'''
57
+ 首先确定你的消费预算。以如下格式回答,不要有冗余的文本!
58
+ {{'消费预算': 一个代表购买必需品需要消耗的钱的数量的数字}}
59
+ '''
60
+ dialogs.append(encap_msg(user_prompt))
61
+ # * 对接一:确定消费预算
62
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '我正在确定消费预算......', None, None)])
63
+ msg = self._agent._soul.text_request(dialogs)
64
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我的消费预算是: {msg}'), None, None])
65
+
66
+ dialogs.append(encap_msg(msg, 'assistant'))
67
+
68
+ # * 对接二:购物选择
69
+ for cand in actions_candidates:
70
+ user_prompt = f'''
71
+ 购物中心里有
72
+ {cand}
73
+ 你要买哪些商品,以如下格式回答,不要有冗余的文本!
74
+ {actions_format[0]}
75
+ '''
76
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我看到了\n {cand}', None, None)])
77
+ dialogs.append(encap_msg(user_prompt))
78
+ msg = self._agent._soul.text_request(dialogs)
79
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'我的购买选择是: {msg}', None, None)])
80
+ dialogs.append(encap_msg(msg, 'assistant'))
81
+
82
+ self._agent.Hub.Update([AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), '购物完成', None, None)])
@@ -0,0 +1,41 @@
1
+ import time
2
+ from typing import Callable, Any
3
+
4
+ from pycityagent.ac.action import ActionType
5
+ from ..action import Action
6
+ from pycitysim.apphub import AgentMessage
7
+
8
+ class TripAction(Action):
9
+ '''Trip行为控制器'''
10
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
11
+ super().__init__(agent, ActionType.Comp, sources, before)
12
+
13
+ async def Forward(self):
14
+ now = self._agent.Scheduler.now
15
+ if now.is_set:
16
+ # TODO: 目前仅支持传输一张图片至前端
17
+ '''之前已经将schedule同步至模拟器了'''
18
+ if self._agent.Hub != None:
19
+ self._agent.Hub.Update(streetview=self._agent.Brain.Sence.sence_buffer['streetview'][0])
20
+ else:
21
+ '''同步schedule至模拟器'''
22
+ self._agent.Scheduler.now.is_set = True
23
+ departure_time = now.time
24
+ mode = now.mode
25
+ aoi_id = now.target_id_aoi
26
+ poi_id = now.target_id_poi
27
+ end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
28
+ activity = now.description
29
+ trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
30
+ set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
31
+
32
+ # * 与模拟器对接
33
+ req = {'person_id': self._agent._id, 'schedules': set_schedule}
34
+ await self._agent._client.person_service.SetSchedule(req)
35
+
36
+ # * 与AppHub对接
37
+ if self._agent.Hub != None:
38
+ messages = [AgentMessage(self._agent.Hub._agent_id, int(time.time()*1000), f'已到达出发时间, {activity}', None, None)]
39
+ self._agent.Hub.Update(messages)
40
+
41
+
@@ -0,0 +1,93 @@
1
+ from typing import Callable, Optional, Any
2
+ from pycitysim.apphub import AgentMessage
3
+ from .action import HubAction
4
+ from PIL.Image import Image
5
+
6
+ class SendUserMessage(HubAction):
7
+ """
8
+ 发送用户可见信息
9
+ Send messages to user
10
+ """
11
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
12
+ super().__init__(agent, source, before)
13
+
14
+ async def Forward(self, messages: Optional[list[AgentMessage]] = None):
15
+ if not messages == None:
16
+ self._agent.Hub.Update(messages = messages)
17
+ elif self._source != None:
18
+ messages = self.get_source()
19
+ if messages != None:
20
+ self._agent.Hub.Update(messages = messages)
21
+
22
+ class SendStreetview(HubAction):
23
+ """
24
+ 发送街景图片至前端
25
+ Send streetview to frontend
26
+ """
27
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
28
+ super().__init__(agent, source, before)
29
+
30
+ async def Forward(self, images: Optional[list[Image]] = None):
31
+ # TODO: 目前只支持发送一张图片
32
+ if not images == None:
33
+ self._agent.Hub.Update(streetview = images[0])
34
+ elif self._source != None:
35
+ images = self.get_source()
36
+ if images != None:
37
+ self._agent.Hub.Update(streetview = images[0])
38
+
39
+ class SendPop(HubAction):
40
+ """
41
+ 发送Pop信息 - agent头顶气泡信息
42
+ Send pop message to frontend, pop message shows above the target agent
43
+ """
44
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
45
+ super().__init__(agent, source, before)
46
+
47
+ async def Forward(self, pop:Optional[str] = None):
48
+ if not pop == None:
49
+ self._agent.Hub.Update(pop = pop)
50
+ elif self._source != None:
51
+ pop = self.get_source()
52
+ if pop != None:
53
+ self._agent.Hub.Update(pop = pop)
54
+
55
+ class PositionUpdate(HubAction):
56
+ """
57
+ 同步当前agent的位置信息
58
+ Send the position of current agent to frontend
59
+ """
60
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
61
+ super().__init__(agent, source, before)
62
+
63
+ async def Forward(self, longlat: Optional[list[float]] = None):
64
+ if longlat != None:
65
+ self._agent.Hub.Update(longlat = longlat)
66
+ elif self._source != None:
67
+ longlat = self.get_source()
68
+ if longlat != None:
69
+ self._agent.Hub.Update(longlat = longlat)
70
+
71
+ class ShowPath(HubAction):
72
+ """
73
+ 在地图上展示路径信息
74
+ Show a path in frontend map
75
+ """
76
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
77
+ super().__init__(agent, source, before)
78
+
79
+ async def Forward(self):
80
+ # TODO: 相关功能完善
81
+ pass
82
+
83
+ class ShowPosition(HubAction):
84
+ """
85
+ 在地图上展示特定地点
86
+ Show a position in frontend map
87
+ """
88
+ def __init__(self, agent, source: str = None, before: Callable[[list], Any] = None) -> None:
89
+ super().__init__(agent, source, before)
90
+
91
+ async def Forward(self):
92
+ # TODO: 相关功能完善
93
+ pass
@@ -0,0 +1,80 @@
1
+ import time
2
+ from typing import Callable, Optional, Any
3
+ from .action import SimAction
4
+ from ..brain.scheduler import TripSchedule
5
+
6
+ class SetSchedule(SimAction):
7
+ """
8
+ 用于将agent的行程信息同步至模拟器 —— 仅对citizen类型agent适用
9
+ Synchronize agent's schedule to simulator —— only avalable for citizen type of agent
10
+ """
11
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
12
+ super().__init__(agent, sources, before)
13
+
14
+ async def Forward(self, schedule: Optional[TripSchedule] = None):
15
+ """
16
+ 如果当前行程已经同步至模拟器: 跳过同步, 否则同步至模拟器
17
+ If current schedule has been synchronized to simulator: skip, else sync
18
+ """
19
+ if not schedule == None:
20
+ if not schedule.is_set:
21
+ '''同步schedule至模拟器'''
22
+ self._agent.Scheduler.now.is_set = True
23
+ departure_time = schedule.time
24
+ mode = schedule.mode
25
+ aoi_id = schedule.target_id_aoi
26
+ poi_id = schedule.target_id_poi
27
+ end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
28
+ activity = schedule.description
29
+ trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
30
+ set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
31
+
32
+ # * 与模拟器对接
33
+ req = {'person_id': self._agent._id, 'schedules': set_schedule}
34
+ await self._agent._client.person_service.SetSchedule(req)
35
+ elif self._source != None:
36
+ schedule = self.get_source()
37
+ if schedule != None and not schedule.is_set:
38
+ '''同步schedule至模拟器'''
39
+ self._agent.Scheduler.now.is_set = True
40
+ departure_time = schedule.time
41
+ mode = schedule.mode
42
+ aoi_id = schedule.target_id_aoi
43
+ poi_id = schedule.target_id_poi
44
+ end = {'aoi_position': {'aoi_id': aoi_id, 'poi_id': poi_id}}
45
+ activity = schedule.description
46
+ trips = [{'mode': mode, 'end': end, 'departure_time': departure_time, 'activity': activity}]
47
+ set_schedule = [{'trips': trips, 'loop_count': 1, 'departure_time': departure_time}]
48
+
49
+ # * 与模拟器对接
50
+ req = {'person_id': self._agent._id, 'schedules': set_schedule}
51
+ await self._agent._client.person_service.SetSchedule(req)
52
+
53
+
54
+ class SendAgentMessage(SimAction):
55
+ """
56
+ 发送信息给其他agent
57
+ Send messages to other agents
58
+ """
59
+ def __init__(self, agent, sources: list[str] = None, before: Callable[[list], Any] = None) -> None:
60
+ super().__init__(agent, sources, before)
61
+
62
+ async def Forward(self, messages: Optional[dict] = None):
63
+ if not messages == None and len(messages) > 0:
64
+ req = {'messages': []}
65
+ for message in messages:
66
+ from_id = self._agent._id
67
+ to_id = message['id']
68
+ mes = message['message']
69
+ req['messages'].append({'from': from_id, 'to': to_id, 'message': mes})
70
+ await self._agent._client.social_service.Send(req)
71
+ elif self._source != None:
72
+ messages = self.get_source()
73
+ if not messages == None and len(messages) > 0:
74
+ req = {'messages': []}
75
+ for message in messages:
76
+ from_id = self._agent._id
77
+ to_id = message['id']
78
+ mes = message['message']
79
+ req['messages'].append({'from': from_id, 'to': to_id, 'message': mes})
80
+ await self._agent._client.social_service.Send(req)