ag2 0.9.1.post0__py3-none-any.whl → 0.9.2__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 ag2 might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ag2
3
- Version: 0.9.1.post0
3
+ Version: 0.9.2
4
4
  Summary: A programming framework for agentic AI
5
5
  Project-URL: Homepage, https://ag2.ai/
6
6
  Project-URL: Documentation, https://docs.ag2.ai
@@ -199,6 +199,12 @@ Requires-Dist: sympy; extra == 'mathchat'
199
199
  Requires-Dist: wolframalpha; extra == 'mathchat'
200
200
  Provides-Extra: mcp
201
201
  Requires-Dist: mcp<1.6,>=1.4.0; (python_version >= '3.10') and extra == 'mcp'
202
+ Provides-Extra: mcp-proxy-gen
203
+ Requires-Dist: fastapi-code-generator>=0.5.4; extra == 'mcp-proxy-gen'
204
+ Requires-Dist: fastapi<1,>=0.112; extra == 'mcp-proxy-gen'
205
+ Requires-Dist: pyyaml; extra == 'mcp-proxy-gen'
206
+ Requires-Dist: requests; extra == 'mcp-proxy-gen'
207
+ Requires-Dist: typer; extra == 'mcp-proxy-gen'
202
208
  Provides-Extra: mistral
203
209
  Requires-Dist: mistralai>=1.0.1; extra == 'mistral'
204
210
  Provides-Extra: neo4j
