oagi-core 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oagi/__init__.py +1 -3
- oagi/actor/__init__.py +21 -0
- oagi/{task → actor}/async_.py +23 -7
- oagi/{task → actor}/async_short.py +1 -1
- oagi/actor/base.py +222 -0
- oagi/{task → actor}/short.py +1 -1
- oagi/{task → actor}/sync.py +21 -5
- oagi/agent/default.py +1 -0
- oagi/agent/observer/exporters.py +6 -0
- oagi/agent/observer/report_template.html +19 -0
- oagi/agent/tasker/planner.py +14 -12
- oagi/agent/tasker/taskee_agent.py +7 -3
- oagi/client/async_.py +54 -96
- oagi/client/base.py +81 -133
- oagi/client/sync.py +52 -99
- oagi/constants.py +7 -2
- oagi/task/__init__.py +22 -8
- oagi/types/models/__init__.py +0 -2
- oagi/types/models/action.py +4 -1
- oagi/types/models/client.py +1 -17
- oagi/types/step_observer.py +2 -0
- oagi/utils/__init__.py +12 -0
- oagi/utils/output_parser.py +166 -0
- oagi/utils/prompt_builder.py +44 -0
- {oagi_core-0.11.0.dist-info → oagi_core-0.12.0.dist-info}/METADATA +57 -10
- {oagi_core-0.11.0.dist-info → oagi_core-0.12.0.dist-info}/RECORD +29 -25
- oagi/task/base.py +0 -158
- {oagi_core-0.11.0.dist-info → oagi_core-0.12.0.dist-info}/WHEEL +0 -0
- {oagi_core-0.11.0.dist-info → oagi_core-0.12.0.dist-info}/entry_points.txt +0 -0
- {oagi_core-0.11.0.dist-info → oagi_core-0.12.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: oagi-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Official API of OpenAGI Foundation
|
|
5
5
|
Project-URL: Homepage, https://github.com/agiopen-org/oagi
|
|
6
6
|
Author-email: OpenAGI Foundation <contact@agiopen.org>
|
|
@@ -26,25 +26,71 @@ License: MIT License
|
|
|
26
26
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
27
|
SOFTWARE.
|
|
28
28
|
Requires-Python: >=3.10
|
|
29
|
-
Requires-Dist: httpx>=0.
|
|
29
|
+
Requires-Dist: httpx>=0.24.0
|
|
30
|
+
Requires-Dist: openai>=1.3.0
|
|
30
31
|
Requires-Dist: pydantic>=2.0.0
|
|
31
|
-
Requires-Dist: rich>=
|
|
32
|
+
Requires-Dist: rich>=10.0.0
|
|
32
33
|
Provides-Extra: desktop
|
|
33
|
-
Requires-Dist: pillow>=
|
|
34
|
+
Requires-Dist: pillow>=9.0.0; extra == 'desktop'
|
|
34
35
|
Requires-Dist: pyautogui>=0.9.54; extra == 'desktop'
|
|
35
|
-
Requires-Dist: pyobjc-framework-applicationservices>=
|
|
36
|
-
Requires-Dist: pyobjc-framework-quartz>=
|
|
36
|
+
Requires-Dist: pyobjc-framework-applicationservices>=8.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
37
|
+
Requires-Dist: pyobjc-framework-quartz>=8.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
37
38
|
Provides-Extra: server
|
|
38
|
-
Requires-Dist: fastapi[standard]>=0.
|
|
39
|
+
Requires-Dist: fastapi[standard]>=0.100.0; extra == 'server'
|
|
39
40
|
Requires-Dist: pydantic-settings>=2.0.0; extra == 'server'
|
|
40
|
-
Requires-Dist: python-socketio>=5.
|
|
41
|
-
Requires-Dist: uvicorn[standard]>=0.
|
|
41
|
+
Requires-Dist: python-socketio>=5.5.0; extra == 'server'
|
|
42
|
+
Requires-Dist: uvicorn[standard]>=0.20.0; extra == 'server'
|
|
42
43
|
Description-Content-Type: text/markdown
|
|
43
44
|
|
|
44
45
|
# OAGI Python SDK
|
|
45
46
|
|
|
47
|
+
[](https://pypi.org/project/oagi-core/)
|
|
48
|
+
[](https://pypi.org/project/oagi-core/)
|
|
49
|
+
[](https://github.com/agiopen-org/oagi-python/blob/main/LICENSE)
|
|
50
|
+
[](https://github.com/agiopen-org/oagi-python/actions/workflows/ci.yml)
|
|
51
|
+
|
|
46
52
|
Python SDK for the OAGI API - vision-based task automation.
|
|
47
53
|
|
|
54
|
+
## What is OAGI?
|
|
55
|
+
|
|
56
|
+
OAGI is the Python SDK for **Lux**, the world's most advanced computer-use model from the OpenAGI Foundation.
|
|
57
|
+
|
|
58
|
+
**Computer Use** is AI's ability to operate human-facing software — not just through APIs, but by operating computers natively, just as human users do. It's a paradigm shift in what AI can do: not just generating, reasoning, or researching, but actually operating on your computer.
|
|
59
|
+
|
|
60
|
+
Lux comes in three modes, giving you control over depth, speed, and style of execution:
|
|
61
|
+
|
|
62
|
+
- **Tasker** — Strictly follows step-by-step instructions with ultra-stable, controllable execution
|
|
63
|
+
- **Actor** — Ideal for immediate tasks, completing actions at near-instant speed
|
|
64
|
+
- **Thinker** — Understands vague, complex goals, performing hour-long executions
|
|
65
|
+
|
|
66
|
+
### Use Cases
|
|
67
|
+
|
|
68
|
+
With Lux, possibilities are endless. Here are a few examples:
|
|
69
|
+
|
|
70
|
+
- **Web Scraping & Data Crawl** — Navigate websites, sort results, and collect product information autonomously
|
|
71
|
+
- **Software QA** — Automate repetitive testing tasks, navigate applications, perform test actions, and validate expected behaviors
|
|
72
|
+
- **Financial Data Extraction** — Navigate to sites like NASDAQ and extract insider activity data
|
|
73
|
+
- **Data Entry** — Enter accurate data across dashboards and forms
|
|
74
|
+
- **Workflow Automation** — Chain together multi-step tasks across different applications
|
|
75
|
+
|
|
76
|
+
## Table of Contents
|
|
77
|
+
|
|
78
|
+
- [What is OAGI?](#what-is-oagi)
|
|
79
|
+
- [Installation](#installation)
|
|
80
|
+
- [Quick Start](#quick-start)
|
|
81
|
+
- [Automated Task Execution](#automated-task-execution)
|
|
82
|
+
- [Command Line Interface](#command-line-interface)
|
|
83
|
+
- [Image Processing](#image-processing)
|
|
84
|
+
- [Manual Control with Actor](#manual-control-with-actor)
|
|
85
|
+
- [Examples](#examples)
|
|
86
|
+
- [Socket.IO Server (Optional)](#socketio-server-optional)
|
|
87
|
+
- [Installation](#installation-1)
|
|
88
|
+
- [Running the Server](#running-the-server)
|
|
89
|
+
- [Server Features](#server-features)
|
|
90
|
+
- [Client Integration](#client-integration)
|
|
91
|
+
- [Documentation](#documentation)
|
|
92
|
+
- [License](#license)
|
|
93
|
+
|
|
48
94
|
## Installation
|
|
49
95
|
|
|
50
96
|
```bash
|
|
@@ -74,7 +120,7 @@ pip install oagi-core[server] # Server support
|
|
|
74
120
|
|
|
75
121
|
Set your API credentials:
|
|
76
122
|
```bash
|
|
77
|
-
export OAGI_API_KEY="your-api-key" # get your API key from https://developer.
|
|
123
|
+
export OAGI_API_KEY="your-api-key" # get your API key from https://developer.agiopen.org/
|
|
78
124
|
# export OAGI_BASE_URL="https://api.agiopen.org/", # optional, defaults to production endpoint
|
|
79
125
|
```
|
|
80
126
|
|
|
@@ -272,6 +318,7 @@ See [`examples/socketio_client_example.py`](examples/socketio_client_example.py)
|
|
|
272
318
|
|
|
273
319
|
## Documentation
|
|
274
320
|
|
|
321
|
+
For full Lux documentation and guides, visit the [OAGI Developer Documentation](https://developer.agiopen.org/docs/index).
|
|
275
322
|
|
|
276
323
|
## License
|
|
277
324
|
|
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
oagi/__init__.py,sha256=
|
|
2
|
-
oagi/constants.py,sha256=
|
|
1
|
+
oagi/__init__.py,sha256=hKfGbbvYFNoc8LsTd34aM6Uj-nGEJ0J8JbceXZP5xZ0,4801
|
|
2
|
+
oagi/constants.py,sha256=ywyMimjh15tC5p4MBZjkJIqOVElPRS50iJtrPE3VClw,1211
|
|
3
3
|
oagi/exceptions.py,sha256=Rco37GQTPYUfc2vRO3hozxPF_s8mKFDpFvBg2UKWo3Y,3066
|
|
4
4
|
oagi/logging.py,sha256=YT3KCMFj5fzO98R9xlDDgfSotUuz1xRD6OZeYM2rKoo,1760
|
|
5
|
+
oagi/actor/__init__.py,sha256=g_8_7ZLDLKuCGzyrB42OzY3gSOjd_SxzkJW3_pf-PXs,662
|
|
6
|
+
oagi/actor/async_.py,sha256=DcU6ifAcrYI1GSrTFgMPrWhikjmnJfZVaFsun15DG_k,3768
|
|
7
|
+
oagi/actor/async_short.py,sha256=QSo67aPsd_rxA2J2TR1fv6nJD6wO00q3S-QQYNK93q4,2821
|
|
8
|
+
oagi/actor/base.py,sha256=UUZdS1tufZDIbtQHLs-es6ptGHQpa-EPWf7RSbVpQnU,7921
|
|
9
|
+
oagi/actor/short.py,sha256=wKLCxvf7Ys6rYxXpHe4zbZdbf_1q1qcmm5WyWubwj3E,2630
|
|
10
|
+
oagi/actor/sync.py,sha256=QTY1WNTI75jwkWBghdVViHIp5rYkbm3kumlLedU8YeQ,3588
|
|
5
11
|
oagi/agent/__init__.py,sha256=KTVLUMhbjgpTJoOWMUZkkiqwhgumvbOZV2tJ9XCLfao,901
|
|
6
|
-
oagi/agent/default.py,sha256=
|
|
12
|
+
oagi/agent/default.py,sha256=YKAAq_XJrM-YpYuLtDtEH9XA502eijsdiawQKAf4iJ0,4709
|
|
7
13
|
oagi/agent/factories.py,sha256=syi_EOlU4SUjo-0CKaML8eIPu3ToUEKua2VHp9lvNF0,5839
|
|
8
14
|
oagi/agent/protocol.py,sha256=IQJGiMN4yZIacrh5e9JQsoM9TyHb8wJRQR4LAk8dSA0,1615
|
|
9
15
|
oagi/agent/registry.py,sha256=7bMA2-pH3xQ9ZavrHB_mnc2fOGSMeICPbOGtHoM7It0,4851
|
|
10
16
|
oagi/agent/observer/__init__.py,sha256=YZ4qvR22pFB0mSDMX6iKKLbBA1dB-nqC7HZVvdMIVGw,909
|
|
11
17
|
oagi/agent/observer/agent_observer.py,sha256=fBs4X2_YKhYVThJocjMM-65JAHQSCLJPvzy8OXMt5pY,2864
|
|
12
18
|
oagi/agent/observer/events.py,sha256=xc3Z1UGpX69BqhO9cQiGmnRhDZbMYya1kuXm6bXtjWI,625
|
|
13
|
-
oagi/agent/observer/exporters.py,sha256=
|
|
19
|
+
oagi/agent/observer/exporters.py,sha256=HeEE5bmWjgOATLkh1R-m1P7f1Ztb58BHk6xbxdsdxCw,12153
|
|
14
20
|
oagi/agent/observer/protocol.py,sha256=jyRXoCG4CdvaPaDASar1rSbwc7vdpkar39KkGpwf8jw,411
|
|
15
|
-
oagi/agent/observer/report_template.html,sha256=
|
|
21
|
+
oagi/agent/observer/report_template.html,sha256=HtvJLh3swTMfmIw4XyGFqquS4vjP9iOe5L2tTnOKpzY,15388
|
|
16
22
|
oagi/agent/tasker/__init__.py,sha256=1iTEFe7lzcqh96TL9R0QADPpLJLrUP0shtZ4DlZSv_8,764
|
|
17
23
|
oagi/agent/tasker/memory.py,sha256=NR13l5yxRA8GUE-oupAP4W1n80ZNG0SxpUfxsNltkUY,5033
|
|
18
24
|
oagi/agent/tasker/models.py,sha256=sMQgwIMKhT1tvVF2yoc1hh8GwEiJ6i6qPMy9WoiA8JM,2137
|
|
19
|
-
oagi/agent/tasker/planner.py,sha256=
|
|
20
|
-
oagi/agent/tasker/taskee_agent.py,sha256=
|
|
25
|
+
oagi/agent/tasker/planner.py,sha256=q6IvH6sfU2kYX1NcC9VHjGaQ0X9jF18yjuAYXisNCg0,15489
|
|
26
|
+
oagi/agent/tasker/taskee_agent.py,sha256=VquuEkkjpLYOVPamHDz53e9GClj6v93VPMHoiNmR8-U,18084
|
|
21
27
|
oagi/agent/tasker/tasker_agent.py,sha256=kbWvvRVS12S8eFd0PRszFrcSSWRzz_f6Jd7LuaRcwJQ,11285
|
|
22
28
|
oagi/cli/__init__.py,sha256=aDnJViTseShpo5fdGPTj-ELysZhmdvB6Z8mEj2D-_N4,359
|
|
23
29
|
oagi/cli/agent.py,sha256=fd7WtR5zoRJmyHDr67zfBvEX-_BLIjPbBqp-dhy4AAk,11061
|
|
@@ -27,9 +33,9 @@ oagi/cli/server.py,sha256=JFpzCOeaftITxesz8Ya-_Efs03bgotBg7aYwmMZhPwU,3033
|
|
|
27
33
|
oagi/cli/tracking.py,sha256=TdrAcNq_-OjgXltFCoFc8NsO_k6yHbdzHnMn3vAAvKA,1707
|
|
28
34
|
oagi/cli/utils.py,sha256=zIkTrr-ai__3cGSaxiXY-OJs69Fcxd1sHb2FoeyHFtE,3034
|
|
29
35
|
oagi/client/__init__.py,sha256=F9DShPUdb6vZYmN1fpM1VYzp4MWqUao_e_R1KYmM4Q4,410
|
|
30
|
-
oagi/client/async_.py,sha256=
|
|
31
|
-
oagi/client/base.py,sha256=
|
|
32
|
-
oagi/client/sync.py,sha256
|
|
36
|
+
oagi/client/async_.py,sha256=m7hkJSebH2MyXAwEbpsFw0UQm6aRJQ8HZiULBlZxvM4,9385
|
|
37
|
+
oagi/client/base.py,sha256=kKkdpd-YkjFfTVCOQzVRjjkQnCpH2hZLtyM1vKizy6I,14693
|
|
38
|
+
oagi/client/sync.py,sha256=-wtaW1H5jgj32_1TDVxMO7zdZ47ZV6ZG7a6jF2ztbv0,9158
|
|
33
39
|
oagi/handler/__init__.py,sha256=vEUvyiUvTRf1GE4vTiz_bQjLv3psdmHyt0mfKJHq24M,1247
|
|
34
40
|
oagi/handler/_macos.py,sha256=Gs8GrhA_WAyv9Yw0D41duliP32Xk6vouyMeWjWJJT90,5187
|
|
35
41
|
oagi/handler/_windows.py,sha256=MSgPDYEOetSjbn9eJDSrdzBVlUGgGsTlegaTDc4C4Ss,2828
|
|
@@ -46,27 +52,25 @@ oagi/server/main.py,sha256=jnTxk7Prc5CzlsUnkBNJp4MOoYN-7HN_Be_m1d3COa8,4829
|
|
|
46
52
|
oagi/server/models.py,sha256=DXjuf5icpCOgCUGMzzoLfRCoreM541KBWKBZnCk5_S0,2688
|
|
47
53
|
oagi/server/session_store.py,sha256=l7t31rNWuZkIPLnaqrllVusHkJkE8j50PMfyb1di9mI,3750
|
|
48
54
|
oagi/server/socketio_server.py,sha256=8RRf8mAmsArOX2nWylT0g5T5On0gzMod0TWRmk0vrgA,14218
|
|
49
|
-
oagi/task/__init__.py,sha256=
|
|
50
|
-
oagi/task/async_.py,sha256=12BrdE-51bEz2-PZv5X2VW__I_nwq2K1YxGfD3wFxos,3190
|
|
51
|
-
oagi/task/async_short.py,sha256=wVMYpsKGbvqYIe2Ws7cMf8-t7SZKmtrgjW1x_RENMgg,2820
|
|
52
|
-
oagi/task/base.py,sha256=6F_nmJsb2Zw6nUibJyAEW0uQBY_jHiQINUbd_jT5wkQ,5696
|
|
53
|
-
oagi/task/short.py,sha256=D5VX8QGy0o8W7njy74jx95PxU0Rv2Nvoa-2T17aBaZQ,2629
|
|
54
|
-
oagi/task/sync.py,sha256=pKRpIFcetm1n2BgmYGWQeWgV3kKLAQRG9xPlBVQ_pho,3024
|
|
55
|
+
oagi/task/__init__.py,sha256=8l3z5nxA3RtGHP94Iu4ot1Wo3Lx-U7_Led2CsVwYINg,760
|
|
55
56
|
oagi/types/__init__.py,sha256=_UyzzRnoKvp00BUBjxW9Tv3_xBNf8Lxb2PUC2DkjOkg,1384
|
|
56
57
|
oagi/types/action_handler.py,sha256=NH8E-m5qpGqWcXzTSWfF7W0Xdp8SkzJsbhCmQ0B96cg,1075
|
|
57
58
|
oagi/types/async_action_handler.py,sha256=k1AaqSkFcXlxwW8sn-w0WFHGsIqHFLbcOPrkknmSVug,1116
|
|
58
59
|
oagi/types/async_image_provider.py,sha256=UwDl7VOCA3tiSP5k1fnxK86iEa84Yr57MVaoBSa3hOE,1203
|
|
59
60
|
oagi/types/image.py,sha256=KgPCCTJ6D5vHIaGZdbTE7eQEa1WlT6G9tf59ZuUCV2U,537
|
|
60
61
|
oagi/types/image_provider.py,sha256=IhKEnwCGZ5l_rO3AvJ6xv5RZMTmTDmqsFRynI9h0R_M,1145
|
|
61
|
-
oagi/types/step_observer.py,sha256=
|
|
62
|
+
oagi/types/step_observer.py,sha256=E7igVqpOeoizUkhXbGRRX80ZOuqoM-zcRyjNyOXwWc8,2380
|
|
62
63
|
oagi/types/url.py,sha256=145jLl3yecFBVKhJDbrR63C48D3l9_w0kpA_8C_gM78,868
|
|
63
|
-
oagi/types/models/__init__.py,sha256=
|
|
64
|
-
oagi/types/models/action.py,sha256=
|
|
65
|
-
oagi/types/models/client.py,sha256=
|
|
64
|
+
oagi/types/models/__init__.py,sha256=VcNrVQvw9p8igBunOv3LQBPnRpp5WEcWBf1Nr9FGkeI,843
|
|
65
|
+
oagi/types/models/action.py,sha256=s3oPBCtbVAmavArjFZBEbL71QyW_akUrXpEDJuHqkYI,2583
|
|
66
|
+
oagi/types/models/client.py,sha256=5fUZVTPviTunoh2KXM3jmLPtPIrvPwrr8o2bR6Phj5M,1156
|
|
66
67
|
oagi/types/models/image_config.py,sha256=tl6abVg_-IAPLwpaWprgknXu7wRWriMg-AEVyUX73v0,1567
|
|
67
68
|
oagi/types/models/step.py,sha256=RSI4H_2rrUBq_xyCoWKaq7JHdJWNobtQppaKC1l0aWU,471
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
oagi_core-0.
|
|
72
|
-
oagi_core-0.
|
|
69
|
+
oagi/utils/__init__.py,sha256=vHXyX66hEsf33OJJkmZSUjaTYU0UngfbtjcZgxfOj3A,441
|
|
70
|
+
oagi/utils/output_parser.py,sha256=U7vzmoD8pyzDg23z3vy-L9a_jKPsAlr3x8lIdPszrY8,5322
|
|
71
|
+
oagi/utils/prompt_builder.py,sha256=_Q1HY82YUrq3jSCTZ3Rszu3qmI3Wn_fmq8hf14NuwQM,2180
|
|
72
|
+
oagi_core-0.12.0.dist-info/METADATA,sha256=a8SJt-skg0xQjodJEqwLd0EOJzhw8BrHBUIqlYGEf1Y,12176
|
|
73
|
+
oagi_core-0.12.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
74
|
+
oagi_core-0.12.0.dist-info/entry_points.txt,sha256=zzgsOSWX6aN3KUB0Z1it8DMxFFBJBqmZVqMVAJRjYuw,44
|
|
75
|
+
oagi_core-0.12.0.dist-info/licenses/LICENSE,sha256=sy5DLA2M29jFT4UfWsuBF9BAr3FnRkYtnAu6oDZiIf8,1075
|
|
76
|
+
oagi_core-0.12.0.dist-info/RECORD,,
|
oagi/task/base.py
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# -----------------------------------------------------------------------------
|
|
2
|
-
# Copyright (c) OpenAGI Foundation
|
|
3
|
-
# All rights reserved.
|
|
4
|
-
#
|
|
5
|
-
# This file is part of the official API project.
|
|
6
|
-
# Licensed under the MIT License.
|
|
7
|
-
# -----------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
from uuid import uuid4
|
|
10
|
-
|
|
11
|
-
from ..constants import DEFAULT_MAX_STEPS
|
|
12
|
-
from ..logging import get_logger
|
|
13
|
-
from ..types import URL, Image, Step
|
|
14
|
-
from ..types.models import LLMResponse
|
|
15
|
-
|
|
16
|
-
logger = get_logger("task.base")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BaseActor:
|
|
20
|
-
"""Base class with shared task management logic for sync/async actors."""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
api_key: str | None,
|
|
25
|
-
base_url: str | None,
|
|
26
|
-
model: str,
|
|
27
|
-
temperature: float | None,
|
|
28
|
-
):
|
|
29
|
-
self.task_id: str = uuid4().hex # Client-side generated UUID
|
|
30
|
-
self.task_description: str | None = None
|
|
31
|
-
self.model = model
|
|
32
|
-
self.temperature = temperature
|
|
33
|
-
self.message_history: list = [] # OpenAI-compatible message history
|
|
34
|
-
self.max_steps: int = DEFAULT_MAX_STEPS
|
|
35
|
-
self.current_step: int = 0 # Current step counter
|
|
36
|
-
# Client will be set by subclasses
|
|
37
|
-
self.api_key: str | None = None
|
|
38
|
-
self.base_url: str | None = None
|
|
39
|
-
|
|
40
|
-
def _prepare_init_task(
|
|
41
|
-
self,
|
|
42
|
-
task_desc: str,
|
|
43
|
-
max_steps: int,
|
|
44
|
-
):
|
|
45
|
-
"""Prepare task initialization (v2 API does not call server for init).
|
|
46
|
-
|
|
47
|
-
Args:
|
|
48
|
-
task_desc: Task description
|
|
49
|
-
max_steps: Maximum number of steps
|
|
50
|
-
"""
|
|
51
|
-
self.task_id = uuid4().hex
|
|
52
|
-
self.task_description = task_desc
|
|
53
|
-
self.message_history = []
|
|
54
|
-
self.max_steps = max_steps
|
|
55
|
-
self.current_step = 0
|
|
56
|
-
logger.info(f"Task initialized: '{task_desc}' (max_steps: {max_steps})")
|
|
57
|
-
|
|
58
|
-
def _validate_and_increment_step(self):
|
|
59
|
-
if not self.task_description:
|
|
60
|
-
raise ValueError("Task description must be set. Call init_task() first.")
|
|
61
|
-
if self.current_step >= self.max_steps:
|
|
62
|
-
raise ValueError(
|
|
63
|
-
f"Max steps limit ({self.max_steps}) reached. "
|
|
64
|
-
"Call init_task() to start a new task."
|
|
65
|
-
)
|
|
66
|
-
self.current_step += 1
|
|
67
|
-
|
|
68
|
-
def _prepare_step(
|
|
69
|
-
self,
|
|
70
|
-
screenshot: Image | URL | bytes,
|
|
71
|
-
instruction: str | None,
|
|
72
|
-
temperature: float | None,
|
|
73
|
-
prefix: str = "",
|
|
74
|
-
) -> dict:
|
|
75
|
-
self._validate_and_increment_step()
|
|
76
|
-
self._log_step_execution(prefix=prefix)
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
"model": self.model,
|
|
80
|
-
"task_description": self.task_description,
|
|
81
|
-
"task_id": self.task_id,
|
|
82
|
-
"instruction": instruction,
|
|
83
|
-
"messages_history": self.message_history,
|
|
84
|
-
"temperature": self._get_temperature(temperature),
|
|
85
|
-
**self._prepare_screenshot_kwargs(screenshot),
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
def _handle_step_error(self, error: Exception, prefix: str = ""):
|
|
89
|
-
logger.error(f"Error during {prefix}step execution: {error}")
|
|
90
|
-
raise
|
|
91
|
-
|
|
92
|
-
def _prepare_screenshot(self, screenshot: Image | bytes) -> bytes:
|
|
93
|
-
if isinstance(screenshot, Image):
|
|
94
|
-
return screenshot.read()
|
|
95
|
-
return screenshot
|
|
96
|
-
|
|
97
|
-
def _get_temperature(self, temperature: float | None) -> float | None:
|
|
98
|
-
return temperature if temperature is not None else self.temperature
|
|
99
|
-
|
|
100
|
-
def _prepare_screenshot_kwargs(self, screenshot: Image | URL | bytes) -> dict:
|
|
101
|
-
if isinstance(screenshot, str):
|
|
102
|
-
return {"screenshot_url": screenshot}
|
|
103
|
-
return {"screenshot": self._prepare_screenshot(screenshot)}
|
|
104
|
-
|
|
105
|
-
def _handle_response_message_history(self, response: LLMResponse):
|
|
106
|
-
if response.raw_output:
|
|
107
|
-
self.message_history.append(
|
|
108
|
-
{
|
|
109
|
-
"role": "assistant",
|
|
110
|
-
"content": [{"type": "text", "text": response.raw_output}],
|
|
111
|
-
}
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
def _build_step_response(self, response: LLMResponse, prefix: str = "") -> Step:
|
|
115
|
-
# Update message history with assistant response
|
|
116
|
-
self._handle_response_message_history(response)
|
|
117
|
-
|
|
118
|
-
result = Step(
|
|
119
|
-
reason=response.reason,
|
|
120
|
-
actions=response.actions,
|
|
121
|
-
stop=response.is_complete,
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
if response.is_complete:
|
|
125
|
-
logger.info(f"{prefix}Task completed.")
|
|
126
|
-
else:
|
|
127
|
-
logger.debug(f"{prefix}Step completed with {len(response.actions)} actions")
|
|
128
|
-
|
|
129
|
-
return result
|
|
130
|
-
|
|
131
|
-
def _log_step_execution(self, prefix: str = ""):
|
|
132
|
-
logger.debug(f"Executing {prefix}step for task: '{self.task_description}'")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
class BaseAutoMode:
|
|
136
|
-
"""Base class with shared auto_mode logic for ShortTask implementations."""
|
|
137
|
-
|
|
138
|
-
def _log_auto_mode_start(self, task_desc: str, max_steps: int, prefix: str = ""):
|
|
139
|
-
logger.info(
|
|
140
|
-
f"Starting {prefix}auto mode for task: '{task_desc}' (max_steps: {max_steps})"
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
def _log_auto_mode_step(self, step_num: int, max_steps: int, prefix: str = ""):
|
|
144
|
-
logger.debug(f"{prefix.capitalize()}auto mode step {step_num}/{max_steps}")
|
|
145
|
-
|
|
146
|
-
def _log_auto_mode_actions(self, action_count: int, prefix: str = ""):
|
|
147
|
-
verb = "asynchronously" if "async" in prefix else ""
|
|
148
|
-
logger.debug(f"Executing {action_count} actions {verb}".strip())
|
|
149
|
-
|
|
150
|
-
def _log_auto_mode_completion(self, steps: int, prefix: str = ""):
|
|
151
|
-
logger.info(
|
|
152
|
-
f"{prefix.capitalize()}auto mode completed successfully after {steps} steps"
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
def _log_auto_mode_max_steps(self, max_steps: int, prefix: str = ""):
|
|
156
|
-
logger.warning(
|
|
157
|
-
f"{prefix.capitalize()}auto mode reached max steps ({max_steps}) without completion"
|
|
158
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|