camel-ai 0.2.0__py3-none-any.whl → 0.2.3a0__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 +1 -1
- camel/agents/chat_agent.py +247 -60
- camel/bots/__init__.py +20 -0
- camel/bots/discord_bot.py +206 -0
- camel/bots/telegram_bot.py +82 -0
- camel/configs/gemini_config.py +1 -1
- camel/loaders/firecrawl_reader.py +11 -43
- camel/loaders/unstructured_io.py +35 -1
- camel/messages/func_message.py +2 -2
- camel/models/mistral_model.py +1 -1
- camel/models/openai_compatibility_model.py +19 -6
- camel/retrievers/vector_retriever.py +32 -15
- camel/societies/role_playing.py +12 -0
- camel/storages/__init__.py +2 -0
- camel/storages/graph_storages/__init__.py +2 -0
- camel/storages/graph_storages/nebula_graph.py +547 -0
- camel/tasks/task.py +11 -4
- camel/tasks/task_prompt.py +4 -0
- camel/types/enums.py +3 -0
- camel/utils/commons.py +8 -1
- camel/workforce/__init__.py +6 -6
- camel/workforce/base.py +9 -5
- camel/workforce/prompts.py +179 -0
- camel/workforce/role_playing_worker.py +181 -0
- camel/workforce/{single_agent_node.py → single_agent_worker.py} +49 -23
- camel/workforce/task_channel.py +3 -5
- camel/workforce/utils.py +20 -50
- camel/workforce/{worker_node.py → worker.py} +15 -12
- camel/workforce/workforce.py +456 -19
- {camel_ai-0.2.0.dist-info → camel_ai-0.2.3a0.dist-info}/METADATA +15 -12
- {camel_ai-0.2.0.dist-info → camel_ai-0.2.3a0.dist-info}/RECORD +32 -29
- camel/workforce/manager_node.py +0 -299
- camel/workforce/role_playing_node.py +0 -168
- camel/workforce/workforce_prompt.py +0 -125
- {camel_ai-0.2.0.dist-info → camel_ai-0.2.3a0.dist-info}/WHEEL +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
camel/__init__.py,sha256=
|
|
1
|
+
camel/__init__.py,sha256=lQSKaE7GqJm4K6yZtPgrzu5SimTTJ16AVlL93Pk2DuI,778
|
|
2
2
|
camel/agents/__init__.py,sha256=SSU1wbhZXWwQnE0rRxkpyN57kEu72KklsZNcdLkXfTs,1551
|
|
3
3
|
camel/agents/base.py,sha256=X39qWSiT1WnDqaJ9k3gQrTpOQSwUKzNEVpp5AY6fDH8,1130
|
|
4
|
-
camel/agents/chat_agent.py,sha256=
|
|
4
|
+
camel/agents/chat_agent.py,sha256=KwbKYfNzYSgNDHeUeBWOFUTlqVn8P8h2eHTVpeBNK8Q,43735
|
|
5
5
|
camel/agents/critic_agent.py,sha256=To-istnO-9Eb0iabdeIDrgfvkxYYfsdX9xIZiSrc3oM,7493
|
|
6
6
|
camel/agents/deductive_reasoner_agent.py,sha256=49vwglWYHgXf-VRftdMN9OFGOwqdsXyTt45PP6z-pbg,13473
|
|
7
7
|
camel/agents/embodied_agent.py,sha256=3ABuiRQXBpplKbuhPY5KNLJyKc6Z8SgXgzIges3ZwVs,7542
|
|
@@ -12,10 +12,13 @@ camel/agents/task_agent.py,sha256=n9xIU3QtcptRPSuHZJ4ntQ_M_a8AvJ6U9ZRV8VaxV5A,14
|
|
|
12
12
|
camel/agents/tool_agents/__init__.py,sha256=ulTNWU2qoFGe3pvVmCq_sdfeSX3NKZ0due66TYvsL-M,862
|
|
13
13
|
camel/agents/tool_agents/base.py,sha256=nQAhfWi8a_bCgzlf5-G-tmj1fKm6AjpRc89NQkWwpnc,1399
|
|
14
14
|
camel/agents/tool_agents/hugging_face_tool_agent.py,sha256=1Z5tG6f_86eL0vmtRZ-BJvoLDFFLhoHt8JtDvgat1xU,8723
|
|
15
|
+
camel/bots/__init__.py,sha256=DGgIhb7Gr_ShnAldq-4wAXucOdSvKtiV3m6e9G10rbA,834
|
|
16
|
+
camel/bots/discord_bot.py,sha256=VplQA162NqSohMzpCexSsuCCx_GdhAXOnL3040Ba1uE,8138
|
|
17
|
+
camel/bots/telegram_bot.py,sha256=MM91afWKUtEZLOoybFY7LGisQJFypc_p_P8kQOUlXwg,2747
|
|
15
18
|
camel/configs/__init__.py,sha256=3SCXrA7ML8CNoOWQ1poJY6dE2e07Qxf7ACD_mdo2aJ8,2341
|
|
16
19
|
camel/configs/anthropic_config.py,sha256=DGQoPyYrayhYQ7aSjkYYGHOZ5VdQ9qahtaS0p_GpU0Q,3294
|
|
17
20
|
camel/configs/base_config.py,sha256=gjsDACMCk-hXDBk7qkeHcpbQrWy6jbp4iyzfqgghJEk,2485
|
|
18
|
-
camel/configs/gemini_config.py,sha256=
|
|
21
|
+
camel/configs/gemini_config.py,sha256=qhGdWMRP87E99ApQdRrf9UyFpp2R0k6Y2n9ZV27qpzs,6879
|
|
19
22
|
camel/configs/groq_config.py,sha256=-ihiO5h4N_kUSlPNeBqIlnIkLkhC7oXsC2FYyAqtKp0,5755
|
|
20
23
|
camel/configs/litellm_config.py,sha256=77k7HT-0s9Sq_g4KeDjL_MZId0Tx5TB8oupIyGQHx08,4692
|
|
21
24
|
camel/configs/mistral_config.py,sha256=G9LuY0-3S6az-8j8kpqB-4asgoaxTOsZVYeZBYJl6LI,3634
|
|
@@ -43,9 +46,9 @@ camel/interpreters/ipython_interpreter.py,sha256=B0v1DCiq6PmOYQXXQAQBX1oOYjgJ0ge
|
|
|
43
46
|
camel/interpreters/subprocess_interpreter.py,sha256=nKxFXZJ9zGYlKdNlz6Ln7bvg65ejKZ8yAHgIFuR2WzM,6835
|
|
44
47
|
camel/loaders/__init__.py,sha256=ClE516UbyUes6Zut8CCiH0zWqFwwpgEcP9ur3dte8iU,949
|
|
45
48
|
camel/loaders/base_io.py,sha256=xzK67fqx66eYaM6fMXRJiSZfwKhFVNQmzuKURPtTzhk,10339
|
|
46
|
-
camel/loaders/firecrawl_reader.py,sha256=
|
|
49
|
+
camel/loaders/firecrawl_reader.py,sha256=OmnT4XdoL-naTg_nvUnN_sjiP6Xf4gdDxFUOqyQbKJo,6691
|
|
47
50
|
camel/loaders/jina_url_reader.py,sha256=ur_2Z3NFrz5AbPFi5REyZh5fISkJ9H_UZV4gtmOSO04,3607
|
|
48
|
-
camel/loaders/unstructured_io.py,sha256=
|
|
51
|
+
camel/loaders/unstructured_io.py,sha256=c2-vBhgVAWD3bJ3Gqo4nOcM5-xGc8CIMXogkc5Li9dw,17502
|
|
49
52
|
camel/memories/__init__.py,sha256=ml1Uj4Y_1Q2LfrTXOY38niF0x1H-N-u_zoN_VvR939U,1364
|
|
50
53
|
camel/memories/agent_memories.py,sha256=pzmjztFXPyNpabMWLi_-oJljMkYQvDP_s6Yq5U0hVEs,6097
|
|
51
54
|
camel/memories/base.py,sha256=kbyAmKkOfFdOKfHxwao8bIAbRSuOEXyzxPFd0NlvUCE,5003
|
|
@@ -57,7 +60,7 @@ camel/memories/context_creators/score_based.py,sha256=UrioLcsj4jB4Rz5mg5hYmR8UYZ
|
|
|
57
60
|
camel/memories/records.py,sha256=kcXOATDTRRo-SCAcDpsV8Ttfie7p1GcXYzuXgXKJB0E,3686
|
|
58
61
|
camel/messages/__init__.py,sha256=djLvpz6AmjeLzuUSQl7J6T2O4x8MwSdcH0l9fbj_3yg,1468
|
|
59
62
|
camel/messages/base.py,sha256=694Zz19D4u-j8mmpRXwCVJ8cd2Wll6h7acbyNRofNTI,13722
|
|
60
|
-
camel/messages/func_message.py,sha256=
|
|
63
|
+
camel/messages/func_message.py,sha256=wqVhTC81g5Fb2b_2EPsOBP3rHZBTP6o9wMiIRkN_HAE,3807
|
|
61
64
|
camel/models/__init__.py,sha256=CxrRisXkHgJPv7HdC6pblHuhSpDjUbUjrTdZeZ-0v7w,1971
|
|
62
65
|
camel/models/anthropic_model.py,sha256=_xhnbrMsuumB2jkuv2pVv3MFYxNE5EL5kVlZbYYBo5E,5751
|
|
63
66
|
camel/models/azure_openai_model.py,sha256=r5diPZp4XmCcZClkCqvTHB8frzRNou559j89dryKLKw,6078
|
|
@@ -65,13 +68,13 @@ camel/models/base_model.py,sha256=UHyAgo6GzYZNLTZD1T0C3_WmHUPoh9Qoe_SfvdI7HrU,43
|
|
|
65
68
|
camel/models/gemini_model.py,sha256=h_kyD8LSpXCn2dQ4OEer5HwwEUwuTD65yRIRV4LD3Vs,7700
|
|
66
69
|
camel/models/groq_model.py,sha256=Lm1br_2FBdqNQ3pCgMNf3VnjykYzttUKnHWExEXshLo,4753
|
|
67
70
|
camel/models/litellm_model.py,sha256=5sTOzI07FsxDEW3jSK-XXBx91Yo8z9voahyCsK36U6U,5748
|
|
68
|
-
camel/models/mistral_model.py,sha256=
|
|
71
|
+
camel/models/mistral_model.py,sha256=7K0hwk4QEGtCO_Btq9v7_iLQRgg6COpdgvXxRB8rd3U,9517
|
|
69
72
|
camel/models/model_factory.py,sha256=_dQOx_MYxXih6uQOjkKR7uoIrhDcWRsMTKHbO3NLYN0,5974
|
|
70
73
|
camel/models/nemotron_model.py,sha256=2Idf4wrZervxvfu6av42EKjefFtDnBb6cKnWCJUkqI4,2682
|
|
71
74
|
camel/models/ollama_model.py,sha256=FSMwH2-856Zhxusm4B773xBBHdlD3UOw9OAuH5eTJTw,5686
|
|
72
75
|
camel/models/open_source_model.py,sha256=p5a2sCeZl5SyrgkygClndOrHEjpJxmyhE1CqKE2fZSw,6363
|
|
73
76
|
camel/models/openai_audio_models.py,sha256=_ddOxqzFZCVZaK6h33Z0THU6HXk2XlJTxVWquZ3oOaQ,10042
|
|
74
|
-
camel/models/openai_compatibility_model.py,sha256=
|
|
77
|
+
camel/models/openai_compatibility_model.py,sha256=jeYBqB3xjV8jx8CJGFShkISO_TrgwubCU1WfmSiDhBY,4758
|
|
75
78
|
camel/models/openai_model.py,sha256=27NbN0bU_cAPmWjwsWceNO4zW8WS2j3P_YWNTXeg1O8,5464
|
|
76
79
|
camel/models/reka_model.py,sha256=_ERZvtkK0Gd7GUx3f4VVqqtH093clVMoJfa896t9f2M,8043
|
|
77
80
|
camel/models/samba_model.py,sha256=CgAYMIVJFAEoyCOsYS7qD_bvWhzOkvA6SD5nGBClbzE,17699
|
|
@@ -102,14 +105,15 @@ camel/retrievers/auto_retriever.py,sha256=XPyECIXO7lFbHoLMPasFurYmC9Me6wa7JPKHZW
|
|
|
102
105
|
camel/retrievers/base.py,sha256=sgqaJDwIkWluEgPBlukFN7RYZJnrp0imCAOEWm6bZ40,2646
|
|
103
106
|
camel/retrievers/bm25_retriever.py,sha256=Dr7Yfkjw45sovI1EVNByGIMj7KERWrr8JHlh8csSF1s,5155
|
|
104
107
|
camel/retrievers/cohere_rerank_retriever.py,sha256=HvnFqXpsX9EdBOab0kFLDyxxJnknPFMVxyQJQDlHbOA,4100
|
|
105
|
-
camel/retrievers/vector_retriever.py,sha256=
|
|
108
|
+
camel/retrievers/vector_retriever.py,sha256=zVsxWrv7-69GBRzC90Bt_JuMy8rQLsUYXXn5glZgdgo,9019
|
|
106
109
|
camel/societies/__init__.py,sha256=JhGwUHjht4CewzC3shKuxmgB3oS7FIxIxmiKyhNsfIs,832
|
|
107
110
|
camel/societies/babyagi_playing.py,sha256=tZTcfQrD9ECUhkqwdthsM2yFPfYGKsoAGMfTlrxt5as,11675
|
|
108
|
-
camel/societies/role_playing.py,sha256=
|
|
109
|
-
camel/storages/__init__.py,sha256=
|
|
110
|
-
camel/storages/graph_storages/__init__.py,sha256=
|
|
111
|
+
camel/societies/role_playing.py,sha256=tu6AyUPEe0j3rGNwzCCTiGqHw9RWdyTStB5JbPNvBs8,23403
|
|
112
|
+
camel/storages/__init__.py,sha256=erzsXX2rPVodgWxlV6hSjwmc4UCguzVb6m3ahBoyWu0,1623
|
|
113
|
+
camel/storages/graph_storages/__init__.py,sha256=YFwNjNYaxpKT2j5dxWZur62T8J0ZPER3DHaWGEAXgo8,954
|
|
111
114
|
camel/storages/graph_storages/base.py,sha256=-Ys1BIuz4H5FvYMZTBIjg8Cfv40CPQ-OsovwMzygEgU,2858
|
|
112
115
|
camel/storages/graph_storages/graph_element.py,sha256=FGYJZpS3UeSd9yyzz5KelMqbpJ6m5177PspZ8ueoQQI,2580
|
|
116
|
+
camel/storages/graph_storages/nebula_graph.py,sha256=PFLI--kgC93Nt5kPFWH2DVqwvk2GrC--dr2bzwvmeXw,18863
|
|
113
117
|
camel/storages/graph_storages/neo4j_graph.py,sha256=YAT7u2jPs5pNSO_tSwARHJyt3HqYXpbpE4ZBtv935Kg,22138
|
|
114
118
|
camel/storages/key_value_storages/__init__.py,sha256=v3Wy3CAJNgrPyBV4miOC6TxQDL-PYdGW8HbqiYl7k00,968
|
|
115
119
|
camel/storages/key_value_storages/base.py,sha256=knxni8WiyTXJ2emZQO-JIsbxw6Ei7EO6dj-bU2YCoSY,2183
|
|
@@ -126,8 +130,8 @@ camel/storages/vectordb_storages/base.py,sha256=XNRv6CFg1rb9G_hZhUmN4t9XCU9rCakH
|
|
|
126
130
|
camel/storages/vectordb_storages/milvus.py,sha256=EkwaG3bq7djektSI2jdSTccE7GjBpZruqXQoPTxtyoo,13489
|
|
127
131
|
camel/storages/vectordb_storages/qdrant.py,sha256=lG_tOdjfTybSUNluQ1TEqYX96dSMrVSPg6HjO6Uzw7I,13439
|
|
128
132
|
camel/tasks/__init__.py,sha256=g8_UAa4WmhaesYtzAUMW7m3mg-3ILEUvTaB7eOU9-3I,912
|
|
129
|
-
camel/tasks/task.py,sha256=
|
|
130
|
-
camel/tasks/task_prompt.py,sha256=
|
|
133
|
+
camel/tasks/task.py,sha256=ptVnC1cbY6einAPf7_p8AV5d04IcTsvv7gay_qmKJ48,12817
|
|
134
|
+
camel/tasks/task_prompt.py,sha256=iQRzCe6YoOH29ktjp5iOsE_qbWCNljV0HyaWmNsHH2s,2156
|
|
131
135
|
camel/terminators/__init__.py,sha256=pE7fcfDUNngdbm1BhzSQPRMXNbdd28rl9YbF4gKWwXE,997
|
|
132
136
|
camel/terminators/base.py,sha256=TSkl3maNEsdjyAniJaSgFfD4UF8RQ1LwNIiGw0dN8Gg,1396
|
|
133
137
|
camel/terminators/response_terminator.py,sha256=zcXuigbvlclUoBv4xcVbfU36ZohUT1RhI-rSnukloUY,4951
|
|
@@ -174,23 +178,22 @@ camel/toolkits/slack_toolkit.py,sha256=gblCbN_RCsOdgo1GGUF-R8YJneNRjezJMHhYoRFjC
|
|
|
174
178
|
camel/toolkits/twitter_toolkit.py,sha256=0QYLlsg4hUVev2Z0hPJHksDNHG_54IiVHsB3IxCqrXs,19741
|
|
175
179
|
camel/toolkits/weather_toolkit.py,sha256=n4YrUI_jTIH7oqH918IdHbXLgfQ2BPGIWWK8Jp8G1Uw,7054
|
|
176
180
|
camel/types/__init__.py,sha256=ArKXATj3z_Vv4ISmROVeo6Mv3tj5kE1dTkqfgwyxVY4,1975
|
|
177
|
-
camel/types/enums.py,sha256=
|
|
181
|
+
camel/types/enums.py,sha256=OfxiXL7VRcIQgfEEu0gdFeHPWGQpiuXHOC86jJE47DA,17773
|
|
178
182
|
camel/types/openai_types.py,sha256=BNQ6iCzKTjSvgcXFsAFIgrUS_YUFZBU6bDoyAp387hI,2045
|
|
179
183
|
camel/utils/__init__.py,sha256=IdI9v0FetNR-nx-Hg4bmNHoYto6Xfcs_uaomksdewmo,2303
|
|
180
184
|
camel/utils/async_func.py,sha256=SLo8KPkrNKdsONvFf3KBb33EgFn4gH2EKSX1aI_LKes,1578
|
|
181
|
-
camel/utils/commons.py,sha256=
|
|
185
|
+
camel/utils/commons.py,sha256=kJ6-9pnt6HgERZh3DXofMUzT0FvDujvybuZG4rzjlso,16611
|
|
182
186
|
camel/utils/constants.py,sha256=8n4F8Y-DZy4z2F0hRvAq6f-d9SbS59kK5FyLrnJ3mkY,1360
|
|
183
187
|
camel/utils/token_counting.py,sha256=AVGml8X_qq3rPdzw2tc9I3n-oEkGyNH_vPsedhVtew0,21318
|
|
184
|
-
camel/workforce/__init__.py,sha256=
|
|
185
|
-
camel/workforce/base.py,sha256=
|
|
186
|
-
camel/workforce/
|
|
187
|
-
camel/workforce/
|
|
188
|
-
camel/workforce/
|
|
189
|
-
camel/workforce/task_channel.py,sha256=
|
|
190
|
-
camel/workforce/utils.py,sha256=
|
|
191
|
-
camel/workforce/
|
|
192
|
-
camel/workforce/workforce.py,sha256=
|
|
193
|
-
|
|
194
|
-
camel_ai-0.2.
|
|
195
|
-
camel_ai-0.2.
|
|
196
|
-
camel_ai-0.2.0.dist-info/RECORD,,
|
|
188
|
+
camel/workforce/__init__.py,sha256=m2KbPItARjIyKiHc_Z34joWTJ-1XnIJfQqAZEeonz2U,926
|
|
189
|
+
camel/workforce/base.py,sha256=ScUPdtMLJgvvJkGEku6rrr4gBRw3GFt3V8HlYOY5Y8A,1809
|
|
190
|
+
camel/workforce/prompts.py,sha256=0Wcu7HpiyaD_387urc2P1uY9-DN8JAdk00HSlhNWz34,6184
|
|
191
|
+
camel/workforce/role_playing_worker.py,sha256=pKKT6MdVCPeag5s45yOzjT4Gn1u_aTbERSVw53ISBUY,7107
|
|
192
|
+
camel/workforce/single_agent_worker.py,sha256=DsibU4VkdFWuzi6mhMnT-YYm3FcVGcKfF7r1WtGii3E,3561
|
|
193
|
+
camel/workforce/task_channel.py,sha256=oQJ-qzXWBqZljwV3EdZ7Kpo7RExZfI_tqg0bop14clM,6741
|
|
194
|
+
camel/workforce/utils.py,sha256=kBrjA_k9BblJBT13kW0eQYcBDjetyjOUHMbRuh_IfPM,2270
|
|
195
|
+
camel/workforce/worker.py,sha256=oZtl3PhxgpizKy7W_wB94Qm4Z2Tw4k1SQsqAGAi_XoI,3844
|
|
196
|
+
camel/workforce/workforce.py,sha256=lF0ZeGtol91N3kAlAFwDxnO6YYVKmZPohxNb5ezHEUc,18185
|
|
197
|
+
camel_ai-0.2.3a0.dist-info/METADATA,sha256=usnLO_QSIxLsoD6iyL09pp0ED-Z5foxzcpvclWoKWpo,25040
|
|
198
|
+
camel_ai-0.2.3a0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
199
|
+
camel_ai-0.2.3a0.dist-info/RECORD,,
|
camel/workforce/manager_node.py
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the “License”);
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
#
|
|
6
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
-
#
|
|
8
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an “AS IS” BASIS,
|
|
10
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
-
# See the License for the specific language governing permissions and
|
|
12
|
-
# limitations under the License.
|
|
13
|
-
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import asyncio
|
|
17
|
-
from collections import deque
|
|
18
|
-
from typing import Deque, Dict, List, Optional
|
|
19
|
-
|
|
20
|
-
from colorama import Fore
|
|
21
|
-
|
|
22
|
-
from camel.agents import ChatAgent
|
|
23
|
-
from camel.messages.base import BaseMessage
|
|
24
|
-
from camel.tasks.task import Task, TaskState
|
|
25
|
-
from camel.workforce.base import BaseNode
|
|
26
|
-
from camel.workforce.single_agent_node import SingleAgentNode
|
|
27
|
-
from camel.workforce.task_channel import TaskChannel
|
|
28
|
-
from camel.workforce.utils import (
|
|
29
|
-
check_if_running,
|
|
30
|
-
parse_assign_task_resp,
|
|
31
|
-
parse_create_node_resp,
|
|
32
|
-
)
|
|
33
|
-
from camel.workforce.worker_node import WorkerNode
|
|
34
|
-
from camel.workforce.workforce_prompt import (
|
|
35
|
-
ASSIGN_TASK_PROMPT,
|
|
36
|
-
CREATE_NODE_PROMPT,
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class ManagerNode(BaseNode):
|
|
41
|
-
r"""A node that manages multiple nodes. It will split the task it
|
|
42
|
-
receives into subtasks and assign them to the child nodes under
|
|
43
|
-
it, and also handles the situation when the task fails.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
description (str): Description of the node.
|
|
47
|
-
coordinator_agent_kwargs (Optional[Dict]): Keyword arguments for the
|
|
48
|
-
coordinator agent, e.g. `model`, `api_key`, `tools`, etc.
|
|
49
|
-
task_agent_kwargs (Optional[Dict]): Keyword arguments for the task
|
|
50
|
-
agent, e.g. `model`, `api_key`, `tools`, etc.
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
def __init__(
|
|
54
|
-
self,
|
|
55
|
-
description: str,
|
|
56
|
-
children: List[BaseNode],
|
|
57
|
-
coordinator_agent_kwargs: Optional[Dict] = None,
|
|
58
|
-
task_agent_kwargs: Optional[Dict] = None,
|
|
59
|
-
) -> None:
|
|
60
|
-
super().__init__(description)
|
|
61
|
-
self._child_listening_tasks: Deque[asyncio.Task] = deque()
|
|
62
|
-
self._children = children
|
|
63
|
-
|
|
64
|
-
coord_agent_sysmsg = BaseMessage.make_assistant_message(
|
|
65
|
-
role_name="Workforce Manager",
|
|
66
|
-
content="You are coordinating a group of workers. A worker can be "
|
|
67
|
-
"a group of agents or a single agent. Each worker is created to"
|
|
68
|
-
" solve a specific kind of task. Your job includes assigning "
|
|
69
|
-
"tasks to a existing worker, creating a new worker for a task, "
|
|
70
|
-
"etc.",
|
|
71
|
-
)
|
|
72
|
-
self.coordinator_agent = ChatAgent(
|
|
73
|
-
coord_agent_sysmsg, **(coordinator_agent_kwargs or {})
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
task_sys_msg = BaseMessage.make_assistant_message(
|
|
77
|
-
role_name="Task Planner",
|
|
78
|
-
content="You are going to compose and decompose tasks.",
|
|
79
|
-
)
|
|
80
|
-
self.task_agent = ChatAgent(task_sys_msg, **(task_agent_kwargs or {}))
|
|
81
|
-
|
|
82
|
-
# if there is one, will set by the workforce class wrapping this
|
|
83
|
-
self._task: Optional[Task] = None
|
|
84
|
-
self._pending_tasks: Deque[Task] = deque()
|
|
85
|
-
|
|
86
|
-
@check_if_running(False)
|
|
87
|
-
def set_main_task(self, task: Task) -> None:
|
|
88
|
-
r"""Set the main task for the node."""
|
|
89
|
-
self._task = task
|
|
90
|
-
|
|
91
|
-
def _get_child_nodes_info(self) -> str:
|
|
92
|
-
r"""Get the information of all the child nodes under this node."""
|
|
93
|
-
return '\n'.join(
|
|
94
|
-
f'{child.node_id}: {child.description}' for child in self._children
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def _find_assignee(
|
|
98
|
-
self,
|
|
99
|
-
task: Task,
|
|
100
|
-
failed_log: Optional[str] = None,
|
|
101
|
-
) -> str:
|
|
102
|
-
r"""Assigns a task to a child node if capable, otherwise create a
|
|
103
|
-
new worker node.
|
|
104
|
-
|
|
105
|
-
Parameters:
|
|
106
|
-
task (Task): The task to be assigned.
|
|
107
|
-
failed_log (Optional[str]): Optional log of a previous failed
|
|
108
|
-
attempt.
|
|
109
|
-
|
|
110
|
-
Returns:
|
|
111
|
-
str: ID of the assigned node.
|
|
112
|
-
"""
|
|
113
|
-
prompt = ASSIGN_TASK_PROMPT.format(
|
|
114
|
-
content=task.content,
|
|
115
|
-
child_nodes_info=self._get_child_nodes_info(),
|
|
116
|
-
)
|
|
117
|
-
req = BaseMessage.make_user_message(
|
|
118
|
-
role_name="User",
|
|
119
|
-
content=prompt,
|
|
120
|
-
)
|
|
121
|
-
response = self.coordinator_agent.step(req)
|
|
122
|
-
try:
|
|
123
|
-
print(f"{Fore.YELLOW}{response.msg.content}{Fore.RESET}")
|
|
124
|
-
assignee_id = parse_assign_task_resp(response.msg.content)
|
|
125
|
-
except ValueError:
|
|
126
|
-
assignee_id = self._create_worker_node_for_task(task).node_id
|
|
127
|
-
return assignee_id
|
|
128
|
-
|
|
129
|
-
async def _post_task(self, task: Task, assignee_id: str) -> None:
|
|
130
|
-
await self._channel.post_task(task, self.node_id, assignee_id)
|
|
131
|
-
|
|
132
|
-
async def _post_dependency(self, dependency: Task) -> None:
|
|
133
|
-
await self._channel.post_dependency(dependency, self.node_id)
|
|
134
|
-
|
|
135
|
-
def _create_worker_node_for_task(self, task: Task) -> WorkerNode:
|
|
136
|
-
r"""Creates a new worker node for a given task and add it to the
|
|
137
|
-
children list of this node. This is one of the actions that
|
|
138
|
-
the coordinator can take when a task has failed.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
task (Task): The task for which the worker node is created.
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
WorkerNode: The created worker node.
|
|
145
|
-
"""
|
|
146
|
-
prompt = CREATE_NODE_PROMPT.format(
|
|
147
|
-
content=task.content,
|
|
148
|
-
child_nodes_info=self._get_child_nodes_info(),
|
|
149
|
-
)
|
|
150
|
-
req = BaseMessage.make_user_message(
|
|
151
|
-
role_name="User",
|
|
152
|
-
content=prompt,
|
|
153
|
-
)
|
|
154
|
-
response = self.coordinator_agent.step(req)
|
|
155
|
-
new_node_conf = parse_create_node_resp(response.msg.content)
|
|
156
|
-
|
|
157
|
-
worker_sysmsg = BaseMessage.make_assistant_message(
|
|
158
|
-
role_name=new_node_conf.role,
|
|
159
|
-
content=new_node_conf.system,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# TODO: add a default selection of tools for the worker
|
|
163
|
-
worker = ChatAgent(worker_sysmsg)
|
|
164
|
-
|
|
165
|
-
new_node = SingleAgentNode(
|
|
166
|
-
description=new_node_conf.description,
|
|
167
|
-
worker=worker,
|
|
168
|
-
)
|
|
169
|
-
new_node.set_channel(self._channel)
|
|
170
|
-
|
|
171
|
-
print(
|
|
172
|
-
f"{Fore.GREEN}New worker node {new_node.node_id} created."
|
|
173
|
-
f"{Fore.RESET}"
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
self._children.append(new_node)
|
|
177
|
-
self._child_listening_tasks.append(
|
|
178
|
-
asyncio.create_task(new_node.start())
|
|
179
|
-
)
|
|
180
|
-
return new_node
|
|
181
|
-
|
|
182
|
-
async def _get_returned_task(self) -> Task:
|
|
183
|
-
r"""Get the task that's published by this node and just get returned
|
|
184
|
-
from the assignee.
|
|
185
|
-
"""
|
|
186
|
-
return await self._channel.get_returned_task_by_publisher(self.node_id)
|
|
187
|
-
|
|
188
|
-
async def _post_ready_tasks(self) -> None:
|
|
189
|
-
r"""Send all the pending tasks that have all the dependencies met to
|
|
190
|
-
the channel, or directly return if there is none. For now, we will
|
|
191
|
-
directly send the first task in the pending list because all the tasks
|
|
192
|
-
are linearly dependent."""
|
|
193
|
-
|
|
194
|
-
if not self._pending_tasks:
|
|
195
|
-
return
|
|
196
|
-
|
|
197
|
-
ready_task = self._pending_tasks[0]
|
|
198
|
-
|
|
199
|
-
# if the task has failed previously, just compose and send the task
|
|
200
|
-
# to the channel as a dependency
|
|
201
|
-
if ready_task.state == TaskState.FAILED:
|
|
202
|
-
# TODO: the composing of tasks seems not work very well
|
|
203
|
-
ready_task.compose(self.task_agent)
|
|
204
|
-
# remove the subtasks from the channel
|
|
205
|
-
for subtask in ready_task.subtasks:
|
|
206
|
-
await self._channel.remove_task(subtask.id)
|
|
207
|
-
# send the task to the channel as a dependency
|
|
208
|
-
await self._post_dependency(ready_task)
|
|
209
|
-
self._pending_tasks.popleft()
|
|
210
|
-
# try to send the next task in the pending list
|
|
211
|
-
await self._post_ready_tasks()
|
|
212
|
-
else:
|
|
213
|
-
# directly post the task to the channel if it's a new one
|
|
214
|
-
# find a node to assign the task
|
|
215
|
-
assignee_id = self._find_assignee(task=ready_task)
|
|
216
|
-
await self._post_task(ready_task, assignee_id)
|
|
217
|
-
|
|
218
|
-
async def _handle_failed_task(self, task: Task) -> None:
|
|
219
|
-
# remove the failed task from the channel
|
|
220
|
-
await self._channel.remove_task(task.id)
|
|
221
|
-
if task.get_depth() >= 3:
|
|
222
|
-
# create a new WF and reassign
|
|
223
|
-
# TODO: add a state for reassign?
|
|
224
|
-
assignee = self._create_worker_node_for_task(task)
|
|
225
|
-
# print('create_new_assignee:', assignee)
|
|
226
|
-
await self._post_task(task, assignee.node_id)
|
|
227
|
-
else:
|
|
228
|
-
subtasks = task.decompose(self.task_agent)
|
|
229
|
-
# Insert packets at the head of the queue
|
|
230
|
-
self._pending_tasks.extendleft(reversed(subtasks))
|
|
231
|
-
await self._post_ready_tasks()
|
|
232
|
-
|
|
233
|
-
async def _handle_completed_task(self, task: Task) -> None:
|
|
234
|
-
# archive the packet, making it into a dependency
|
|
235
|
-
self._pending_tasks.popleft()
|
|
236
|
-
await self._channel.archive_task(task.id)
|
|
237
|
-
await self._post_ready_tasks()
|
|
238
|
-
|
|
239
|
-
@check_if_running(False)
|
|
240
|
-
def set_channel(self, channel: TaskChannel):
|
|
241
|
-
r"""Set the channel for the node and all the child nodes under it."""
|
|
242
|
-
self._channel = channel
|
|
243
|
-
for child in self._children:
|
|
244
|
-
child.set_channel(channel)
|
|
245
|
-
|
|
246
|
-
@check_if_running(False)
|
|
247
|
-
async def _listen_to_channel(self) -> None:
|
|
248
|
-
r"""Continuously listen to the channel, post task to the channel and
|
|
249
|
-
track the status of posted tasks.
|
|
250
|
-
"""
|
|
251
|
-
|
|
252
|
-
self._running = True
|
|
253
|
-
print(f"{Fore.GREEN}Manager node {self.node_id} started.{Fore.RESET}")
|
|
254
|
-
|
|
255
|
-
# if this node is at the top level, it will have an initial task
|
|
256
|
-
# the initial task must be decomposed into subtasks first
|
|
257
|
-
if self._task is not None:
|
|
258
|
-
subtasks = self._task.decompose(self.task_agent)
|
|
259
|
-
self._pending_tasks.extend(subtasks)
|
|
260
|
-
self._task.state = TaskState.FAILED
|
|
261
|
-
self._pending_tasks.append(self._task)
|
|
262
|
-
|
|
263
|
-
# before starting the loop, send ready pending tasks to the channel
|
|
264
|
-
await self._post_ready_tasks()
|
|
265
|
-
|
|
266
|
-
await self._channel.print_channel()
|
|
267
|
-
|
|
268
|
-
while self._task is None or self._pending_tasks:
|
|
269
|
-
returned_task = await self._get_returned_task()
|
|
270
|
-
if returned_task.state == TaskState.DONE:
|
|
271
|
-
await self._handle_completed_task(returned_task)
|
|
272
|
-
elif returned_task.state == TaskState.FAILED:
|
|
273
|
-
await self._handle_failed_task(returned_task)
|
|
274
|
-
else:
|
|
275
|
-
raise ValueError(
|
|
276
|
-
f"Task {returned_task.id} has an unexpected state."
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
# shut down the whole workforce tree
|
|
280
|
-
self.stop()
|
|
281
|
-
|
|
282
|
-
@check_if_running(False)
|
|
283
|
-
async def start(self) -> None:
|
|
284
|
-
r"""Start itself and all the child nodes under it."""
|
|
285
|
-
for child in self._children:
|
|
286
|
-
child_listening_task = asyncio.create_task(child.start())
|
|
287
|
-
self._child_listening_tasks.append(child_listening_task)
|
|
288
|
-
await self._listen_to_channel()
|
|
289
|
-
|
|
290
|
-
@check_if_running(True)
|
|
291
|
-
def stop(self) -> None:
|
|
292
|
-
r"""Stop all the child nodes under it. The node itself will be stopped
|
|
293
|
-
by its parent node.
|
|
294
|
-
"""
|
|
295
|
-
for child in self._children:
|
|
296
|
-
child.stop()
|
|
297
|
-
for child_task in self._child_listening_tasks:
|
|
298
|
-
child_task.cancel()
|
|
299
|
-
self._running = False
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the “License”);
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
#
|
|
6
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
-
#
|
|
8
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an “AS IS” BASIS,
|
|
10
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
-
# See the License for the specific language governing permissions and
|
|
12
|
-
# limitations under the License.
|
|
13
|
-
# =========== Copyright 2023 @ CAMEL-AI.org. All Rights Reserved. ===========
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
from typing import Dict, List, Optional
|
|
17
|
-
|
|
18
|
-
from colorama import Fore, Style
|
|
19
|
-
|
|
20
|
-
from camel.agents.chat_agent import ChatAgent, FunctionCallingRecord
|
|
21
|
-
from camel.messages.base import BaseMessage
|
|
22
|
-
from camel.societies import RolePlaying
|
|
23
|
-
from camel.tasks.task import Task, TaskState
|
|
24
|
-
from camel.utils import print_text_animated
|
|
25
|
-
from camel.workforce.utils import parse_task_result_resp
|
|
26
|
-
from camel.workforce.worker_node import WorkerNode
|
|
27
|
-
from camel.workforce.workforce_prompt import (
|
|
28
|
-
ROLEPLAY_PROCESS_TASK_PROMPT,
|
|
29
|
-
ROLEPLAY_SUMMERIZE_PROMPT,
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class RolePlayingNode(WorkerNode):
|
|
34
|
-
r"""A worker node that contains a role playing.
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
description (str): Description of the node.
|
|
38
|
-
assistant_role_name (str): The role name of the assistant agent.
|
|
39
|
-
user_role_name (str): The role name of the user agent.
|
|
40
|
-
assistant_agent_kwargs (Optional[Dict], optional): The keyword
|
|
41
|
-
arguments to initialize the assistant agent in the role playing,
|
|
42
|
-
like the model name, etc. Defaults to None.
|
|
43
|
-
user_agent_kwargs (Optional[Dict], optional): The keyword arguments to
|
|
44
|
-
initialize the user agent in the role playing, like the model name,
|
|
45
|
-
etc. Defaults to None.
|
|
46
|
-
chat_turn_limit (int, optional): The maximum number of chat turns in
|
|
47
|
-
the role playing. Defaults to 3.
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
def __init__(
|
|
51
|
-
self,
|
|
52
|
-
description: str,
|
|
53
|
-
assistant_role_name: str,
|
|
54
|
-
user_role_name: str,
|
|
55
|
-
assistant_agent_kwargs: Optional[Dict] = None,
|
|
56
|
-
user_agent_kwargs: Optional[Dict] = None,
|
|
57
|
-
chat_turn_limit: int = 3,
|
|
58
|
-
) -> None:
|
|
59
|
-
super().__init__(description)
|
|
60
|
-
sys_message = BaseMessage.make_assistant_message(
|
|
61
|
-
role_name="Summarizer",
|
|
62
|
-
content="Good at summarizing the results of the chat logs",
|
|
63
|
-
)
|
|
64
|
-
self.summerize_agent = ChatAgent(sys_message)
|
|
65
|
-
self.chat_turn_limit = chat_turn_limit
|
|
66
|
-
self.assistant_role_name = assistant_role_name
|
|
67
|
-
self.user_role_name = user_role_name
|
|
68
|
-
self.assistant_agent_kwargs = assistant_agent_kwargs
|
|
69
|
-
self.user_agent_kwargs = user_agent_kwargs
|
|
70
|
-
|
|
71
|
-
async def _process_task(
|
|
72
|
-
self, task: Task, dependencies: List[Task]
|
|
73
|
-
) -> TaskState:
|
|
74
|
-
r"""Processes a task leveraging its dependencies through role-playing.
|
|
75
|
-
|
|
76
|
-
This method orchestrates a role-playing session between an AI
|
|
77
|
-
assistant and an AI user to process a given task. It initiates with a
|
|
78
|
-
generated prompt based on the task and its dependencies, conducts a
|
|
79
|
-
dialogue up to a specified chat turn limit, and then summarizes the
|
|
80
|
-
dialogue to determine the task's outcome.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
task (Task): The task object to be processed, containing necessary
|
|
84
|
-
details like content and type.
|
|
85
|
-
dependencies (List[Task]): A list of task objects that the current
|
|
86
|
-
task depends on.
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
TaskState: `TaskState.DONE` if processed successfully, otherwise
|
|
90
|
-
`TaskState.FAILED`.
|
|
91
|
-
"""
|
|
92
|
-
try:
|
|
93
|
-
dependency_tasks_info = self._get_dep_tasks_info(dependencies)
|
|
94
|
-
prompt = ROLEPLAY_PROCESS_TASK_PROMPT.format(
|
|
95
|
-
content=task.content,
|
|
96
|
-
type=task.type,
|
|
97
|
-
dependency_task_info=dependency_tasks_info,
|
|
98
|
-
)
|
|
99
|
-
role_play_session = RolePlaying(
|
|
100
|
-
assistant_role_name=self.assistant_role_name,
|
|
101
|
-
user_role_name=self.user_role_name,
|
|
102
|
-
assistant_agent_kwargs=self.assistant_agent_kwargs,
|
|
103
|
-
user_agent_kwargs=self.user_agent_kwargs,
|
|
104
|
-
task_prompt=prompt,
|
|
105
|
-
with_task_specify=False,
|
|
106
|
-
)
|
|
107
|
-
n = 0
|
|
108
|
-
input_msg = role_play_session.init_chat()
|
|
109
|
-
chat_history = []
|
|
110
|
-
while n < self.chat_turn_limit:
|
|
111
|
-
n += 1
|
|
112
|
-
assistant_response, user_response = role_play_session.step(
|
|
113
|
-
input_msg
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
if assistant_response.terminated:
|
|
117
|
-
reason = assistant_response.info['termination_reasons']
|
|
118
|
-
print(
|
|
119
|
-
Fore.GREEN + f"AI Assistant terminated. Reason: "
|
|
120
|
-
f"{reason}. "
|
|
121
|
-
)
|
|
122
|
-
break
|
|
123
|
-
if user_response.terminated:
|
|
124
|
-
reason = user_response.info['termination_reasons']
|
|
125
|
-
print(
|
|
126
|
-
Fore.GREEN + f"AI User terminated. Reason: {reason}."
|
|
127
|
-
)
|
|
128
|
-
break
|
|
129
|
-
print_text_animated(
|
|
130
|
-
Fore.BLUE + f"AI User:\n\n{user_response.msg.content}\n",
|
|
131
|
-
delay=0.005,
|
|
132
|
-
)
|
|
133
|
-
chat_history.append(f"AI User: {user_response.msg.content}")
|
|
134
|
-
|
|
135
|
-
print_text_animated(Fore.GREEN + "AI Assistant:", delay=0.005)
|
|
136
|
-
tool_calls: List[FunctionCallingRecord] = (
|
|
137
|
-
assistant_response.info['tool_calls']
|
|
138
|
-
)
|
|
139
|
-
for func_record in tool_calls:
|
|
140
|
-
print_text_animated(f"{func_record}", delay=0.005)
|
|
141
|
-
print_text_animated(
|
|
142
|
-
f"{assistant_response.msg.content}\n", delay=0.005
|
|
143
|
-
)
|
|
144
|
-
chat_history.append(
|
|
145
|
-
f"AI Assistant: {assistant_response.msg.content}"
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
if "CAMEL_TASK_DONE" in user_response.msg.content:
|
|
149
|
-
break
|
|
150
|
-
|
|
151
|
-
input_msg = assistant_response.msg
|
|
152
|
-
|
|
153
|
-
chat_history_str = "\n".join(chat_history)
|
|
154
|
-
prompt = ROLEPLAY_SUMMERIZE_PROMPT.format(
|
|
155
|
-
content=task.content,
|
|
156
|
-
type=task.type,
|
|
157
|
-
chat_history=chat_history_str,
|
|
158
|
-
)
|
|
159
|
-
req = BaseMessage.make_user_message(
|
|
160
|
-
role_name="User",
|
|
161
|
-
content=prompt,
|
|
162
|
-
)
|
|
163
|
-
response = self.summerize_agent.step(req)
|
|
164
|
-
task.result = parse_task_result_resp(response.msg.content)
|
|
165
|
-
print(Style.RESET_ALL + 'Task result:', task.result, '\n')
|
|
166
|
-
return TaskState.DONE
|
|
167
|
-
except Exception:
|
|
168
|
-
return TaskState.FAILED
|