camel-ai 0.2.72a10__py3-none-any.whl → 0.2.73a1__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 +113 -338
- camel/memories/agent_memories.py +18 -17
- camel/societies/workforce/prompts.py +10 -4
- camel/societies/workforce/single_agent_worker.py +7 -5
- camel/toolkits/__init__.py +6 -1
- camel/toolkits/base.py +57 -1
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +136 -413
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +796 -1631
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +4356 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +33 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +945 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +522 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +110 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +210 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +533 -0
- camel/toolkits/message_integration.py +592 -0
- camel/toolkits/notion_mcp_toolkit.py +234 -0
- camel/toolkits/screenshot_toolkit.py +116 -31
- camel/toolkits/search_toolkit.py +20 -2
- camel/toolkits/terminal_toolkit.py +16 -2
- camel/toolkits/video_analysis_toolkit.py +13 -13
- camel/toolkits/video_download_toolkit.py +11 -11
- {camel_ai-0.2.72a10.dist-info → camel_ai-0.2.73a1.dist-info}/METADATA +12 -6
- {camel_ai-0.2.72a10.dist-info → camel_ai-0.2.73a1.dist-info}/RECORD +31 -24
- camel/toolkits/hybrid_browser_toolkit/actions.py +0 -417
- camel/toolkits/hybrid_browser_toolkit/agent.py +0 -311
- camel/toolkits/hybrid_browser_toolkit/browser_session.py +0 -740
- camel/toolkits/hybrid_browser_toolkit/snapshot.py +0 -227
- camel/toolkits/hybrid_browser_toolkit/stealth_script.js +0 -0
- camel/toolkits/hybrid_browser_toolkit/unified_analyzer.js +0 -1002
- {camel_ai-0.2.72a10.dist-info → camel_ai-0.2.73a1.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.72a10.dist-info → camel_ai-0.2.73a1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: camel-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.73a1
|
|
4
4
|
Summary: Communicative Agents for AI Society Study
|
|
5
5
|
Project-URL: Homepage, https://www.camel-ai.org/
|
|
6
6
|
Project-URL: Repository, https://github.com/camel-ai/camel
|
|
@@ -69,7 +69,7 @@ Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'all'
|
|
|
69
69
|
Requires-Dist: langfuse>=2.60.5; extra == 'all'
|
|
70
70
|
Requires-Dist: linkup-sdk<0.3,>=0.2.1; extra == 'all'
|
|
71
71
|
Requires-Dist: litellm<2,>=1.38.1; extra == 'all'
|
|
72
|
-
Requires-Dist: markitdown
|
|
72
|
+
Requires-Dist: markitdown>=0.1.1; extra == 'all'
|
|
73
73
|
Requires-Dist: math-verify<0.8,>=0.7.0; extra == 'all'
|
|
74
74
|
Requires-Dist: mcp>=1.3.0; extra == 'all'
|
|
75
75
|
Requires-Dist: mem0ai>=0.1.67; extra == 'all'
|
|
@@ -82,6 +82,7 @@ Requires-Dist: networkx<4,>=3.4.2; extra == 'all'
|
|
|
82
82
|
Requires-Dist: newspaper3k<0.3,>=0.2.8; extra == 'all'
|
|
83
83
|
Requires-Dist: notion-client<3,>=2.2.1; extra == 'all'
|
|
84
84
|
Requires-Dist: numpy<=2.2,>=1.2; extra == 'all'
|
|
85
|
+
Requires-Dist: onnxruntime<=1.20.1; extra == 'all'
|
|
85
86
|
Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'all'
|
|
86
87
|
Requires-Dist: openpyxl>=3.1.5; extra == 'all'
|
|
87
88
|
Requires-Dist: pandas<2,>=1.5.3; extra == 'all'
|
|
@@ -127,7 +128,7 @@ Requires-Dist: sympy<2,>=1.13.3; extra == 'all'
|
|
|
127
128
|
Requires-Dist: tabulate>=0.9.0; extra == 'all'
|
|
128
129
|
Requires-Dist: tavily-python<0.6,>=0.5.0; extra == 'all'
|
|
129
130
|
Requires-Dist: textblob<0.18,>=0.17.1; extra == 'all'
|
|
130
|
-
Requires-Dist: traceroot==0.0.
|
|
131
|
+
Requires-Dist: traceroot==0.0.4a5; extra == 'all'
|
|
131
132
|
Requires-Dist: transformers<5,>=4; extra == 'all'
|
|
132
133
|
Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'all'
|
|
133
134
|
Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'all'
|
|
@@ -140,6 +141,7 @@ Requires-Dist: types-setuptools<70,>=69.2.0; extra == 'all'
|
|
|
140
141
|
Requires-Dist: types-tqdm<5,>=4.66.0; extra == 'all'
|
|
141
142
|
Requires-Dist: unstructured==0.16.20; extra == 'all'
|
|
142
143
|
Requires-Dist: weaviate-client>=4.15.0; extra == 'all'
|
|
144
|
+
Requires-Dist: websockets<15.1,>=13.0; extra == 'all'
|
|
143
145
|
Requires-Dist: wikipedia<2,>=1; extra == 'all'
|
|
144
146
|
Requires-Dist: wolframalpha<6,>=5.0.0; extra == 'all'
|
|
145
147
|
Requires-Dist: xls2xlsx>=0.2.0; extra == 'all'
|
|
@@ -191,7 +193,7 @@ Requires-Dist: ipykernel<7,>=6.0.0; extra == 'dev-tools'
|
|
|
191
193
|
Requires-Dist: jupyter-client<9,>=8.6.2; extra == 'dev-tools'
|
|
192
194
|
Requires-Dist: langfuse>=2.60.5; extra == 'dev-tools'
|
|
193
195
|
Requires-Dist: mcp>=1.3.0; extra == 'dev-tools'
|
|
194
|
-
Requires-Dist: traceroot==0.0.
|
|
196
|
+
Requires-Dist: traceroot==0.0.4a5; extra == 'dev-tools'
|
|
195
197
|
Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'dev-tools'
|
|
196
198
|
Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'dev-tools'
|
|
197
199
|
Requires-Dist: typer>=0.15.2; extra == 'dev-tools'
|
|
@@ -208,8 +210,9 @@ Requires-Dist: chunkr-ai>=0.0.50; extra == 'document-tools'
|
|
|
208
210
|
Requires-Dist: crawl4ai>=0.3.745; extra == 'document-tools'
|
|
209
211
|
Requires-Dist: docx2txt<0.9,>=0.8; extra == 'document-tools'
|
|
210
212
|
Requires-Dist: docx>=0.2.4; extra == 'document-tools'
|
|
211
|
-
Requires-Dist: markitdown
|
|
213
|
+
Requires-Dist: markitdown>=0.1.1; extra == 'document-tools'
|
|
212
214
|
Requires-Dist: numpy<=2.2,>=1.2; extra == 'document-tools'
|
|
215
|
+
Requires-Dist: onnxruntime<=1.20.1; extra == 'document-tools'
|
|
213
216
|
Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'document-tools'
|
|
214
217
|
Requires-Dist: openpyxl>=3.1.5; extra == 'document-tools'
|
|
215
218
|
Requires-Dist: pandasai<3,>=2.3.0; extra == 'document-tools'
|
|
@@ -259,11 +262,12 @@ Requires-Dist: exa-py<2,>=1.10.0; extra == 'owl'
|
|
|
259
262
|
Requires-Dist: ffmpeg-python<0.3,>=0.2.0; extra == 'owl'
|
|
260
263
|
Requires-Dist: html2text>=2024.2.26; extra == 'owl'
|
|
261
264
|
Requires-Dist: imageio[pyav]<3,>=2.34.2; extra == 'owl'
|
|
262
|
-
Requires-Dist: markitdown
|
|
265
|
+
Requires-Dist: markitdown>=0.1.1; extra == 'owl'
|
|
263
266
|
Requires-Dist: mcp-server-fetch==2025.1.17; extra == 'owl'
|
|
264
267
|
Requires-Dist: mcp-simple-arxiv==0.2.2; extra == 'owl'
|
|
265
268
|
Requires-Dist: newspaper3k<0.3,>=0.2.8; extra == 'owl'
|
|
266
269
|
Requires-Dist: numpy<=2.2,>=1.2; extra == 'owl'
|
|
270
|
+
Requires-Dist: onnxruntime<=1.20.1; extra == 'owl'
|
|
267
271
|
Requires-Dist: openapi-spec-validator<0.8,>=0.7.1; extra == 'owl'
|
|
268
272
|
Requires-Dist: openpyxl>=3.1.5; extra == 'owl'
|
|
269
273
|
Requires-Dist: pandas<2,>=1.5.3; extra == 'owl'
|
|
@@ -290,6 +294,7 @@ Requires-Dist: tree-sitter-python<0.24,>=0.23.6; extra == 'owl'
|
|
|
290
294
|
Requires-Dist: tree-sitter<0.24,>=0.23.2; extra == 'owl'
|
|
291
295
|
Requires-Dist: typer>=0.15.2; extra == 'owl'
|
|
292
296
|
Requires-Dist: unstructured==0.16.20; extra == 'owl'
|
|
297
|
+
Requires-Dist: websockets<15.1,>=13.0; extra == 'owl'
|
|
293
298
|
Requires-Dist: wikipedia<2,>=1; extra == 'owl'
|
|
294
299
|
Requires-Dist: xls2xlsx>=0.2.0; extra == 'owl'
|
|
295
300
|
Requires-Dist: yt-dlp<2025,>=2024.11.4; extra == 'owl'
|
|
@@ -353,6 +358,7 @@ Requires-Dist: requests-oauthlib<2,>=1.3.1; extra == 'web-tools'
|
|
|
353
358
|
Requires-Dist: scrapegraph-py<2,>=1.12.0; extra == 'web-tools'
|
|
354
359
|
Requires-Dist: sympy<2,>=1.13.3; extra == 'web-tools'
|
|
355
360
|
Requires-Dist: tavily-python<0.6,>=0.5.0; extra == 'web-tools'
|
|
361
|
+
Requires-Dist: websockets<15.1,>=13.0; extra == 'web-tools'
|
|
356
362
|
Requires-Dist: wikipedia<2,>=1; extra == 'web-tools'
|
|
357
363
|
Requires-Dist: wolframalpha<6,>=5.0.0; extra == 'web-tools'
|
|
358
364
|
Description-Content-Type: text/markdown
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
camel/__init__.py,sha256=
|
|
1
|
+
camel/__init__.py,sha256=wTOL4fY0oWlHviwCNl_t2MQqROlrDeuKQRCvElto5kw,901
|
|
2
2
|
camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
|
|
3
3
|
camel/human.py,sha256=Xg8x1cS5KK4bQ1SDByiHZnzsRpvRP-KZViNvmu38xo4,5475
|
|
4
4
|
camel/logger.py,sha256=WgEwael_eT6D-lVAKHpKIpwXSTjvLbny5jbV1Ab8lnA,5760
|
|
@@ -7,7 +7,7 @@ camel/agents/__init__.py,sha256=64weKqdvmpZcGWyVkO-OKASAmVUdrQjv60JApgPk_SA,1644
|
|
|
7
7
|
camel/agents/_types.py,sha256=MeFZzay2kJA6evALQ-MbBTKW-0lu_0wBuKsxzH_4gWI,1552
|
|
8
8
|
camel/agents/_utils.py,sha256=AR7Qqgbkmn4X2edYUQf1rdksGUyV5hm3iK1z-Dn0Mcg,6266
|
|
9
9
|
camel/agents/base.py,sha256=c4bJYL3G3Z41SaFdMPMn8ZjLdFiFaVOFO6EQIfuCVR8,1124
|
|
10
|
-
camel/agents/chat_agent.py,sha256=
|
|
10
|
+
camel/agents/chat_agent.py,sha256=1vypUj36VlAHRSb9U-jzJPq3TqA4dS6b8kZAPIaqJ0c,150855
|
|
11
11
|
camel/agents/critic_agent.py,sha256=L6cTbYjyZB0DCa51tQ6LZLA6my8kHLC4nktHySH78H4,10433
|
|
12
12
|
camel/agents/deductive_reasoner_agent.py,sha256=6BZGaq1hR6hKJuQtOfoYQnk_AkZpw_Mr7mUy2MspQgs,13540
|
|
13
13
|
camel/agents/embodied_agent.py,sha256=XBxBu5ZMmSJ4B2U3Z7SMwvLlgp6yNpaBe8HNQmY9CZA,7536
|
|
@@ -154,7 +154,7 @@ camel/loaders/pandas_reader.py,sha256=zTVrUWsnR6oeOqeL8KLlnapJeaB4El0wyIrEPY1aLu
|
|
|
154
154
|
camel/loaders/scrapegraph_reader.py,sha256=k8EOV5-p41DHDr2ITV8BR1sMqBsvN41CN8Byj2cf5kY,3120
|
|
155
155
|
camel/loaders/unstructured_io.py,sha256=wA3fkDeS4mSPFkMDnWZzJYKDltio7l72BU9D3EGfoUs,17423
|
|
156
156
|
camel/memories/__init__.py,sha256=JQbs-_7VkcVTjE8y9J0DWI3btDyMRZilTZNVuy_RxZM,1358
|
|
157
|
-
camel/memories/agent_memories.py,sha256=
|
|
157
|
+
camel/memories/agent_memories.py,sha256=c8HwmgNwhtp8F4Wz9f5ekPXLA7DF8TEHhNYCutF1L9U,10872
|
|
158
158
|
camel/memories/base.py,sha256=LRhCmPwQl7ADBb8bE0Izd0vmo5VhOSymtR8Q58fvrYA,5971
|
|
159
159
|
camel/memories/records.py,sha256=NoiwDuwnKYObhrXPHSRGw8xdxAqyZDDiarOAN6-d17I,4451
|
|
160
160
|
camel/memories/blocks/__init__.py,sha256=ci7_WU11222cNd1Zkv-a0z5E2ux95NMjAYm_cDzF0pE,854
|
|
@@ -273,9 +273,9 @@ camel/societies/babyagi_playing.py,sha256=KbTdpHfZ2V8AripVck0bNTOyF-RSaMPCRARz3D
|
|
|
273
273
|
camel/societies/role_playing.py,sha256=0XScr3WfxX1QOC71RhBLmrcS5y2c7DMQB_mAFOHU34M,31421
|
|
274
274
|
camel/societies/workforce/__init__.py,sha256=bkTI-PE-MSK9AQ2V2gR6cR2WY-R7Jqy_NmXRtAoqo8o,920
|
|
275
275
|
camel/societies/workforce/base.py,sha256=z2DmbTP5LL5-aCAAqglznQqCLfPmnyM5zD3w6jjtsb8,2175
|
|
276
|
-
camel/societies/workforce/prompts.py,sha256=
|
|
276
|
+
camel/societies/workforce/prompts.py,sha256=V51MWETPDkUZiwDv8t3aEF8-v3sFV8J8d64NBZaiLqc,18462
|
|
277
277
|
camel/societies/workforce/role_playing_worker.py,sha256=Zm89lZTlV0T3o9C-DJ0HAV68Iq2Kdg8QqJRWs1TV9_A,10320
|
|
278
|
-
camel/societies/workforce/single_agent_worker.py,sha256=
|
|
278
|
+
camel/societies/workforce/single_agent_worker.py,sha256=c7gXxeTGofYWfnQdv3id1c4G2B2jqAakYN-BaSw3BwY,19396
|
|
279
279
|
camel/societies/workforce/structured_output_handler.py,sha256=xr8szFN86hg3jQ825aEkJTjkSFQnTlbinVg4j1vZJVI,17870
|
|
280
280
|
camel/societies/workforce/task_channel.py,sha256=GWHaGQBpjTzdKbWoBYAQzzAiLKRKRXa6beqtc4cg-Is,7611
|
|
281
281
|
camel/societies/workforce/utils.py,sha256=THgNHSeZsNVnjTzQTur3qCJhi72MrDS8X2gPET174cI,8434
|
|
@@ -317,13 +317,13 @@ camel/terminators/__init__.py,sha256=t8uqrkUnXEOYMXQDgaBkMFJ0EXFKI0kmx4cUimli3Ls
|
|
|
317
317
|
camel/terminators/base.py,sha256=xmJzERX7GdSXcxZjAHHODa0rOxRChMSRboDCNHWSscs,1511
|
|
318
318
|
camel/terminators/response_terminator.py,sha256=n3G5KP6Oj7-7WlRN0yFcrtLpqAJKaKS0bmhrWlFfCgQ,4982
|
|
319
319
|
camel/terminators/token_limit_terminator.py,sha256=YWv6ZR8R9yI2Qnf_3xES5bEE_O5bb2CxQ0EUXfMh34c,2118
|
|
320
|
-
camel/toolkits/__init__.py,sha256=
|
|
320
|
+
camel/toolkits/__init__.py,sha256=ug0QbctUQWLUfVI4fSufMyqvorttPYDKy3cI33-v9Ho,6086
|
|
321
321
|
camel/toolkits/aci_toolkit.py,sha256=39AsXloBb16hHB7DKi6mFU6NPZ3iVpM2FZgaP4o4eLE,16060
|
|
322
322
|
camel/toolkits/arxiv_toolkit.py,sha256=mw629nIN_ozaAxNv3nbvhonJKNI2-97ScRCBS3gVqNo,6297
|
|
323
323
|
camel/toolkits/ask_news_toolkit.py,sha256=WfWaqwEo1Apbil3-Rb5y65Ws43NU4rAFWZu5VHe4los,23448
|
|
324
324
|
camel/toolkits/async_browser_toolkit.py,sha256=dHXV8uCDetLKN7no5otyP3hHDnQIRhGY0msJRJrFbIY,50436
|
|
325
325
|
camel/toolkits/audio_analysis_toolkit.py,sha256=dnDtQJbztVBwBpamSyCfigPw2GBnDAfi3fOPgql4Y50,8941
|
|
326
|
-
camel/toolkits/base.py,sha256=
|
|
326
|
+
camel/toolkits/base.py,sha256=RuqpAvs4dM070tv_L-9vSevQn5Q46TpQpyx5k6yKYVI,4374
|
|
327
327
|
camel/toolkits/bohrium_toolkit.py,sha256=453t-m0h0IGjurG6tCHUejGzfRAN2SAkhIoY8V-WJpw,11396
|
|
328
328
|
camel/toolkits/browser_toolkit.py,sha256=Ntn_LmCrhqqIBWq9HtiIKw-M0cL5ebn74Ej1GBoZiC8,44400
|
|
329
329
|
camel/toolkits/browser_toolkit_commons.py,sha256=uuc1V5tN3YJmTSe6NHAVJqwsL4iYD7IiSZWxPLYW67A,22196
|
|
@@ -351,9 +351,11 @@ camel/toolkits/mcp_toolkit.py,sha256=da7QLwGKIKnKvMx5mOOiC56w0hKV1bvD1Z9PgrSHOtA
|
|
|
351
351
|
camel/toolkits/memory_toolkit.py,sha256=TeKYd5UMwgjVpuS2orb-ocFL13eUNKujvrFOruDCpm8,4436
|
|
352
352
|
camel/toolkits/meshy_toolkit.py,sha256=NbgdOBD3FYLtZf-AfonIv6-Q8-8DW129jsaP1PqI2rs,7126
|
|
353
353
|
camel/toolkits/message_agent_toolkit.py,sha256=yWvAaxoxAvDEtD7NH7IkkHIyfWIYK47WZhn5E_RaxKo,22661
|
|
354
|
+
camel/toolkits/message_integration.py,sha256=WdcoVoDAPwlvfXK26wHBf2q_IQCH4PQ_gJtyqUViVvE,23213
|
|
354
355
|
camel/toolkits/mineru_toolkit.py,sha256=vRX9LholLNkpbJ6axfEN4pTG85aWb0PDmlVy3rAAXhg,6868
|
|
355
356
|
camel/toolkits/networkx_toolkit.py,sha256=C7pUCZTzzGkFyqdkrmhRKpAHmHWfLKeuzYHC_BHPtbk,8826
|
|
356
357
|
camel/toolkits/note_taking_toolkit.py,sha256=cp7uoSBMjiGy331Tdk2Bl6yqKSMGwws7rQJkq8tfTQs,10687
|
|
358
|
+
camel/toolkits/notion_mcp_toolkit.py,sha256=ie_6Z-7DqDhgTiwYX8L3X47rfWGwzgwQH_s2DaK1ckc,8362
|
|
357
359
|
camel/toolkits/notion_toolkit.py,sha256=jmmVWk_WazRNWnx4r9DAvhFTAL-n_ige0tb32UHJ_ik,9752
|
|
358
360
|
camel/toolkits/open_api_toolkit.py,sha256=Venfq8JwTMQfzRzzB7AYmYUMEX35hW0BjIv_ozFMiNk,23316
|
|
359
361
|
camel/toolkits/openai_agent_toolkit.py,sha256=hT2ancdQigngAiY1LNnGJzZeiBDHUxrRGv6BdZTJizc,4696
|
|
@@ -368,33 +370,38 @@ camel/toolkits/pulse_mcp_search_toolkit.py,sha256=uLUpm19uC_4xLJow0gGVS9f-5T5EW2
|
|
|
368
370
|
camel/toolkits/pyautogui_toolkit.py,sha256=Q810fm8cFvElRory7B74aqS2YV6BOpdRE6jkewoM8xc,16093
|
|
369
371
|
camel/toolkits/reddit_toolkit.py,sha256=x0XAT1zQJVNHUr1R1HwWCgIlkamU-kPmbfb_H1WIv-w,8036
|
|
370
372
|
camel/toolkits/retrieval_toolkit.py,sha256=BKjEyOqW3cGEPTS5yHPYb-Qg795iNNPIs1wjowfuq3U,3825
|
|
371
|
-
camel/toolkits/screenshot_toolkit.py,sha256=
|
|
372
|
-
camel/toolkits/search_toolkit.py,sha256=
|
|
373
|
+
camel/toolkits/screenshot_toolkit.py,sha256=IwfvfLSfqrEywvPlDbtYJe1qcbrO5uC3Mxxv87VYveo,8237
|
|
374
|
+
camel/toolkits/search_toolkit.py,sha256=2zKclYTQi5ThjPLiwKV7qX8GxuvgtgSLBHipTz-ZgWY,48360
|
|
373
375
|
camel/toolkits/searxng_toolkit.py,sha256=a2GtE4FGSrmaIVvX6Yide-abBYD1wsHqitnDlx9fdVg,7664
|
|
374
376
|
camel/toolkits/semantic_scholar_toolkit.py,sha256=Rh7eA_YPxV5pvPIzhjjvpr3vtlaCniJicrqzkPWW9_I,11634
|
|
375
377
|
camel/toolkits/slack_toolkit.py,sha256=ZT6Ndlce2qjGsyZaNMfQ54nSEi7DOC9Ro7YqtK-u5O4,11651
|
|
376
378
|
camel/toolkits/stripe_toolkit.py,sha256=07swo5znGTnorafC1uYLKB4NRcJIOPOx19J7tkpLYWk,10102
|
|
377
379
|
camel/toolkits/sympy_toolkit.py,sha256=BAQnI8EFJydNUpKQWXBdleQ1Cm-srDBhFlqp9V9pbPQ,33757
|
|
378
380
|
camel/toolkits/task_planning_toolkit.py,sha256=Ttw9fHae4omGC1SA-6uaeXVHJ1YkwiVloz_hO-fm1gw,4855
|
|
379
|
-
camel/toolkits/terminal_toolkit.py,sha256=
|
|
381
|
+
camel/toolkits/terminal_toolkit.py,sha256=_A6_cXVUEodaiLnC-1r-PrsNNVtDQk7vl942GrbkHzQ,58847
|
|
380
382
|
camel/toolkits/thinking_toolkit.py,sha256=nZYLvKWIx2BM1DYu69I9B5EISAG7aYcLYXKv9663BVk,8000
|
|
381
383
|
camel/toolkits/twitter_toolkit.py,sha256=Px4N8aUxUzy01LhGSWkdrC2JgwKkrY3cvxgMeJ2XYfU,15939
|
|
382
|
-
camel/toolkits/video_analysis_toolkit.py,sha256=
|
|
383
|
-
camel/toolkits/video_download_toolkit.py,sha256=
|
|
384
|
+
camel/toolkits/video_analysis_toolkit.py,sha256=h6D7b1MAAzaHn222n_YKtwG-EGEGgMt7mBrNNVipYZc,23361
|
|
385
|
+
camel/toolkits/video_download_toolkit.py,sha256=0dOzsG9vpCHr31bW4Iiqz4iMkQ7uxkAyTMgiculvenk,7567
|
|
384
386
|
camel/toolkits/weather_toolkit.py,sha256=fs9x9aC38Wsvni6A4PPpbRX6-aBnZiqs2Jix39yoULU,7413
|
|
385
387
|
camel/toolkits/web_deploy_toolkit.py,sha256=8dhbYmx5opmimDRdXwEU7LPeG8Z17TWUEURbEneyIPg,38847
|
|
386
388
|
camel/toolkits/whatsapp_toolkit.py,sha256=udUQXkXyeWsmrUlOJZsGBhHtc_jhB05Axe_TchhibsU,5760
|
|
387
389
|
camel/toolkits/wolfram_alpha_toolkit.py,sha256=qeIM8ySn5ilcExBWtx-hDOc35bNcebLVnZ67kt1H3mQ,9295
|
|
388
390
|
camel/toolkits/zapier_toolkit.py,sha256=A83y1UcfuopH7Fx82pORzypl1StbhBjB2HhyOqYa300,7124
|
|
389
391
|
camel/toolkits/hybrid_browser_toolkit/__init__.py,sha256=vxjWhq7GjUKE5I9RGQU_GoikZJ-AVK4ertdvEqp9pd0,802
|
|
390
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
391
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
392
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
393
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
394
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
395
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
396
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
397
|
-
camel/toolkits/hybrid_browser_toolkit/
|
|
392
|
+
camel/toolkits/hybrid_browser_toolkit/config_loader.py,sha256=UwBh7wG4-owoI2VfiNMum0O7dPWMYiEDxQKtq_GazU4,6903
|
|
393
|
+
camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py,sha256=8ArSGFCx1bIrZR8cdRVUX6axy5Fxgk5ADEgiSrPQ_Bo,45269
|
|
394
|
+
camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py,sha256=5wssGj2LvREtyl91lC5pTIb0G7DZlFvLT_Pn-7XPESY,18460
|
|
395
|
+
camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json,sha256=_-YE9S_C1XT59A6upQp9lLuZcC67cV9QlbwAsEKkfyw,156337
|
|
396
|
+
camel/toolkits/hybrid_browser_toolkit/ts/package.json,sha256=pUQm0xwXR7ZyWNv6O2QtHW00agnfAoX9F_XGXZlAxl4,745
|
|
397
|
+
camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json,sha256=SwpQnq4Q-rwRobF2iWrP96mgmgwaVPZEv-nii5QIYEU,523
|
|
398
|
+
camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js,sha256=mLjufus1_ugzRtWMTMQmn5xqsph-RNW55jkWrXbGxrg,6752
|
|
399
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js,sha256=NNwM_H2xaDrlrdac0PJK1iUBwdiuQsg9qKaMhHAvZuI,3160
|
|
400
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts,sha256=csJ6yelay5r0QULBzWybakO3IB7dQ5QpbrSdCxLlrwE,33165
|
|
401
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts,sha256=jYsu9qFuwpFIS5y8rQ5R6aX_HDlDEh2YsvFH6CQLhmg,6181
|
|
402
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts,sha256=VLhaKGQ2rz9OMRTluQ4h9kC0MMJz6-y29WxR-DQEu-c,16551
|
|
403
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts,sha256=uJGHmGs640iCrjllqXDXwDE4hGW1VJA2YL6BkFkzYNs,353
|
|
404
|
+
camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts,sha256=Soid_nh1Ft829pKe_Xt1wxGf3pMSY2vDx4MJHGlhzaA,2442
|
|
398
405
|
camel/toolkits/open_api_specs/security_config.py,sha256=ZVnBa_zEifaE_ao2xsvV5majuJHpn2Tn7feMDOnj-eo,898
|
|
399
406
|
camel/toolkits/open_api_specs/biztoc/__init__.py,sha256=OKCZrQCDwaWtXIN_2rA9FSqEvgpQRieRoHh7Ek6N16A,702
|
|
400
407
|
camel/toolkits/open_api_specs/biztoc/ai-plugin.json,sha256=IJinQbLv5MFPGFwdN7PbOhwArFVExSEZdJspe-mOBIo,866
|
|
@@ -450,7 +457,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
|
|
|
450
457
|
camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
|
|
451
458
|
camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
|
|
452
459
|
camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
|
|
453
|
-
camel_ai-0.2.
|
|
454
|
-
camel_ai-0.2.
|
|
455
|
-
camel_ai-0.2.
|
|
456
|
-
camel_ai-0.2.
|
|
460
|
+
camel_ai-0.2.73a1.dist-info/METADATA,sha256=fyFGeV9znnEsiURZU0Za6FeAkyzm6_hqzk-GLa53aOQ,50334
|
|
461
|
+
camel_ai-0.2.73a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
462
|
+
camel_ai-0.2.73a1.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
|
|
463
|
+
camel_ai-0.2.73a1.dist-info/RECORD,,
|
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
# ========= Copyright 2023-2024 @ 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-2024 @ CAMEL-AI.org. All Rights Reserved. =========
|
|
14
|
-
import asyncio
|
|
15
|
-
from typing import TYPE_CHECKING, Any, Dict, Optional
|
|
16
|
-
|
|
17
|
-
from .config_loader import ConfigLoader
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from playwright.async_api import Page
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class ActionExecutor:
|
|
24
|
-
r"""Executes high-level actions (click, type …) on a Playwright Page."""
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
page: "Page",
|
|
29
|
-
session: Optional[Any] = None,
|
|
30
|
-
default_timeout: Optional[int] = None,
|
|
31
|
-
short_timeout: Optional[int] = None,
|
|
32
|
-
max_scroll_amount: Optional[int] = None,
|
|
33
|
-
):
|
|
34
|
-
self.page = page
|
|
35
|
-
self.session = session # HybridBrowserSession instance
|
|
36
|
-
|
|
37
|
-
# Configure timeouts using the config file with optional overrides
|
|
38
|
-
self.default_timeout = ConfigLoader.get_action_timeout(default_timeout)
|
|
39
|
-
self.short_timeout = ConfigLoader.get_short_timeout(short_timeout)
|
|
40
|
-
self.max_scroll_amount = ConfigLoader.get_max_scroll_amount(
|
|
41
|
-
max_scroll_amount
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# ------------------------------------------------------------------
|
|
45
|
-
# Public helpers
|
|
46
|
-
# ------------------------------------------------------------------
|
|
47
|
-
async def execute(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
48
|
-
r"""Execute an action and return detailed result information."""
|
|
49
|
-
if not action:
|
|
50
|
-
return {
|
|
51
|
-
"success": False,
|
|
52
|
-
"message": "No action to execute",
|
|
53
|
-
"details": {},
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
action_type = action.get("type")
|
|
57
|
-
if not action_type:
|
|
58
|
-
return {
|
|
59
|
-
"success": False,
|
|
60
|
-
"message": "Error: action has no type",
|
|
61
|
-
"details": {},
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try:
|
|
65
|
-
# small helper to ensure basic stability
|
|
66
|
-
# await self._wait_dom_stable()
|
|
67
|
-
|
|
68
|
-
handler = {
|
|
69
|
-
"click": self._click,
|
|
70
|
-
"type": self._type,
|
|
71
|
-
"select": self._select,
|
|
72
|
-
"wait": self._wait,
|
|
73
|
-
"extract": self._extract,
|
|
74
|
-
"scroll": self._scroll,
|
|
75
|
-
"enter": self._enter,
|
|
76
|
-
}.get(action_type)
|
|
77
|
-
|
|
78
|
-
if handler is None:
|
|
79
|
-
return {
|
|
80
|
-
"success": False,
|
|
81
|
-
"message": f"Error: Unknown action type '{action_type}'",
|
|
82
|
-
"details": {"action_type": action_type},
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
result = await handler(action)
|
|
86
|
-
return {
|
|
87
|
-
"success": True,
|
|
88
|
-
"message": result["message"],
|
|
89
|
-
"details": result.get("details", {}),
|
|
90
|
-
}
|
|
91
|
-
except Exception as exc:
|
|
92
|
-
return {
|
|
93
|
-
"success": False,
|
|
94
|
-
"message": f"Error executing {action_type}: {exc}",
|
|
95
|
-
"details": {"action_type": action_type, "error": str(exc)},
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
# ------------------------------------------------------------------
|
|
99
|
-
# Internal handlers
|
|
100
|
-
# ------------------------------------------------------------------
|
|
101
|
-
async def _click(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
102
|
-
r"""Handle click actions with new tab support for any clickable
|
|
103
|
-
element."""
|
|
104
|
-
ref = action.get("ref")
|
|
105
|
-
text = action.get("text")
|
|
106
|
-
selector = action.get("selector")
|
|
107
|
-
if not (ref or text or selector):
|
|
108
|
-
return {
|
|
109
|
-
"message": "Error: click requires ref/text/selector",
|
|
110
|
-
"details": {"error": "missing_selector"},
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
# Build strategies in priority order
|
|
114
|
-
strategies = []
|
|
115
|
-
if ref:
|
|
116
|
-
strategies.append(f"[aria-ref='{ref}']")
|
|
117
|
-
if selector:
|
|
118
|
-
strategies.append(selector)
|
|
119
|
-
if text:
|
|
120
|
-
strategies.append(f'text="{text}"')
|
|
121
|
-
|
|
122
|
-
details: Dict[str, Any] = {
|
|
123
|
-
"ref": ref,
|
|
124
|
-
"selector": selector,
|
|
125
|
-
"text": text,
|
|
126
|
-
"strategies_tried": [],
|
|
127
|
-
"successful_strategy": None,
|
|
128
|
-
"click_method": None,
|
|
129
|
-
"new_tab_created": False,
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
# Find the first valid selector
|
|
133
|
-
found_selector = None
|
|
134
|
-
for sel in strategies:
|
|
135
|
-
if await self.page.locator(sel).count() > 0:
|
|
136
|
-
found_selector = sel
|
|
137
|
-
break
|
|
138
|
-
|
|
139
|
-
if not found_selector:
|
|
140
|
-
details['error'] = "Element not found with any strategy"
|
|
141
|
-
return {
|
|
142
|
-
"message": "Error: Click failed, element not found",
|
|
143
|
-
"details": details,
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
element = self.page.locator(found_selector).first
|
|
147
|
-
details['successful_strategy'] = found_selector
|
|
148
|
-
|
|
149
|
-
# Attempt ctrl+click first (always)
|
|
150
|
-
try:
|
|
151
|
-
if self.session:
|
|
152
|
-
async with self.page.context.expect_page(
|
|
153
|
-
timeout=self.short_timeout
|
|
154
|
-
) as new_page_info:
|
|
155
|
-
await element.click(modifiers=["ControlOrMeta"])
|
|
156
|
-
new_page = await new_page_info.value
|
|
157
|
-
await new_page.wait_for_load_state('domcontentloaded')
|
|
158
|
-
new_tab_index = await self.session.register_page(new_page)
|
|
159
|
-
if new_tab_index is not None:
|
|
160
|
-
await self.session.switch_to_tab(new_tab_index)
|
|
161
|
-
self.page = new_page
|
|
162
|
-
details.update(
|
|
163
|
-
{
|
|
164
|
-
"click_method": "ctrl_click_new_tab",
|
|
165
|
-
"new_tab_created": True,
|
|
166
|
-
"new_tab_index": new_tab_index,
|
|
167
|
-
}
|
|
168
|
-
)
|
|
169
|
-
return {
|
|
170
|
-
"message": f"Clicked element (ctrl click), opened in new "
|
|
171
|
-
f"tab {new_tab_index}",
|
|
172
|
-
"details": details,
|
|
173
|
-
}
|
|
174
|
-
else:
|
|
175
|
-
await element.click(modifiers=["ControlOrMeta"])
|
|
176
|
-
details["click_method"] = "ctrl_click_no_session"
|
|
177
|
-
return {
|
|
178
|
-
"message": f"Clicked element (ctrl click, no"
|
|
179
|
-
f" session): {found_selector}",
|
|
180
|
-
"details": details,
|
|
181
|
-
}
|
|
182
|
-
except asyncio.TimeoutError:
|
|
183
|
-
# No new tab was opened, click may have still worked
|
|
184
|
-
details["click_method"] = "ctrl_click_same_tab"
|
|
185
|
-
return {
|
|
186
|
-
"message": f"Clicked element (ctrl click, "
|
|
187
|
-
f"same tab): {found_selector}",
|
|
188
|
-
"details": details,
|
|
189
|
-
}
|
|
190
|
-
except Exception as e:
|
|
191
|
-
details['strategies_tried'].append(
|
|
192
|
-
{
|
|
193
|
-
'selector': found_selector,
|
|
194
|
-
'method': 'ctrl_click',
|
|
195
|
-
'error': str(e),
|
|
196
|
-
}
|
|
197
|
-
)
|
|
198
|
-
# Fall through to fallback
|
|
199
|
-
|
|
200
|
-
# Fallback to normal force click if ctrl+click fails
|
|
201
|
-
try:
|
|
202
|
-
await element.click(force=True, timeout=self.default_timeout)
|
|
203
|
-
details["click_method"] = "playwright_force_click"
|
|
204
|
-
return {
|
|
205
|
-
"message": f"Fallback clicked element: {found_selector}",
|
|
206
|
-
"details": details,
|
|
207
|
-
}
|
|
208
|
-
except Exception as e:
|
|
209
|
-
details["click_method"] = "playwright_force_click_failed"
|
|
210
|
-
details["error"] = str(e)
|
|
211
|
-
return {
|
|
212
|
-
"message": f"Error: All click strategies "
|
|
213
|
-
f"failed for {found_selector}",
|
|
214
|
-
"details": details,
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async def _type(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
218
|
-
r"""Handle typing text into input fields."""
|
|
219
|
-
ref = action.get("ref")
|
|
220
|
-
selector = action.get("selector")
|
|
221
|
-
text = action.get("text", "")
|
|
222
|
-
if not (ref or selector):
|
|
223
|
-
return {
|
|
224
|
-
"message": "Error: type requires ref/selector",
|
|
225
|
-
"details": {"error": "missing_selector"},
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
target = selector or f"[aria-ref='{ref}']"
|
|
229
|
-
details = {
|
|
230
|
-
"ref": ref,
|
|
231
|
-
"selector": selector,
|
|
232
|
-
"target": target,
|
|
233
|
-
"text": text,
|
|
234
|
-
"text_length": len(text),
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
try:
|
|
238
|
-
await self.page.fill(target, text, timeout=self.short_timeout)
|
|
239
|
-
return {
|
|
240
|
-
"message": f"Typed '{text}' into {target}",
|
|
241
|
-
"details": details,
|
|
242
|
-
}
|
|
243
|
-
except Exception as exc:
|
|
244
|
-
details["error"] = str(exc)
|
|
245
|
-
return {"message": f"Type failed: {exc}", "details": details}
|
|
246
|
-
|
|
247
|
-
async def _select(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
248
|
-
r"""Handle selecting options from dropdowns."""
|
|
249
|
-
ref = action.get("ref")
|
|
250
|
-
selector = action.get("selector")
|
|
251
|
-
value = action.get("value", "")
|
|
252
|
-
if not (ref or selector):
|
|
253
|
-
return {
|
|
254
|
-
"message": "Error: select requires ref/selector",
|
|
255
|
-
"details": {"error": "missing_selector"},
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
target = selector or f"[aria-ref='{ref}']"
|
|
259
|
-
details = {
|
|
260
|
-
"ref": ref,
|
|
261
|
-
"selector": selector,
|
|
262
|
-
"target": target,
|
|
263
|
-
"value": value,
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
try:
|
|
267
|
-
await self.page.select_option(
|
|
268
|
-
target, value, timeout=self.default_timeout
|
|
269
|
-
)
|
|
270
|
-
return {
|
|
271
|
-
"message": f"Selected '{value}' in {target}",
|
|
272
|
-
"details": details,
|
|
273
|
-
}
|
|
274
|
-
except Exception as exc:
|
|
275
|
-
details["error"] = str(exc)
|
|
276
|
-
return {"message": f"Select failed: {exc}", "details": details}
|
|
277
|
-
|
|
278
|
-
async def _wait(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
279
|
-
r"""Handle wait actions."""
|
|
280
|
-
details: Dict[str, Any] = {
|
|
281
|
-
"wait_type": None,
|
|
282
|
-
"timeout": None,
|
|
283
|
-
"selector": None,
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if "timeout" in action:
|
|
287
|
-
ms = int(action["timeout"])
|
|
288
|
-
details["wait_type"] = "timeout"
|
|
289
|
-
details["timeout"] = ms
|
|
290
|
-
await asyncio.sleep(ms / 1000)
|
|
291
|
-
return {"message": f"Waited {ms}ms", "details": details}
|
|
292
|
-
if "selector" in action:
|
|
293
|
-
sel = action["selector"]
|
|
294
|
-
details["wait_type"] = "selector"
|
|
295
|
-
details["selector"] = sel
|
|
296
|
-
await self.page.wait_for_selector(
|
|
297
|
-
sel, timeout=self.default_timeout
|
|
298
|
-
)
|
|
299
|
-
return {"message": f"Waited for {sel}", "details": details}
|
|
300
|
-
return {
|
|
301
|
-
"message": "Error: wait requires timeout/selector",
|
|
302
|
-
"details": details,
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async def _extract(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
306
|
-
r"""Handle text extraction from elements."""
|
|
307
|
-
ref = action.get("ref")
|
|
308
|
-
if not ref:
|
|
309
|
-
return {
|
|
310
|
-
"message": "Error: extract requires ref",
|
|
311
|
-
"details": {"error": "missing_ref"},
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
target = f"[aria-ref='{ref}']"
|
|
315
|
-
details = {"ref": ref, "target": target}
|
|
316
|
-
|
|
317
|
-
await self.page.wait_for_selector(target, timeout=self.default_timeout)
|
|
318
|
-
txt = await self.page.text_content(target)
|
|
319
|
-
|
|
320
|
-
details["extracted_text"] = txt
|
|
321
|
-
details["text_length"] = len(txt) if txt else 0
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
"message": f"Extracted: {txt[:100] if txt else 'None'}",
|
|
325
|
-
"details": details,
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
async def _scroll(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
329
|
-
r"""Handle page scrolling with safe parameter validation."""
|
|
330
|
-
direction = action.get("direction", "down")
|
|
331
|
-
amount = action.get("amount", 300)
|
|
332
|
-
|
|
333
|
-
details = {
|
|
334
|
-
"direction": direction,
|
|
335
|
-
"requested_amount": amount,
|
|
336
|
-
"actual_amount": None,
|
|
337
|
-
"scroll_offset": None,
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
# Validate inputs to prevent injection
|
|
341
|
-
if direction not in ("up", "down"):
|
|
342
|
-
return {
|
|
343
|
-
"message": "Error: direction must be 'up' or 'down'",
|
|
344
|
-
"details": details,
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
try:
|
|
348
|
-
# Safely convert amount to integer and clamp to reasonable range
|
|
349
|
-
amount_int = int(amount)
|
|
350
|
-
amount_int = max(
|
|
351
|
-
-self.max_scroll_amount,
|
|
352
|
-
min(self.max_scroll_amount, amount_int),
|
|
353
|
-
) # Clamp to max_scroll_amount range
|
|
354
|
-
details["actual_amount"] = amount_int
|
|
355
|
-
except (ValueError, TypeError):
|
|
356
|
-
return {
|
|
357
|
-
"message": "Error: amount must be a valid number",
|
|
358
|
-
"details": details,
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
# Use safe evaluation with bound parameters
|
|
362
|
-
scroll_offset = amount_int if direction == "down" else -amount_int
|
|
363
|
-
details["scroll_offset"] = scroll_offset
|
|
364
|
-
|
|
365
|
-
await self.page.evaluate(
|
|
366
|
-
"offset => window.scrollBy(0, offset)", scroll_offset
|
|
367
|
-
)
|
|
368
|
-
await asyncio.sleep(0.5)
|
|
369
|
-
return {
|
|
370
|
-
"message": f"Scrolled {direction} by {abs(amount_int)}px",
|
|
371
|
-
"details": details,
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
async def _enter(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
375
|
-
r"""Handle Enter key press on the currently focused element."""
|
|
376
|
-
details = {"action_type": "enter", "target": "focused_element"}
|
|
377
|
-
|
|
378
|
-
# Press Enter on whatever element currently has focus
|
|
379
|
-
await self.page.keyboard.press("Enter")
|
|
380
|
-
return {
|
|
381
|
-
"message": "Pressed Enter on focused element",
|
|
382
|
-
"details": details,
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
# utilities
|
|
386
|
-
async def _wait_dom_stable(self) -> None:
|
|
387
|
-
r"""Wait for DOM to become stable before executing actions."""
|
|
388
|
-
try:
|
|
389
|
-
# Wait for basic DOM content loading
|
|
390
|
-
await self.page.wait_for_load_state(
|
|
391
|
-
'domcontentloaded', timeout=self.short_timeout
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
# Try to wait for network idle briefly
|
|
395
|
-
try:
|
|
396
|
-
await self.page.wait_for_load_state(
|
|
397
|
-
'networkidle', timeout=self.short_timeout
|
|
398
|
-
)
|
|
399
|
-
except Exception:
|
|
400
|
-
pass # Network idle is optional
|
|
401
|
-
|
|
402
|
-
except Exception:
|
|
403
|
-
pass # Don't fail if wait times out
|
|
404
|
-
|
|
405
|
-
# static helpers
|
|
406
|
-
@staticmethod
|
|
407
|
-
def should_update_snapshot(action: Dict[str, Any]) -> bool:
|
|
408
|
-
r"""Determine if an action requires a snapshot update."""
|
|
409
|
-
change_types = {
|
|
410
|
-
"click",
|
|
411
|
-
"type",
|
|
412
|
-
"select",
|
|
413
|
-
"scroll",
|
|
414
|
-
"navigate",
|
|
415
|
-
"enter",
|
|
416
|
-
}
|
|
417
|
-
return action.get("type") in change_types
|