@@ -613,7 +619,7 @@ teacher.initiate_chat(
613
619
 
614
620
  When executed, this code creates a collaborative system where the teacher initiates the conversation, and the lesson planner and reviewer agents work together to create and refine a lesson plan. The GroupChatManager orchestrates the conversation, selecting the next agent to respond based on the context of the discussion.
615
621
 
616
- For workflows requiring more structured processes, explore the Swarm pattern in the detailed [documentation](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/conversation-patterns-deep-dive).
622
+ For workflows requiring more structured processes, explore the Group Chat pattern in the detailed [documentation](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/orchestration/group-chat/introduction).
617
623
 
618
624
  ### Tools
619
625
 
@@ -674,7 +680,7 @@ AG2 supports more advanced concepts to help you build your AI agent workflows. Y
674
680
  - [Ending a conversation](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/orchestration/ending-a-chat/)
675
681
  - [Retrieval Augmented Generation (RAG)](https://docs.ag2.ai/docs/user-guide/advanced-concepts/rag)
676
682
  - [Code Execution](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/code-execution)
677
- - [Tools with Secrets](https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/introducing-tools/tools-with-secrets)
683
+ - [Tools with Secrets](https://docs.ag2.ai/latest/docs/user-guide/advanced-concepts/tools/tools-with-secrets/)
678
684
 
679
685
  ## Announcements
680
686
 
@@ -8,13 +8,13 @@ autogen/function_utils.py,sha256=YnzwNFA49Jbbe4riAY1sinYcKphg5lrHFCXx0POdYbw,481
8
8
  autogen/graph_utils.py,sha256=2dfGUHZCCF629vh0vMK9WMXIX-Zi-if9NbdC0KFcuw4,7904
9
9
  autogen/import_utils.py,sha256=byPlexRvu1bkGzEAtwwtJ2SQIm1IzModK9B5ONGkqJw,17634
10
10
  autogen/json_utils.py,sha256=_61k__3SS1-ffE2K5Mm9ZGHQJBRUbOL9kHGQGTAWRZk,1378
11
- autogen/llm_config.py,sha256=Vpm23hwFj_Xi6dzkPHpPv20P1Xeo4pUFPhhHTDsOncI,14107
11
+ autogen/llm_config.py,sha256=eFWSN9yR3w2R7d2CdDQ5ZpU2tUy8xBzEwGuq5K6QZLs,14172
12
12
  autogen/math_utils.py,sha256=Ew9-I5chny9eAOnphGxKf6XCeW6Pepz5S-5touWrbYU,9546
13
13
  autogen/retrieve_utils.py,sha256=R3Yp5d8dH4o9ayLZrGn4rCjIaY4glOHIiyQjwClmdi8,20087
14
14
  autogen/runtime_logging.py,sha256=yCmZODvwqYR91m8lX3Q4SoPcY-DK48NF4m56CP6Om3c,4692
15
15
  autogen/token_count_utils.py,sha256=n4wTFVNHwrfjZkrErFr8kNig2K-YCGgMLWsjDRS9D6g,10797
16
16
  autogen/types.py,sha256=qu-7eywhakW2AxQ5lYisLLeIg45UoOW-b3ErIuyRTuw,1000
17
- autogen/version.py,sha256=YukZ5zIFYpMhlQ_olcWkkgdY7RATOWxDna2VVuOd3NI,198
17
+ autogen/version.py,sha256=zvCJ0lHDfEBMWZDWk8uOP6RODc_0sB12xDf8whkwhGc,193
18
18
  autogen/_website/__init__.py,sha256=c8B9TpO07x9neD0zsJWj6AaEdlcP-WvxrvVOGWLtamk,143
19
19
  autogen/_website/generate_api_references.py,sha256=yKqyeSP_NE27wwLYWsZbTYRceEoxzNxPXqn6vsIzEvk,14789
20
20
  autogen/_website/generate_mkdocs.py,sha256=TkmLnUDv1Ms5cGClXPmenA8nxmwg4kR0E-FHCVjw_og,43246
@@ -25,7 +25,7 @@ autogen/agentchat/__init__.py,sha256=d5jPpXeavynP9eh5uMIgJKbK3-3tywJBa6l3L9X4l34
25
25
  autogen/agentchat/agent.py,sha256=HePNJ5BXJTcZtaD2a8CoTeHAoLUUy3scM6Ihm-NsSWk,5828
26
26
  autogen/agentchat/assistant_agent.py,sha256=XTJvD66r4qYkdNAJJLr1CC-wTYFJWvhmD5_G0WbbX2I,5741
27
27
  autogen/agentchat/chat.py,sha256=6Gx2t1-Xa8kP6ZoUihHBNGOqNlrGhhqLPKrckL0n-RI,14003
28
- autogen/agentchat/conversable_agent.py,sha256=x2-UQzDJ_dhteicsS2eAKRTG8ozDrqdWh0ZawuFy6iI,191305
28
+ autogen/agentchat/conversable_agent.py,sha256=F5OtTxBYb4Cqw5cp6V1gt8tL6EVVFuAKmbCR9SVosT8,191085
29
29
  autogen/agentchat/groupchat.py,sha256=eh_JNZWU-0gbxO7rIngokh71kpHLkA1Qunn6zXDdM0k,85361
30
30
  autogen/agentchat/user_proxy_agent.py,sha256=-gbDblRvE09FGuVB6-y5ZT9Cpvv--rM3FMi8PnPIFBA,7445
31
31
  autogen/agentchat/utils.py,sha256=2ZweUqe4ynxji0jnvd0r9Uxg3n0elif4a-jZOyeeqcg,8238
@@ -226,7 +226,7 @@ autogen/coding/jupyter/jupyter_client.py,sha256=ROXAWOKG_EJ_oFNuyqUd_3uOBPUTRoTh
226
226
  autogen/coding/jupyter/jupyter_code_executor.py,sha256=Z2vZvou6QzpMBg0IgOzVRoCADswd15mvfkktIjGhUMY,6374
227
227
  autogen/coding/jupyter/local_jupyter_server.py,sha256=7b8yi5qK8ms2e5-PRCrzmXKGp1iC5KgpMU8xiqQ9u8o,6589
228
228
  autogen/events/__init__.py,sha256=XwCA6Rsq9AyjgeecGuiwHcAvDQMmKXgGomw5iLDIU5Q,358
229
- autogen/events/agent_events.py,sha256=jY5WZa4uetm9bp42pMFjpggL_HWNpiJqAG5vAl27bUY,30651
229
+ autogen/events/agent_events.py,sha256=G4SO8DlXyeiBvUVW0z8BuOGpUpcUXjF6mzbDxW9Nn-w,30789
230
230
  autogen/events/base_event.py,sha256=5K1wzDBAio9wLxahErSvE0-UbFfMuSTxBp6EI8SbPGU,3475
231
231
  autogen/events/client_events.py,sha256=2skE5f9BxQmwJv22vNe-s1ReDXE-DsadeAmMWlrmltc,5466
232
232
  autogen/events/helpers.py,sha256=CMcetNzfCE-dWTTJ_9B09of2slRG43yYnHXvFfuGz2Q,1185
@@ -256,7 +256,7 @@ autogen/interop/langchain/__init__.py,sha256=8v-kdg4ImQ1Udzd8Y6r7DTvd760SgWkwNKz
256
256
  autogen/interop/langchain/langchain_chat_model_factory.py,sha256=Jv6Q-SFcaAk9e20fBu92ZZgEEShnUJDqbP5XTZravhE,5591
257
257
  autogen/interop/langchain/langchain_tool.py,sha256=2njJVv17ApNiei-ZJvpZhKFderwQIpmOAxNzx_jQmFM,3132
258
258
  autogen/interop/litellm/__init__.py,sha256=0K9NkQEBXKZI6UVNwD4daTumQL-uhMrAJE33wiSYmkI,237
259
- autogen/interop/litellm/litellm_config_factory.py,sha256=Zfc1UvPDQfccz1bxQGmUDLsS0sj-kCBFilrLjHFjSa0,3995
259
+ autogen/interop/litellm/litellm_config_factory.py,sha256=NiyU0fCCMu5uerirGLu2MR45x_xvAFIVFEJaG5bw4mY,6289
260
260
  autogen/interop/pydantic_ai/__init__.py,sha256=w9tqh96x43Ipq2loD_F-kqwws2RFRs7-98mPxWG-Mjc,238
261
261
  autogen/interop/pydantic_ai/pydantic_ai.py,sha256=ux0V3J37rrT80FCYwkEui3UjsMwUyLd1yfUOidVa4ks,6680
262
262
  autogen/io/__init__.py,sha256=c5iZkM24B9j3K0yPQ0HYJnvAdNMqhlRZVXqcfdnGFX4,600
@@ -275,7 +275,16 @@ autogen/logger/logger_factory.py,sha256=CeLbW3gN0J5zgvQSsRLCSnaiMYusrDWLWovo_Bk-
275
275
  autogen/logger/logger_utils.py,sha256=H9hcsRyEcUcfxTYWf5cRjtNghF4h3FT8sr4IIuqQumY,2053
276
276
  autogen/logger/sqlite_logger.py,sha256=sRwMx42zh85QWLz1BqKyVySI8OwEB_NjM3ObLOW-mcI,18685
277
277
  autogen/mcp/__init__.py,sha256=6BDDmw0sjLZRjyHnd-Gfh9BE-pTKTv5bkow9W6odHtQ,213
278
+ autogen/mcp/__main__.py,sha256=C7nXbWxG3yGsWKRgFnhSsbQOmshLnz6ZOcCxK2TWWio,2487
278
279
  autogen/mcp/mcp_client.py,sha256=7c_lHgBJEs77TFYjLcTlVrEu_0z4EafPPY3PgteY87c,7400
280
+ autogen/mcp/mcp_proxy/__init__.py,sha256=3HTU-TqHLk4XSXeBV1UFd9XkQ1B0yOuXXyGseXvDVec,518
281
+ autogen/mcp/mcp_proxy/fastapi_code_generator_helpers.py,sha256=dx-w2tGVMnh8pzY2NuXlMD7oIF7_5Gvc5oSbHIySEpc,2110
282
+ autogen/mcp/mcp_proxy/mcp_proxy.py,sha256=k2_FZyvCtF0h1CxL_VRL0rWMEuzmU42SpB6JCNbk9zc,22112
283
+ autogen/mcp/mcp_proxy/operation_grouping.py,sha256=1n4o5qhkQd2hVr7OaOMsRhInDveDGkCozLudsBVusC4,6349
284
+ autogen/mcp/mcp_proxy/operation_renaming.py,sha256=G5J4VdxUAwSvOo-DsqIUbCfV9TnH3riaHLI6IpctDF8,3956
285
+ autogen/mcp/mcp_proxy/patch_fastapi_code_generator.py,sha256=vBr8P890nsFvK4iuFicrdNskooHlBQeTQ6jbb5kcPAk,3490
286
+ autogen/mcp/mcp_proxy/security.py,sha256=HUcdIE1CCmvuWBPUlvjoKOJV-05sve6pcKHalgm9Z8E,13611
287
+ autogen/mcp/mcp_proxy/security_schema_visitor.py,sha256=UafLMd5zcz0COcc5Vfvt6bP3LQ3jmaBwQIlWhovN9H4,1345
279
288
  autogen/messages/__init__.py,sha256=ZuLvvIQRkNE5fotPe6MSS_YzOUkmfIqGSfOZZOZQ3go,321
280
289
  autogen/messages/agent_messages.py,sha256=ZnRkdWcKS20lW2Njt740m2YNfKanHt8C3k84KKbzR8E,30414
281
290
  autogen/messages/base_message.py,sha256=MbYEXM0dWHl31y7o08PGeJNcpK67hpoQpUMgnZ8qTGE,3808
@@ -285,11 +294,11 @@ autogen/oai/__init__.py,sha256=BIwnV6wtHmKgIM4IUdymfPfpdNqos5P7BfRv-7_QL9A,1680
285
294
  autogen/oai/anthropic.py,sha256=AK_Bbcc5I-PqAvoiwB0LaO1ZLugh_wQNAOIFcj7eTtk,29174
286
295
  autogen/oai/bedrock.py,sha256=8AYWZVsDkJS2HmQ0ggoUqlKV_a4H_ON8rks4VW2Jrxk,25719
287
296
  autogen/oai/cerebras.py,sha256=8hiSBq88l2yTXUJPV7AvGXRCtwvW0Y9hIYUnYK2S2os,12462
288
- autogen/oai/client.py,sha256=oy90ySCTmsAO-4p2VF40IZfHAvZdoI6q5_SIq7aLz5g,64571
297
+ autogen/oai/client.py,sha256=BB_6Heny6_7lq8q7ZAPKohHAK63zs9UGzRoUknTxjYY,65051
289
298
  autogen/oai/client_utils.py,sha256=lVbHyff7OnpdM-tXskC23xLdFccj2AalTdWA4DxzxS4,7543
290
299
  autogen/oai/cohere.py,sha256=pRcQWjbzKbZ1RfC1vk9WGjgndwjHbIaOVoKEYdV2L6c,19421
291
- autogen/oai/gemini.py,sha256=-SgJaRvJ9cv79Ktpv88ZUTySa7M0n4bC_IcqtvXsmr8,41692
292
- autogen/oai/gemini_types.py,sha256=pEJFkDhHx91u5_TMFTV9b8nzho0DD5Pgyf3amBeEnCA,4735
300
+ autogen/oai/gemini.py,sha256=c0uA8FKpU1S3GpN7sKwU96uHbA1wEtlWHodwZvwMP58,41884
301
+ autogen/oai/gemini_types.py,sha256=jRai-e2Qf73Yga17xm33OwKtkcU1oOKLITzFNB68LSg,5759
293
302
  autogen/oai/groq.py,sha256=pQWtaAY_AjT30XKbZNHXDzWsawBys3yFWlfy6K4Nqr8,12431
294
303
  autogen/oai/mistral.py,sha256=SlOYPdnNLHuTEHBGCzsemG9sLEgphdUukRurERdMsvI,12677
295
304
  autogen/oai/ollama.py,sha256=t0fIgDCoIfsQZ3hhpseam5N-fbpI7-fw82bG55mA8nU,29103
@@ -311,7 +320,7 @@ autogen/tools/toolkit.py,sha256=1tOmTGJ96RhkJrrtAViKUyEcwacA6ztoIbYbnf8NgTU,2558
311
320
  autogen/tools/contrib/__init__.py,sha256=DWEjPK6xCR2ihAXXdquQZmiuqRLA3Pqb8QV8W1RtS3k,202
312
321
  autogen/tools/contrib/time/__init__.py,sha256=dplie5aBJZ8VoKy6EKcQMLTtSgcCkNDYzpdsC2I0YWk,195
313
322
  autogen/tools/contrib/time/time.py,sha256=tPi49vOUwfvujbYA-zS00CWcLW-y18CPyQ1gnJG6iRg,1271
314
- autogen/tools/experimental/__init__.py,sha256=3GcjpvEtTvBNPh0VLoWsSwtox2aDeOXABbyuD4PPln8,1249
323
+ autogen/tools/experimental/__init__.py,sha256=G399sJCbL3hV2HSU3eGnrrQ4i3a_P55LobmtcYYUrqU,1466
315
324
  autogen/tools/experimental/browser_use/__init__.py,sha256=kfxCajXcVMDH6CZq-lWh2p8PKxOwT9yjC_Za0jr4zUg,290
316
325
  autogen/tools/experimental/browser_use/browser_use.py,sha256=VEYJwUna_DM_HxeI5kgjhtTUzPBYlwrcGk5UOy85gDo,5426
317
326
  autogen/tools/experimental/crawl4ai/__init__.py,sha256=UjFJLSZ9P5xT6WCV0RDPtwt4MHuwPdK90TU7ByXhLWs,207
@@ -342,12 +351,17 @@ autogen/tools/experimental/messageplatform/telegram/__init__.py,sha256=gPhyMHRvu
342
351
  autogen/tools/experimental/messageplatform/telegram/telegram.py,sha256=i_rSZO8hgWcYrNKuRsgGVeIkIaw737IonPQtk7K5FjE,12332
343
352
  autogen/tools/experimental/perplexity/__init__.py,sha256=VxWG2HfcxwBhLUV4LnAlte9T2dH5dXIy-78gkPVfwSI,232
344
353
  autogen/tools/experimental/perplexity/perplexity_search.py,sha256=UZtyS9Pde3_VXufuZVuiBw87MiOiAWwVyXqstzE7Rlk,9976
354
+ autogen/tools/experimental/reliable/__init__.py,sha256=GLvfvsFLfBANFVcOptIa_Tm71YsHt5U7X5N9quqDZW0,479
355
+ autogen/tools/experimental/reliable/reliable.py,sha256=5s3aD5u-6JJrXqbSQBcW2qxNfyvx3MQ--IcZ6wMdsvE,64687
345
356
  autogen/tools/experimental/tavily/__init__.py,sha256=rvztagn7FpWiXZwJtZmKbIFBteBenaedwsiUViDyC4Y,220
346
357
  autogen/tools/experimental/tavily/tavily_search.py,sha256=S1Aj519kaEIwOAJXTc9Y__GHyY--vvc-P-5nh3ksCOQ,7810
347
358
  autogen/tools/experimental/web_search_preview/__init__.py,sha256=8vd1XWS14883MQ4U4dHvMP8aAKAtMILLnqRJNzgNh6A,233
348
359
  autogen/tools/experimental/web_search_preview/web_search_preview.py,sha256=bLKZSl0670uh82C3OCceRD0WaRfEPtQ4o06PTsQ3kKk,4818
349
360
  autogen/tools/experimental/wikipedia/__init__.py,sha256=jS_gUMyz-uCWr75yKv2esIiGz0ijNDNokt6wovQULLE,274
350
361
  autogen/tools/experimental/wikipedia/wikipedia.py,sha256=Cw7luG34J6if_5D40C_039BTA6l_LvOiEg6FY5UysC4,11545
362
+ templates/main.jinja2,sha256=UWDs5BU-h-L9daFPIy4OAkWFMu2-g5p1R759-yF6Oks,1729
363
+ templates/client_template/main.jinja2,sha256=HLXxq-DAqHyh_8PZ9uk6OVHB0RC6FZqKdIbnJQNJrLU,1978
364
+ templates/config_template/config.jinja2,sha256=A-p-YBsnEm1iftBIhuIBfIyCY-qw34KWcxalmM6KPWc,167
351
365
  autogen/agentchat/contrib/captainagent/tools/README.md,sha256=454O-irP4gjSdYnFgoE0i3BfueXO0qFONxe3GMxMpHg,1677
352
366
  autogen/agentchat/contrib/captainagent/tools/__init__.py,sha256=tOTe4nwbKj7elHpftAy3zS_embMDzncrKL98XKhY6-c,168
353
367
  autogen/agentchat/contrib/captainagent/tools/requirements.txt,sha256=z2uZXzuO-MT_d0EPrk9G3Ct2cQeS-KTj0p7HdgqiEYg,110
@@ -385,8 +399,8 @@ autogen/agentchat/contrib/captainagent/tools/math/modular_inverse_sum.py,sha256=
385
399
  autogen/agentchat/contrib/captainagent/tools/math/simplify_mixed_numbers.py,sha256=iqgpFJdyBHPPNCqkehSIbeuV8Rabr2eDMilT23Wx7PI,1687
386
400
  autogen/agentchat/contrib/captainagent/tools/math/sum_of_digit_factorials.py,sha256=-6T5r6Er4mONPldRxv3F9tLoE7Og3qmeSeTC7Du_tTg,596
387
401
  autogen/agentchat/contrib/captainagent/tools/math/sum_of_primes_below.py,sha256=Xig7K3A3DRnbv-UXfyo5bybGZUQYAQsltthfTYW5eV8,509
388
- ag2-0.9.1.post0.dist-info/METADATA,sha256=8X27ld0Dx4bVu445ftjyKFBba9qooBmme159PBE1L78,34793
389
- ag2-0.9.1.post0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
390
- ag2-0.9.1.post0.dist-info/licenses/LICENSE,sha256=GEFQVNayAR-S_rQD5l8hPdgvgyktVdy4Bx5-v90IfRI,11384
391
- ag2-0.9.1.post0.dist-info/licenses/NOTICE.md,sha256=07iCPQGbth4pQrgkSgZinJGT5nXddkZ6_MGYcBd2oiY,1134
392
- ag2-0.9.1.post0.dist-info/RECORD,,
402
+ ag2-0.9.2.dist-info/METADATA,sha256=w0e1Z82GEyYEh-kPA2PXa-nrXEPobW4vYHXSwHHmo-E,35095
403
+ ag2-0.9.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
404
+ ag2-0.9.2.dist-info/licenses/LICENSE,sha256=GEFQVNayAR-S_rQD5l8hPdgvgyktVdy4Bx5-v90IfRI,11384
405
+ ag2-0.9.2.dist-info/licenses/NOTICE.md,sha256=07iCPQGbth4pQrgkSgZinJGT5nXddkZ6_MGYcBd2oiY,1134
406
+ ag2-0.9.2.dist-info/RECORD,,
@@ -2321,6 +2321,21 @@ class ConversableAgent(LLMAgent):
2321
2321
 
2322
2322
  return False, None
2323
2323
 
2324
+ def _run_async_in_thread(self, coro):
2325
+ """Run an async coroutine in a separate thread with its own event loop."""
2326
+ result = {}
2327
+
2328
+ def runner():
2329
+ loop = asyncio.new_event_loop()
2330
+ asyncio.set_event_loop(loop)
2331
+ result["value"] = loop.run_until_complete(coro)
2332
+ loop.close()
2333
+
2334
+ t = threading.Thread(target=runner)
2335
+ t.start()
2336
+ t.join()
2337
+ return result["value"]
2338
+
2324
2339
  def generate_function_call_reply(
2325
2340
  self,
2326
2341
  messages: Optional[list[dict[str, Any]]] = None,
@@ -2342,18 +2357,8 @@ class ConversableAgent(LLMAgent):
2342
2357
  func_call = message["function_call"]
2343
2358
  func = self._function_map.get(func_call.get("name", None), None)
2344
2359
  if inspect.iscoroutinefunction(func):
2345
- try:
2346
- # get the running loop if it was already created
2347
- loop = asyncio.get_running_loop()
2348
- close_loop = False
2349
- except RuntimeError:
2350
- # create a loop if there is no running loop
2351
- loop = asyncio.new_event_loop()
2352
- close_loop = True
2353
-
2354
- _, func_return = loop.run_until_complete(self.a_execute_function(func_call, call_id=call_id))
2355
- if close_loop:
2356
- loop.close()
2360
+ coro = self.a_execute_function(func_call, call_id=call_id)
2361
+ _, func_return = self._run_async_in_thread(coro)
2357
2362
  else:
2358
2363
  _, func_return = self.execute_function(message["function_call"], call_id=call_id)
2359
2364
  return True, func_return
@@ -2409,18 +2414,8 @@ class ConversableAgent(LLMAgent):
2409
2414
  tool_call_id = tool_call.get("id", None)
2410
2415
  func = self._function_map.get(function_call.get("name", None), None)
2411
2416
  if inspect.iscoroutinefunction(func):
2412
- try:
2413
- # get the running loop if it was already created
2414
- loop = asyncio.get_running_loop()
2415
- close_loop = False
2416
- except RuntimeError:
2417
- # create a loop if there is no running loop
2418
- loop = asyncio.new_event_loop()
2419
- close_loop = True
2420
-
2421
- _, func_return = loop.run_until_complete(self.a_execute_function(function_call, call_id=tool_call_id))
2422
- if close_loop:
2423
- loop.close()
2417
+ coro = self.a_execute_function(function_call, call_id=tool_call_id)
2418
+ _, func_return = self._run_async_in_thread(coro)
2424
2419
  else:
2425
2420
  _, func_return = self.execute_function(function_call, call_id=tool_call_id)
2426
2421
  content = func_return.get("content", "")
@@ -3130,12 +3125,16 @@ class ConversableAgent(LLMAgent):
3130
3125
  arguments = {}
3131
3126
  content = f"Error: Function {func_name} not found."
3132
3127
 
3133
- if verbose:
3134
- iostream.send(
3135
- ExecutedFunctionEvent(
3136
- func_name=func_name, call_id=call_id, arguments=arguments, content=content, recipient=self
3137
- )
3128
+ iostream.send(
3129
+ ExecutedFunctionEvent(
3130
+ func_name=func_name,
3131
+ call_id=call_id,
3132
+ arguments=arguments,
3133
+ content=content,
3134
+ recipient=self,
3135
+ is_exec_success=is_exec_success,
3138
3136
  )
3137
+ )
3139
3138
 
3140
3139
  return is_exec_success, {
3141
3140
  "name": func_name,
@@ -3198,12 +3197,16 @@ class ConversableAgent(LLMAgent):
3198
3197
  arguments = {}
3199
3198
  content = f"Error: Function {func_name} not found."
3200
3199
 
3201
- if verbose:
3202
- iostream.send(
3203
- ExecutedFunctionEvent(
3204
- func_name=func_name, call_id=call_id, arguments=arguments, content=content, recipient=self
3205
- )
3200
+ iostream.send(
3201
+ ExecutedFunctionEvent(
3202
+ func_name=func_name,
3203
+ call_id=call_id,
3204
+ arguments=arguments,
3205
+ content=content,
3206
+ recipient=self,
3207
+ is_exec_success=is_exec_success,
3206
3208
  )
3209
+ )
3207
3210
 
3208
3211
  return is_exec_success, {
3209
3212
  "name": func_name,
@@ -763,9 +763,10 @@ class ExecuteFunctionEvent(BaseEvent):
763
763
  class ExecutedFunctionEvent(BaseEvent):
764
764
  func_name: str
765
765
  call_id: Optional[str] = None
766
- arguments: dict[str, Any]
767
- content: str
766
+ arguments: Optional[dict[str, Any]]
767
+ content: Any
768
768
  recipient: str
769
+ is_exec_success: bool = True
769
770
 
770
771
  def __init__(
771
772
  self,
@@ -773,9 +774,10 @@ class ExecutedFunctionEvent(BaseEvent):
773
774
  uuid: Optional[UUID] = None,
774
775
  func_name: str,
775
776
  call_id: Optional[str] = None,
776
- arguments: dict[str, Any],
777
- content: str,
777
+ arguments: Optional[dict[str, Any]],
778
+ content: Any,
778
779
  recipient: Union["Agent", str],
780
+ is_exec_success: bool = True,
779
781
  ):
780
782
  super().__init__(
781
783
  uuid=uuid,
@@ -785,6 +787,7 @@ class ExecutedFunctionEvent(BaseEvent):
785
787
  content=content,
786
788
  recipient=recipient.name if hasattr(recipient, "name") else recipient,
787
789
  )
790
+ self.is_exec_success = is_exec_success
788
791
 
789
792
  def print(self, f: Optional[Callable[..., Any]] = None) -> None:
790
793
  f = f or print
@@ -4,7 +4,7 @@
4
4
 
5
5
  import os
6
6
  from abc import ABC, abstractmethod
7
- from typing import Any, Callable, TypeVar, Union
7
+ from typing import Any, Callable, Optional, TypeVar, Union
8
8
 
9
9
  from ...doc_utils import export_module
10
10
  from ...llm_config import LLMConfig
@@ -15,19 +15,85 @@ __all__ = ["LiteLLmConfigFactory"]
15
15
  T = TypeVar("T", bound="LiteLLmConfigFactory")
16
16
 
17
17
 
18
+ def get_crawl4ai_version() -> Optional[str]:
19
+ """Get the installed crawl4ai version."""
20
+ try:
21
+ import crawl4ai
22
+
23
+ version = getattr(crawl4ai, "__version__", None)
24
+ return version if isinstance(version, str) else None
25
+ except (ImportError, AttributeError):
26
+ return None
27
+
28
+
29
+ def is_crawl4ai_v05_or_higher() -> bool:
30
+ """Check if crawl4ai version is 0.5 or higher."""
31
+ version = get_crawl4ai_version()
32
+ if version is None:
33
+ return False
34
+
35
+ # Parse version string (e.g., "0.5.0" -> [0, 5, 0])
36
+ try:
37
+ version_parts = [int(x) for x in version.split(".")]
38
+ # Check if version >= 0.5.0
39
+ return version_parts >= [0, 5, 0]
40
+ except (ValueError, IndexError):
41
+ return False
42
+
43
+
18
44
  @export_module("autogen.interop")
19
45
  class LiteLLmConfigFactory(ABC):
20
46
  _factories: set["LiteLLmConfigFactory"] = set()
21
47
 
22
48
  @classmethod
23
49
  def create_lite_llm_config(cls, llm_config: Union[LLMConfig, dict[str, Any]]) -> dict[str, Any]:
50
+ """
51
+ Create a lite LLM config compatible with the installed crawl4ai version.
52
+
53
+ For crawl4ai >=0.5: Returns config with llmConfig parameter
54
+ For crawl4ai <0.5: Returns config with provider parameter (legacy)
55
+ """
24
56
  first_llm_config = get_first_llm_config(llm_config)
25
57
  for factory in LiteLLmConfigFactory._factories:
26
58
  if factory.accepts(first_llm_config):
27
- return factory.create(first_llm_config)
59
+ base_config = factory.create(first_llm_config)
60
+
61
+ # Check crawl4ai version and adapt config accordingly
62
+ if is_crawl4ai_v05_or_higher():
63
+ return cls._adapt_for_crawl4ai_v05(base_config)
64
+ else:
65
+ return base_config # Use legacy format
28
66
 
29
67
  raise ValueError("Could not find a factory for the given config.")
30
68
 
69
+ @classmethod
70
+ def _adapt_for_crawl4ai_v05(cls, base_config: dict[str, Any]) -> dict[str, Any]:
71
+ """
72
+ Adapt the config for crawl4ai >=0.5 by moving deprecated parameters
73
+ into an llmConfig object.
74
+ """
75
+ adapted_config = base_config.copy()
76
+
77
+ # Extract deprecated parameters
78
+ llm_config_params = {}
79
+
80
+ if "provider" in adapted_config:
81
+ llm_config_params["provider"] = adapted_config.pop("provider")
82
+
83
+ if "api_token" in adapted_config:
84
+ llm_config_params["api_token"] = adapted_config.pop("api_token")
85
+
86
+ # Add other parameters that should be in llmConfig
87
+ for param in ["base_url", "api_base", "api_version"]:
88
+ if param in adapted_config:
89
+ llm_config_params[param] = adapted_config.pop(param)
90
+
91
+ # Create the llmConfig object if we have parameters for it
92
+ if llm_config_params:
93
+ adapted_config["llmConfig"] = llm_config_params
94
+
95
+ return adapted_config
96
+
31
97
  @classmethod
32
98
  def register_factory(cls) -> Callable[[type[T]], type[T]]:
33
99
  def decorator(factory: type[T]) -> type[T]:
autogen/llm_config.py CHANGED
@@ -138,7 +138,10 @@ class LLMConfig(metaclass=MetaLLMConfig):
138
138
  if len(filtered_config_list) == 0:
139
139
  raise ValueError(f"No config found that satisfies the filter criteria: {kwargs}")
140
140
 
141
- return LLMConfig(config_list=filtered_config_list)
141
+ kwargs = self.model_dump()
142
+ kwargs["config_list"] = filtered_config_list
143
+
144
+ return LLMConfig(**kwargs)
142
145
 
143
146
  # @functools.wraps(BaseModel.model_dump)
144
147
  def model_dump(self, *args: Any, exclude_none: bool = True, **kwargs: Any) -> dict[str, Any]:
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ import logging
5
+ from typing import Annotated, Literal, Optional
6
+
7
+ from .. import __version__
8
+ from ..import_utils import optional_import_block, require_optional_import
9
+ from .mcp_proxy import MCPProxy
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ with optional_import_block():
14
+ import typer
15
+
16
+
17
+ @require_optional_import(["typer"], "mcp-proxy-gen")
18
+ def create_typer_app() -> "typer.Typer":
19
+ """Create a Typer app for the mcp proxy CLI."""
20
+ app = typer.Typer(rich_markup_mode="rich")
21
+
22
+ def version_callback(value: bool) -> None:
23
+ if value:
24
+ typer.echo(f"{__version__}")
25
+ raise typer.Exit()
26
+
27
+ @app.callback()
28
+ def callback(
29
+ version: Annotated[
30
+ Optional[bool],
31
+ typer.Option("--version", help="Show the version and exit.", callback=version_callback),
32
+ ] = None,
33
+ ) -> None:
34
+ """AG2 mcp proxy CLI - The [bold]mcp proxy[/bold] command line app. 😎
35
+
36
+ Generate mcp proxy for your [bold]AG2[/bold] projects.
37
+
38
+ Read more in the docs: ...
39
+ """ # noqa: D415
40
+
41
+ @app.command()
42
+ def create(
43
+ openapi_specification: Annotated[
44
+ Optional[str],
45
+ "Specification of the OpenAPI to use for the proxy generation.",
46
+ ] = None,
47
+ openapi_url: Annotated[
48
+ Optional[str],
49
+ "URL to the OpenAPI specification to use for the proxy generation.",
50
+ ] = None,
51
+ client_source_path: Annotated[
52
+ Optional[str],
53
+ "Path to the generated proxy client source code.",
54
+ ] = None,
55
+ server_url: Annotated[
56
+ Optional[str],
57
+ "Comma-separated list of server URLs to use for the proxy generation.",
58
+ ] = None,
59
+ configuration_type: Annotated[
60
+ Literal["json", "yaml"],
61
+ "Configuration type of the specification. Can be 'json' or 'yaml'.",
62
+ ] = "json",
63
+ ) -> None:
64
+ """Generate mcp proxy for your AG2 projects."""
65
+ MCPProxy.create(
66
+ openapi_specification=openapi_specification,
67
+ openapi_url=openapi_url,
68
+ client_source_path=client_source_path,
69
+ servers=[{"url": server_url}],
70
+ configuration_type=configuration_type,
71
+ )
72
+
73
+ return app
74
+
75
+
76
+ if __name__ == "__main__":
77
+ app = create_typer_app()
78
+ app(prog_name="mcp_proxy")
@@ -0,0 +1,19 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from autogen.import_utils import optional_import_block
6
+
7
+ from .patch_fastapi_code_generator import ( # noqa: E402
8
+ SUCCESFUL_IMPORT,
9
+ patch_function_name_parsing,
10
+ patch_generate_code,
11
+ )
12
+
13
+ if SUCCESFUL_IMPORT:
14
+ patch_function_name_parsing()
15
+ patch_generate_code()
16
+
17
+ from .mcp_proxy import MCPProxy # noqa: E402
18
+
19
+ __all__ = ["MCPProxy", "optional_import_block"]
@@ -0,0 +1,63 @@
1
+ # Copyright (c) 2023 - 2025, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ from collections.abc import Iterator
5
+ from contextlib import contextmanager
6
+ from functools import cached_property
7
+ from typing import Optional, Union
8
+
9
+ from ...import_utils import optional_import_block
10
+
11
+ with optional_import_block() as result:
12
+ from fastapi_code_generator.parser import (
13
+ Argument,
14
+ OpenAPIParser,
15
+ ParameterObject,
16
+ ReferenceObject,
17
+ )
18
+
19
+ SUCCESFUL_IMPORT = result.is_successful
20
+
21
+ __all__ = ["SUCCESFUL_IMPORT", "patch_get_parameter_type"]
22
+
23
+
24
+ @contextmanager
25
+ def patch_get_parameter_type() -> Iterator[None]:
26
+ class ArgumentWithDescription(Argument): # type: ignore[misc]
27
+ description: Optional[str] = None
28
+
29
+ @cached_property
30
+ def argument(self) -> str:
31
+ if self.description:
32
+ description = self.description.replace('"""', '"""')
33
+ type_hint = f'Annotated[{self.type_hint}, """{description}"""]'
34
+ else:
35
+ type_hint = self.type_hint
36
+
37
+ if self.default is None and self.required:
38
+ return f"{self.name}: {type_hint}"
39
+
40
+ return f"{self.name}: {type_hint} = {self.default}"
41
+
42
+ original_get_parameter_type = OpenAPIParser.get_parameter_type
43
+
44
+ def get_parameter_type(
45
+ self: OpenAPIParser,
46
+ parameters: Union[ReferenceObject, ParameterObject],
47
+ snake_case: bool,
48
+ path: list[str],
49
+ ) -> Optional[Argument]:
50
+ # get the original argument
51
+ argument = original_get_parameter_type(self, parameters, snake_case, path)
52
+
53
+ # add description to the argument
54
+ parameters = self.resolve_object(parameters, ParameterObject)
55
+ argument_with_description = ArgumentWithDescription(description=parameters.description, **argument.model_dump())
56
+ return argument_with_description
57
+
58
+ OpenAPIParser.get_parameter_type = get_parameter_type
59
+
60
+ try:
61
+ yield
62
+ finally:
63
+ OpenAPIParser.get_parameter_type = original_get_parameter_type