droidrun 0.3.8__py3-none-any.whl → 0.3.10.dev2__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.
- droidrun/__init__.py +2 -3
- droidrun/__main__.py +1 -1
- droidrun/agent/__init__.py +1 -1
- droidrun/agent/codeact/__init__.py +1 -4
- droidrun/agent/codeact/codeact_agent.py +112 -48
- droidrun/agent/codeact/events.py +6 -3
- droidrun/agent/codeact/prompts.py +2 -2
- droidrun/agent/common/constants.py +2 -0
- droidrun/agent/common/events.py +5 -3
- droidrun/agent/context/__init__.py +1 -3
- droidrun/agent/context/agent_persona.py +2 -1
- droidrun/agent/context/context_injection_manager.py +6 -6
- droidrun/agent/context/episodic_memory.py +5 -3
- droidrun/agent/context/personas/__init__.py +3 -3
- droidrun/agent/context/personas/app_starter.py +3 -3
- droidrun/agent/context/personas/big_agent.py +3 -3
- droidrun/agent/context/personas/default.py +3 -3
- droidrun/agent/context/personas/ui_expert.py +5 -5
- droidrun/agent/context/task_manager.py +15 -17
- droidrun/agent/droid/__init__.py +1 -1
- droidrun/agent/droid/droid_agent.py +327 -182
- droidrun/agent/droid/events.py +91 -9
- droidrun/agent/executor/__init__.py +13 -0
- droidrun/agent/executor/events.py +24 -0
- droidrun/agent/executor/executor_agent.py +327 -0
- droidrun/agent/executor/prompts.py +136 -0
- droidrun/agent/manager/__init__.py +18 -0
- droidrun/agent/manager/events.py +20 -0
- droidrun/agent/manager/manager_agent.py +459 -0
- droidrun/agent/manager/prompts.py +223 -0
- droidrun/agent/oneflows/app_starter_workflow.py +118 -0
- droidrun/agent/oneflows/text_manipulator.py +204 -0
- droidrun/agent/planner/__init__.py +3 -3
- droidrun/agent/planner/events.py +6 -3
- droidrun/agent/planner/planner_agent.py +60 -53
- droidrun/agent/planner/prompts.py +2 -2
- droidrun/agent/usage.py +15 -13
- droidrun/agent/utils/__init__.py +11 -1
- droidrun/agent/utils/async_utils.py +2 -1
- droidrun/agent/utils/chat_utils.py +48 -60
- droidrun/agent/utils/device_state_formatter.py +177 -0
- droidrun/agent/utils/executer.py +13 -12
- droidrun/agent/utils/inference.py +114 -0
- droidrun/agent/utils/llm_picker.py +2 -0
- droidrun/agent/utils/message_utils.py +85 -0
- droidrun/agent/utils/tools.py +220 -0
- droidrun/agent/utils/trajectory.py +8 -7
- droidrun/cli/__init__.py +1 -1
- droidrun/cli/logs.py +29 -28
- droidrun/cli/main.py +279 -143
- droidrun/config_manager/__init__.py +25 -0
- droidrun/config_manager/config_manager.py +583 -0
- droidrun/macro/__init__.py +2 -2
- droidrun/macro/__main__.py +1 -1
- droidrun/macro/cli.py +36 -34
- droidrun/macro/replay.py +7 -9
- droidrun/portal.py +1 -1
- droidrun/telemetry/__init__.py +2 -2
- droidrun/telemetry/events.py +3 -4
- droidrun/telemetry/phoenix.py +173 -0
- droidrun/telemetry/tracker.py +7 -5
- droidrun/tools/__init__.py +1 -1
- droidrun/tools/adb.py +210 -82
- droidrun/tools/ios.py +7 -5
- droidrun/tools/tools.py +25 -8
- {droidrun-0.3.8.dist-info → droidrun-0.3.10.dev2.dist-info}/METADATA +13 -7
- droidrun-0.3.10.dev2.dist-info/RECORD +70 -0
- droidrun/agent/common/default.py +0 -5
- droidrun/agent/context/reflection.py +0 -20
- droidrun/agent/oneflows/reflector.py +0 -265
- droidrun-0.3.8.dist-info/RECORD +0 -55
- {droidrun-0.3.8.dist-info → droidrun-0.3.10.dev2.dist-info}/WHEEL +0 -0
- {droidrun-0.3.8.dist-info → droidrun-0.3.10.dev2.dist-info}/entry_points.txt +0 -0
- {droidrun-0.3.8.dist-info → droidrun-0.3.10.dev2.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: droidrun
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.10.dev2
|
4
4
|
Summary: A framework for controlling Android devices through LLM agents
|
5
5
|
Project-URL: Homepage, https://github.com/droidrun/droidrun
|
6
6
|
Project-URL: Bug Tracker, https://github.com/droidrun/droidrun/issues
|
@@ -16,6 +16,8 @@ Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
19
21
|
Classifier: Topic :: Communications :: Chat
|
20
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
21
23
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
@@ -25,16 +27,16 @@ Classifier: Topic :: Software Development :: Testing
|
|
25
27
|
Classifier: Topic :: Software Development :: Testing :: Acceptance
|
26
28
|
Classifier: Topic :: System :: Emulators
|
27
29
|
Classifier: Topic :: Utilities
|
28
|
-
Requires-Python: >=3.
|
30
|
+
Requires-Python: >=3.13
|
29
31
|
Requires-Dist: adbutils>=2.10.2
|
30
32
|
Requires-Dist: apkutils==2.0.0
|
31
|
-
Requires-Dist: llama-index==0.
|
32
|
-
Requires-Dist: posthog>=6.7.
|
33
|
-
Requires-Dist: pydantic>=2.11.
|
33
|
+
Requires-Dist: llama-index==0.14.4
|
34
|
+
Requires-Dist: posthog>=6.7.6
|
35
|
+
Requires-Dist: pydantic>=2.11.10
|
34
36
|
Requires-Dist: rich>=14.1.0
|
35
37
|
Provides-Extra: anthropic
|
36
38
|
Requires-Dist: anthropic>=0.67.0; extra == 'anthropic'
|
37
|
-
Requires-Dist: llama-index-llms-anthropic
|
39
|
+
Requires-Dist: llama-index-llms-anthropic<0.9.0,>=0.8.6; extra == 'anthropic'
|
38
40
|
Provides-Extra: deepseek
|
39
41
|
Requires-Dist: llama-index-llms-deepseek>=0.2.1; extra == 'deepseek'
|
40
42
|
Provides-Extra: dev
|
@@ -51,6 +53,10 @@ Provides-Extra: openai
|
|
51
53
|
Requires-Dist: llama-index-llms-openai-like>=0.5.1; extra == 'openai'
|
52
54
|
Requires-Dist: llama-index-llms-openai>=0.5.6; extra == 'openai'
|
53
55
|
Requires-Dist: openai>=1.99.1; extra == 'openai'
|
56
|
+
Provides-Extra: openrouter
|
57
|
+
Requires-Dist: llama-index-llms-openrouter>=0.4.2; extra == 'openrouter'
|
58
|
+
Provides-Extra: phoenix
|
59
|
+
Requires-Dist: arize-phoenix>=12.3.0; extra == 'phoenix'
|
54
60
|
Description-Content-Type: text/markdown
|
55
61
|
|
56
62
|
<picture>
|
@@ -88,7 +94,7 @@ DroidRun is a powerful framework for controlling Android and iOS devices through
|
|
88
94
|
## 📦 Installation
|
89
95
|
|
90
96
|
```bash
|
91
|
-
pip install droidrun[google,anthropic,openai,deepseek,ollama,dev]
|
97
|
+
pip install 'droidrun[google,anthropic,openai,deepseek,ollama,dev]'
|
92
98
|
```
|
93
99
|
|
94
100
|
## 🚀 Quickstart
|
@@ -0,0 +1,70 @@
|
|
1
|
+
droidrun/__init__.py,sha256=c2exmv8MuTJ6wWXqzPR30pKGENeIgWe5ytY5hSQYuBc,621
|
2
|
+
droidrun/__main__.py,sha256=8HpscyKn49EH05wXIdoxMiU43xPKb1czq8Aze2vIIqI,106
|
3
|
+
droidrun/portal.py,sha256=Z4daRlMOpsiGxtJ4csuEaEiXAfGM5otbbrcrHvGhAB4,6161
|
4
|
+
droidrun/agent/__init__.py,sha256=91sM0qTmdV5trlXOWE4D_nRhXVPgHKMnYU_9Stc_obQ,209
|
5
|
+
droidrun/agent/usage.py,sha256=6PVeHctNa0EmHmNPTdOUv5e3-EK6AMu6D2Pz5OMqs5c,7145
|
6
|
+
droidrun/agent/codeact/__init__.py,sha256=gWL38IhaeXVWpX3DZCfMWj7gqtFw752edbMHft0b3Ts,266
|
7
|
+
droidrun/agent/codeact/codeact_agent.py,sha256=aUcDVoy6dKA-u0uzLzBhov_-VkeO3cIdV8pn5zULBoc,20131
|
8
|
+
droidrun/agent/codeact/events.py,sha256=rMhiqu3SMfGjuUI4YoSac0zKEiDMtOwPhuvKBq5l_JQ,722
|
9
|
+
droidrun/agent/codeact/prompts.py,sha256=mk6I07B6gYtXG9DibUh_Ir5fhrtMybZ45HjprdG-mus,1005
|
10
|
+
droidrun/agent/common/constants.py,sha256=q7ywmOXCsJZg8m9ctpzQ-nxvuj5GMn28Pr8z3dMj1Rg,94
|
11
|
+
droidrun/agent/common/events.py,sha256=rbPWdlqNNMdnVjYhJOL2mJcNNORHhjXOkY8XiLPzp7c,1182
|
12
|
+
droidrun/agent/context/__init__.py,sha256=obq_4xDV5lk0V72uYwQwotIEXdzNSJoT6QytTnRxDio,644
|
13
|
+
droidrun/agent/context/agent_persona.py,sha256=owIeiWO5ILyXh9elUJgpw_b_wFrSq6Gx9duGVzMjUHY,360
|
14
|
+
droidrun/agent/context/context_injection_manager.py,sha256=TQ5rId7CESRAmORIXHkRGLEoRMBXoT9-lcmQVCZ5RTs,2148
|
15
|
+
droidrun/agent/context/episodic_memory.py,sha256=G9XI-NrYmgJCHNltMutDGNqYuF18pPHoF43nXBqX4Jg,396
|
16
|
+
droidrun/agent/context/task_manager.py,sha256=hOmUsOFvJz3DTKsFREftdTCFO6SJgpzJbwwZy2A6INE,4777
|
17
|
+
droidrun/agent/context/personas/__init__.py,sha256=MoWMnh9XVYWYooXthUh9ccgSkV2ndQBCDksrbpPrV3c,233
|
18
|
+
droidrun/agent/context/personas/app_starter.py,sha256=Hl0MnuWbVmicH9OzE5qrqCrX_3KTtWvE2JGKfpMQX1U,1584
|
19
|
+
droidrun/agent/context/personas/big_agent.py,sha256=yM0DfFSaN9v5YKUePCZRFF_lt0CAsdV7tF5lZmjNuP4,5090
|
20
|
+
droidrun/agent/context/personas/default.py,sha256=CLPPL3_qPt_55N2Hpm_7b2ezVrnRVBQBQYRue72iLDQ,5059
|
21
|
+
droidrun/agent/context/personas/ui_expert.py,sha256=llSlD8BbH67yhOMH3QkCUw3iu9JF9jtBkOMQtV8muVA,4728
|
22
|
+
droidrun/agent/droid/__init__.py,sha256=3Kzejs0p2hqKzgMc253W147P-Y84bYnQX7AZ4pybIsU,297
|
23
|
+
droidrun/agent/droid/droid_agent.py,sha256=ngGWtXZX2OaO8cKUTlpVLyo338MZV60sPbwg36e0220,23577
|
24
|
+
droidrun/agent/droid/events.py,sha256=O1ejFbb4fs4TDvCP5zuW_7OaPWBaKso6eDFGtpVbPi0,2848
|
25
|
+
droidrun/agent/executor/__init__.py,sha256=eTQ0Z3W4Rv69gpVxblCQkWILcyR2_AakpN08NlGLLdU,320
|
26
|
+
droidrun/agent/executor/events.py,sha256=4ftKsmdCIiEBVqVqf0oo5c4u4qSUcZhNzkXOaBBMWXY,456
|
27
|
+
droidrun/agent/executor/executor_agent.py,sha256=Yc8T4R_b_XS3iEfb69Hc7kxaaTLntAj_faKWuMQsdi0,12109
|
28
|
+
droidrun/agent/executor/prompts.py,sha256=pZABRvhOQ1vllmQz5I8m3deVxrXtkIokfpzAcrwkNp0,7329
|
29
|
+
droidrun/agent/manager/__init__.py,sha256=jF53YlSNztP_iQLRbJEeEyEqwI982SUi7Tb6E0pEGxk,461
|
30
|
+
droidrun/agent/manager/events.py,sha256=qHxquD5G_pPRy3puXujOJjecruxgIYc0aXsRYQl7cu4,396
|
31
|
+
droidrun/agent/manager/manager_agent.py,sha256=5TmdVX3egSylSoGQ0XRBBaAwczhu5-wf9f50wN7fVmQ,18509
|
32
|
+
droidrun/agent/manager/prompts.py,sha256=uwg7bMs6TV075HAQxKaQ4uoFh3Q6SLfUHJQ4EGoqAPY,10068
|
33
|
+
droidrun/agent/oneflows/app_starter_workflow.py,sha256=MSJ6_jfbiCfSIjnw-qfSDFDuqsUS6rUGLsdKVj43wvY,3525
|
34
|
+
droidrun/agent/oneflows/text_manipulator.py,sha256=mO59DF1uif9poUWy90UehrBmHbNxL9ph4Evtgt1ODbQ,8751
|
35
|
+
droidrun/agent/planner/__init__.py,sha256=Q3YeOx6JObcxAoZqY7_rncgE8bnm32xEhHPrAl2KnoI,365
|
36
|
+
droidrun/agent/planner/events.py,sha256=Ykq_-qjxfurkvpyiN4dju6rZ0QeOeRAxp7rtKZPrFps,471
|
37
|
+
droidrun/agent/planner/planner_agent.py,sha256=w9Zwo3dOG6mN-4-aDf_XavNqUKZ0Wuc5qxXxPDK74Vk,11598
|
38
|
+
droidrun/agent/planner/prompts.py,sha256=gdXAzBjZAB_shmYYbKIVSJEvdbxkMRa4jd7DiB3Kxcg,6045
|
39
|
+
droidrun/agent/utils/__init__.py,sha256=Oro0oyiz1xzRpchWLDA1TZJELJNSwBOb2WdGgknthKo,244
|
40
|
+
droidrun/agent/utils/async_utils.py,sha256=_JhZ_ZfCkRTfPsufFDhUUds_Vp6z1-TokzUG4H8G7pc,338
|
41
|
+
droidrun/agent/utils/chat_utils.py,sha256=lKaQSwEqS3pAguTGehnvH0arilEvopP6CWwvnxCpsMs,11715
|
42
|
+
droidrun/agent/utils/device_state_formatter.py,sha256=rbFrpDfdXh9nA26M0p9ZEuY7e8dPnCtz850PrDe5HCU,6074
|
43
|
+
droidrun/agent/utils/executer.py,sha256=0yfoJZKQGjhzqptxV1pqwHV-cxwd0Q312IcjDVs9HuY,5234
|
44
|
+
droidrun/agent/utils/inference.py,sha256=nWlm_7Ufz4EODYeMHXL2a1RUwLa_Av0D5xT1jJWZtlo,3955
|
45
|
+
droidrun/agent/utils/llm_picker.py,sha256=m5PHBe8iex5n_a5fPwfPd5Qdup_atx4C6iv0-wTCGzY,7232
|
46
|
+
droidrun/agent/utils/message_utils.py,sha256=_wngf082gg232y_3pC_yn4fnPhHiyYAxhU4ewT78roo,2309
|
47
|
+
droidrun/agent/utils/tools.py,sha256=t_NDcOU_wMkZ2QrtNQsEbMRV5t7eCQ_Sv8EVlo4Ayiw,7678
|
48
|
+
droidrun/agent/utils/trajectory.py,sha256=wdnQaE20AZnlzBEAFrNhoMRimKF0cNJvYFs39dPSt2E,19507
|
49
|
+
droidrun/cli/__init__.py,sha256=5cO-QBcUl5w35zO18OENj4OShdglQjn8Ne9aqgSh-PM,167
|
50
|
+
droidrun/cli/logs.py,sha256=34AwXVHjzqIX0eDEug4hUHxzeFOZ99yk63hx8oIiBOQ,9899
|
51
|
+
droidrun/cli/main.py,sha256=hYUSx4AhaT-3wuBQq-9A-6OSwdGiDRyZepKybuLPOhU,25569
|
52
|
+
droidrun/config_manager/__init__.py,sha256=EBvCVqdolHP1ibU3AEHVI5qJ9n1LOHiGxYUOLpwB74w,445
|
53
|
+
droidrun/config_manager/config_manager.py,sha256=T2Swe7L1EDg2ulkDf_RbNnfIRLa0_RGDtcGtju9Zqqo,18320
|
54
|
+
droidrun/macro/__init__.py,sha256=UryKkwmf1slfoKNwlPFqtswCK9ezCVqRxHebNOtTZzQ,343
|
55
|
+
droidrun/macro/__main__.py,sha256=MWdBvQVhOoeKlC8atDwjVbPSn0-XNt4PDbpCCoeJuUk,193
|
56
|
+
droidrun/macro/cli.py,sha256=5PaWGlQbFCcyn9O00sE4e95OE2SUTJUmnCOlMf5Qimg,8843
|
57
|
+
droidrun/macro/replay.py,sha256=ILhnvN3VYhMK13wkaD5oDwP4wCYTniwcgesUON-9L5o,10721
|
58
|
+
droidrun/telemetry/__init__.py,sha256=Jh6Mpu9Ex04BEvnmnMqvb6zhLptikLFDXymsZode-Po,235
|
59
|
+
droidrun/telemetry/events.py,sha256=OnX5DsYxsp2pR2oQPqAqWt9dXIHuMk1KsjjhKvuSJqQ,444
|
60
|
+
droidrun/telemetry/phoenix.py,sha256=JHdFdRHXu7cleAb4X4_Y5yn5zPSIApwyKCOxoaj_gf4,7117
|
61
|
+
droidrun/telemetry/tracker.py,sha256=bIusAM33WSNLb3DrP0hqGrhJ3NeRSSm5b9r7D2OUSVg,2717
|
62
|
+
droidrun/tools/__init__.py,sha256=BbQFKuPn-5MwGzr-3urMDK8S1ZsP96D96y7WTJYB3AA,271
|
63
|
+
droidrun/tools/adb.py,sha256=cOs2bPOm9_74---jOjSTTQQHKLPfC6nkx7oK-yHEPJs,43916
|
64
|
+
droidrun/tools/ios.py,sha256=dLc3RqL2pyEYUJ_MNnJiszpl9Oa6aI5bs7xETJxTjAY,21829
|
65
|
+
droidrun/tools/tools.py,sha256=0eAZFTaY10eiiUcJM4AkURmTGX-O1RRXjpQ5MHj2Ydo,5241
|
66
|
+
droidrun-0.3.10.dev2.dist-info/METADATA,sha256=XQSG1jNM5RTxooa9jA4N-BWBHeC-nwQlpkMmlygmrT0,7158
|
67
|
+
droidrun-0.3.10.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
68
|
+
droidrun-0.3.10.dev2.dist-info/entry_points.txt,sha256=o259U66js8TIybQ7zs814Oe_LQ_GpZsp6a9Cr-xm5zE,51
|
69
|
+
droidrun-0.3.10.dev2.dist-info/licenses/LICENSE,sha256=s-uxn9qChu-kFdRXUp6v_0HhsaJ_5OANmfNOFVm2zdk,1069
|
70
|
+
droidrun-0.3.10.dev2.dist-info/RECORD,,
|
droidrun/agent/common/default.py
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
from dataclasses import dataclass
|
2
|
-
from typing import Optional
|
3
|
-
|
4
|
-
@dataclass
|
5
|
-
class Reflection:
|
6
|
-
"""Represents the result of a reflection analysis on episodic memory."""
|
7
|
-
goal_achieved: bool
|
8
|
-
summary: str
|
9
|
-
advice: Optional[str] = None
|
10
|
-
raw_response: Optional[str] = None
|
11
|
-
|
12
|
-
@classmethod
|
13
|
-
def from_dict(cls, data: dict) -> 'Reflection':
|
14
|
-
"""Create a Reflection from a dictionary (e.g., parsed JSON)."""
|
15
|
-
return cls(
|
16
|
-
goal_achieved=data.get('goal_achieved', False),
|
17
|
-
summary=data.get('summary', ''),
|
18
|
-
advice=data.get('advice'),
|
19
|
-
raw_response=data.get('raw_response')
|
20
|
-
)
|
@@ -1,265 +0,0 @@
|
|
1
|
-
from llama_index.core.llms.llm import LLM
|
2
|
-
from droidrun.agent.context import EpisodicMemory
|
3
|
-
from droidrun.agent.context.reflection import Reflection
|
4
|
-
from llama_index.core.base.llms.types import ChatMessage, ImageBlock
|
5
|
-
from droidrun.agent.utils.chat_utils import add_screenshot_image_block
|
6
|
-
from droidrun.agent.context.agent_persona import AgentPersona
|
7
|
-
import json
|
8
|
-
from typing import Dict, Any, List, Optional
|
9
|
-
import logging
|
10
|
-
from PIL import Image, ImageDraw, ImageFont
|
11
|
-
import io
|
12
|
-
|
13
|
-
logger = logging.getLogger("droidrun")
|
14
|
-
|
15
|
-
class Reflector:
|
16
|
-
def __init__(
|
17
|
-
self,
|
18
|
-
llm: LLM,
|
19
|
-
debug: bool = False,
|
20
|
-
*args,
|
21
|
-
**kwargs
|
22
|
-
):
|
23
|
-
self.llm = llm
|
24
|
-
self.debug = debug
|
25
|
-
|
26
|
-
async def reflect_on_episodic_memory(self, episodic_memory: EpisodicMemory, goal: str) -> Reflection:
|
27
|
-
"""Analyze episodic memory and provide reflection on the agent's performance."""
|
28
|
-
system_prompt_content = self._create_system_prompt()
|
29
|
-
system_prompt = ChatMessage(role="system", content=system_prompt_content)
|
30
|
-
|
31
|
-
episodic_memory_content = self._format_episodic_memory(episodic_memory)
|
32
|
-
persona_content = self._format_persona(episodic_memory.persona)
|
33
|
-
|
34
|
-
# Create user message content with persona information
|
35
|
-
user_content = f"{persona_content}\n\nGoal: {goal}\n\nEpisodic Memory Steps:\n{episodic_memory_content}\n\nPlease evaluate if the goal was achieved and provide your analysis in the specified JSON format."
|
36
|
-
|
37
|
-
# Create user message
|
38
|
-
user_message = ChatMessage(role="user", content=user_content)
|
39
|
-
|
40
|
-
# Create the screenshots grid and add as ImageBlock if screenshots exist
|
41
|
-
screenshots_grid = self._create_screenshots_grid(episodic_memory)
|
42
|
-
|
43
|
-
if screenshots_grid:
|
44
|
-
# Use the add_screenshot_image_block function to properly add the image
|
45
|
-
messages_list = [system_prompt, user_message]
|
46
|
-
messages_list = await add_screenshot_image_block(screenshots_grid, messages_list, copy=False)
|
47
|
-
messages = messages_list
|
48
|
-
else:
|
49
|
-
messages = [system_prompt, user_message]
|
50
|
-
response = await self.llm.achat(messages=messages)
|
51
|
-
|
52
|
-
logger.info(f"REFLECTION {response.message.content}")
|
53
|
-
|
54
|
-
try:
|
55
|
-
# Clean the response content to handle markdown code blocks
|
56
|
-
content = response.message.content.strip()
|
57
|
-
|
58
|
-
# Remove markdown code block formatting if present
|
59
|
-
if content.startswith('```json'):
|
60
|
-
content = content[7:] # Remove ```json
|
61
|
-
elif content.startswith('```'):
|
62
|
-
content = content[3:] # Remove ```
|
63
|
-
|
64
|
-
if content.endswith('```'):
|
65
|
-
content = content[:-3] # Remove trailing ```
|
66
|
-
|
67
|
-
content = content.strip()
|
68
|
-
|
69
|
-
parsed_response = json.loads(content)
|
70
|
-
return Reflection.from_dict(parsed_response)
|
71
|
-
except json.JSONDecodeError as e:
|
72
|
-
logger.error(f"Failed to parse reflection response: {e}")
|
73
|
-
logger.error(f"Raw response: {response.message.content}")
|
74
|
-
return await self.reflect_on_episodic_memory(episodic_memory=episodic_memory, goal=goal)
|
75
|
-
|
76
|
-
def _create_screenshots_grid(self, episodic_memory: EpisodicMemory) -> Optional[bytes]:
|
77
|
-
"""Create a 3x2 grid of screenshots from episodic memory steps."""
|
78
|
-
# Extract screenshots from steps
|
79
|
-
screenshots = []
|
80
|
-
for step in episodic_memory.steps:
|
81
|
-
if step.screenshot:
|
82
|
-
try:
|
83
|
-
# Convert bytes to PIL Image
|
84
|
-
screenshot_image = Image.open(io.BytesIO(step.screenshot))
|
85
|
-
screenshots.append(screenshot_image)
|
86
|
-
except Exception as e:
|
87
|
-
logger.warning(f"Failed to load screenshot: {e}")
|
88
|
-
continue
|
89
|
-
|
90
|
-
if not screenshots:
|
91
|
-
return None
|
92
|
-
|
93
|
-
num_screenshots = min(len(screenshots), 6)
|
94
|
-
cols, rows = num_screenshots, 1
|
95
|
-
|
96
|
-
screenshots = screenshots[:num_screenshots]
|
97
|
-
|
98
|
-
if not screenshots:
|
99
|
-
return None
|
100
|
-
|
101
|
-
if screenshots:
|
102
|
-
cell_width = screenshots[0].width // 2
|
103
|
-
cell_height = screenshots[0].height // 2
|
104
|
-
else:
|
105
|
-
return None
|
106
|
-
|
107
|
-
# Define header bar height
|
108
|
-
header_height = 60
|
109
|
-
|
110
|
-
# Create the grid image with space for header bars
|
111
|
-
grid_width = cols * cell_width
|
112
|
-
grid_height = rows * (cell_height + header_height)
|
113
|
-
grid_image = Image.new('RGB', (grid_width, grid_height), color='white')
|
114
|
-
|
115
|
-
# Set up font for step text
|
116
|
-
draw = ImageDraw.Draw(grid_image)
|
117
|
-
try:
|
118
|
-
# Use larger font for header text
|
119
|
-
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 48)
|
120
|
-
except:
|
121
|
-
font = ImageFont.load_default()
|
122
|
-
|
123
|
-
# Place screenshots in the grid with header bars
|
124
|
-
for i, screenshot in enumerate(screenshots):
|
125
|
-
row = i // cols
|
126
|
-
col = i % cols
|
127
|
-
|
128
|
-
# Calculate positions
|
129
|
-
x = col * cell_width
|
130
|
-
header_y = row * (cell_height + header_height)
|
131
|
-
screenshot_y = header_y + header_height
|
132
|
-
|
133
|
-
# Create header bar
|
134
|
-
header_rect = [x, header_y, x + cell_width, header_y + header_height]
|
135
|
-
draw.rectangle(header_rect, fill='#2c3e50') # Dark blue header
|
136
|
-
|
137
|
-
# Draw step text in header bar
|
138
|
-
text = f"Step {i+1}"
|
139
|
-
# Get text dimensions for centering
|
140
|
-
bbox = draw.textbbox((0, 0), text, font=font)
|
141
|
-
text_width = bbox[2] - bbox[0]
|
142
|
-
text_height = bbox[3] - bbox[1]
|
143
|
-
|
144
|
-
# Center text in header bar
|
145
|
-
text_x = x + (cell_width - text_width) // 2
|
146
|
-
text_y = header_y + (header_height - text_height) // 2
|
147
|
-
|
148
|
-
draw.text((text_x, text_y), text, fill='white', font=font)
|
149
|
-
|
150
|
-
# Resize and place screenshot below header
|
151
|
-
resized_screenshot = screenshot.resize((cell_width, cell_height), Image.Resampling.LANCZOS)
|
152
|
-
grid_image.paste(resized_screenshot, (x, screenshot_y))
|
153
|
-
|
154
|
-
# Save grid to disk for debugging (only if debug flag is enabled)
|
155
|
-
if self.debug:
|
156
|
-
import os
|
157
|
-
from datetime import datetime
|
158
|
-
|
159
|
-
# Create debug directory if it doesn't exist
|
160
|
-
debug_dir = "reflection_screenshots"
|
161
|
-
os.makedirs(debug_dir, exist_ok=True)
|
162
|
-
|
163
|
-
# Save with timestamp
|
164
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
165
|
-
debug_filename = os.path.join(debug_dir, f"screenshot_grid_{timestamp}.png")
|
166
|
-
grid_image.save(debug_filename)
|
167
|
-
logger.info(f"Screenshot grid saved to: {debug_filename}")
|
168
|
-
|
169
|
-
# Convert to bytes for use with add_screenshot_image_block
|
170
|
-
buffer = io.BytesIO()
|
171
|
-
grid_image.save(buffer, format='PNG')
|
172
|
-
buffer.seek(0)
|
173
|
-
|
174
|
-
return buffer.getvalue()
|
175
|
-
|
176
|
-
def _create_system_prompt(self) -> str:
|
177
|
-
"""Create a system prompt with reflection instructions."""
|
178
|
-
system_prompt = """You are a Reflector AI that analyzes the performance of an Android Agent. Your role is to examine episodic memory steps and evaluate whether the agent achieved its goal.
|
179
|
-
|
180
|
-
EVALUATION PROCESS:
|
181
|
-
1. First, determine if the agent achieved the stated goal based on the episodic memory steps
|
182
|
-
2. If the goal was achieved, acknowledge the success
|
183
|
-
3. If the goal was NOT achieved, analyze what went wrong and provide direct advice
|
184
|
-
4. Use the provided screenshots (if any) to understand the visual context of each step
|
185
|
-
The screenshots show a screen the agent saw. It is in chronological order from left to right
|
186
|
-
|
187
|
-
ANALYSIS AREAS (for failed goals):
|
188
|
-
- Missed opportunities or inefficient actions
|
189
|
-
- Incorrect tool usage or navigation choices
|
190
|
-
- Failure to understand context or user intent
|
191
|
-
- Suboptimal decision-making patterns
|
192
|
-
|
193
|
-
ADVICE GUIDELINES (for failed goals):
|
194
|
-
- Address the agent directly using "you" form with present/future focus (e.g., "You need to...", "Look for...", "Focus on...")
|
195
|
-
- Provide situational awareness advice that helps with the current state after the failed attempt
|
196
|
-
- Give actionable guidance for what to do NOW when retrying the goal, not what went wrong before
|
197
|
-
- Consider the current app state and context the agent will face when retrying
|
198
|
-
- Focus on the key strategy or approach needed for success in the current situation
|
199
|
-
- Keep it concise but precise (1-2 sentences)
|
200
|
-
|
201
|
-
OUTPUT FORMAT:
|
202
|
-
You MUST respond with a valid JSON object in this exact format:
|
203
|
-
|
204
|
-
{{
|
205
|
-
"goal_achieved": true,
|
206
|
-
"advice": null,
|
207
|
-
"summary": "Brief summary of what happened"
|
208
|
-
}}
|
209
|
-
|
210
|
-
OR
|
211
|
-
|
212
|
-
{{
|
213
|
-
"goal_achieved": false,
|
214
|
-
"advice": "Direct advice using 'you' form focused on current situation - what you need to do NOW when retrying",
|
215
|
-
"summary": "Brief summary of what happened"
|
216
|
-
}}
|
217
|
-
|
218
|
-
IMPORTANT:
|
219
|
-
- If goal_achieved is true, set advice to null
|
220
|
-
- If goal_achieved is false, provide direct "you" form advice focused on what to do NOW in the current situation when retrying
|
221
|
-
- Advice should be forward-looking and situational, not retrospective about past mistakes
|
222
|
-
- Always include a brief summary of the agent's performance
|
223
|
-
- Ensure the JSON is valid and parsable
|
224
|
-
- ONLY return the JSON object, no additional text or formatting"""
|
225
|
-
|
226
|
-
return system_prompt
|
227
|
-
|
228
|
-
def _format_persona(self, persona: AgentPersona) -> str:
|
229
|
-
"""Format the agent persona information for the user prompt."""
|
230
|
-
persona_content = f"""ACTOR AGENT PERSONA:
|
231
|
-
- Name: {persona.name}
|
232
|
-
- Description: {persona.description}
|
233
|
-
- Available Tools: {', '.join(persona.allowed_tools)}
|
234
|
-
- Expertise Areas: {', '.join(persona.expertise_areas)}
|
235
|
-
- System Prompt: {persona.system_prompt}"""
|
236
|
-
|
237
|
-
return persona_content
|
238
|
-
|
239
|
-
def _format_episodic_memory(self, episodic_memory: EpisodicMemory) -> str:
|
240
|
-
"""Format the episodic memory steps into a readable format for analysis."""
|
241
|
-
formatted_steps = []
|
242
|
-
|
243
|
-
for i, step in enumerate(episodic_memory.steps, 1):
|
244
|
-
try:
|
245
|
-
# Parse the JSON strings to get the original content without escape characters
|
246
|
-
chat_history = json.loads(step.chat_history)
|
247
|
-
response = json.loads(step.response)
|
248
|
-
|
249
|
-
|
250
|
-
formatted_step = f"""Step {i}:
|
251
|
-
Chat History: {json.dumps(chat_history, indent=2)}
|
252
|
-
Response: {json.dumps(response, indent=2)}
|
253
|
-
Timestamp: {step.timestamp}
|
254
|
-
---"""
|
255
|
-
except json.JSONDecodeError as e:
|
256
|
-
# Fallback to original format if JSON parsing fails
|
257
|
-
logger.warning(f"Failed to parse JSON for step {i}: {e}")
|
258
|
-
formatted_step = f"""Step {i}:
|
259
|
-
Chat History: {step.chat_history}
|
260
|
-
Response: {step.response}
|
261
|
-
Timestamp: {step.timestamp}
|
262
|
-
---"""
|
263
|
-
formatted_steps.append(formatted_step)
|
264
|
-
|
265
|
-
return "\n".join(formatted_steps)
|
droidrun-0.3.8.dist-info/RECORD
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
droidrun/__init__.py,sha256=Cqt4NXZ-753220dlRZXglMkFT2ygcXSErMmqupGsi9A,622
|
2
|
-
droidrun/__main__.py,sha256=78o1Wr_Z-NrZy9yLWmEfNfRRhAiJGBr4Xi3lmbgkx3w,105
|
3
|
-
droidrun/portal.py,sha256=4-1lNc28yxDSkg2qf_t36gXzTSflcJqfsxggYpUwmio,6169
|
4
|
-
droidrun/agent/__init__.py,sha256=4SqTJeGDvr_wT8rtN9J8hnN6P-pae663mkYr-JmzH4w,208
|
5
|
-
droidrun/agent/usage.py,sha256=ZTgqxRAgugJ9tk6ApZ2BJ5nB88pt9rhLyTFS5AnVUHo,7153
|
6
|
-
droidrun/agent/codeact/__init__.py,sha256=ZLDGT_lTTzyNm7pcBzdyRIGHJ2ZgbInJdhXZRbJLhSQ,278
|
7
|
-
droidrun/agent/codeact/codeact_agent.py,sha256=34lGKarbXcPRJVghRPlpJAt9ZDKBG2iwZmWYs-wz8DQ,17123
|
8
|
-
droidrun/agent/codeact/events.py,sha256=R3lNWSRTHQBkIBlel6CzyEUuozD40_9cugTvQ6PZsvw,720
|
9
|
-
droidrun/agent/codeact/prompts.py,sha256=28HflWMNkC1ky0hGCzAxhJftjU2IIU1ZRUfya3S7M6I,1006
|
10
|
-
droidrun/agent/common/default.py,sha256=P07el-PrHsoqQMYsYxSSln6mFl-QY75vzwp1Dll_XmY,259
|
11
|
-
droidrun/agent/common/events.py,sha256=xh1Qly2_ZC2edRr3Ad18QMe90ndRDxrJYZBWB3rqIjg,1183
|
12
|
-
droidrun/agent/context/__init__.py,sha256=upSJilVQUwQYWJuGr_8QrmJaReV3SNAc_Z61wQZzbK4,697
|
13
|
-
droidrun/agent/context/agent_persona.py,sha256=Mxd4HTyirWD-aqNlka1hQBdS-0I-lXJr2AjPMwDMUo8,390
|
14
|
-
droidrun/agent/context/context_injection_manager.py,sha256=sA33q2KPtX_4Yap8wM11T6ewlZC_0FIbKPEc400SHrE,2188
|
15
|
-
droidrun/agent/context/episodic_memory.py,sha256=1ImeR3jAWOpKwkQt3bMlXVOBiQbIli5fBIlBq2waREQ,394
|
16
|
-
droidrun/agent/context/reflection.py,sha256=0hJluOz0hTlHHhReKpIJ9HU5aJbaJsvrjMfraQ84D-M,652
|
17
|
-
droidrun/agent/context/task_manager.py,sha256=9CDax1G48DRcqPm1JYy9UiLI7wPsF34eqAM0dRDCC1k,4992
|
18
|
-
droidrun/agent/context/personas/__init__.py,sha256=oSRa8g_xngX7JPIRPu7fLO33m3r7fdEQzIuORuqcw5M,232
|
19
|
-
droidrun/agent/context/personas/app_starter.py,sha256=dHeknznxGEPJ7S6VPyEG_MB-HvAvQwUOnRWaShaV8Xo,1585
|
20
|
-
droidrun/agent/context/personas/big_agent.py,sha256=Gl_y4ykz3apGc203-KG2UbSOwf7gDUiWh7GOVyiLn-Y,5091
|
21
|
-
droidrun/agent/context/personas/default.py,sha256=Xm07YCWoKjvlHAbQRtzE3vn7BVcz6wYcSVeg4FiojJQ,5060
|
22
|
-
droidrun/agent/context/personas/ui_expert.py,sha256=j0OKfN1jQSrREHcVeomMTDPCWLsZVX4aeuWN4Y-x3z0,4739
|
23
|
-
droidrun/agent/droid/__init__.py,sha256=3BfUVZiUQ8ATAJ_JmqQZQx53WoERRpQ4AyHW5WOgbRI,297
|
24
|
-
droidrun/agent/droid/droid_agent.py,sha256=Bd273hbefa7s1M-HW_FQEuhQWUKctDjhdlGyH6k455A,17650
|
25
|
-
droidrun/agent/droid/events.py,sha256=hjYpWcSffqP83rNv_GyOEc3CNSrdvlVPdUkaRU6QDJc,722
|
26
|
-
droidrun/agent/oneflows/reflector.py,sha256=I_tE0PBjvwWbS6SA8Qd41etxJglFgn8oScuKUxc9LEE,11621
|
27
|
-
droidrun/agent/planner/__init__.py,sha256=Fu0Ewtd-dIRLgHIL1DB_9EEKvQS_f1vjB8jgO5TbJXg,364
|
28
|
-
droidrun/agent/planner/events.py,sha256=AJEC5lqMc5qLoj8V7lIN08KXT0YEg3i1anjLqiNS6is,475
|
29
|
-
droidrun/agent/planner/planner_agent.py,sha256=3Jx6NZJ3IFmb5zi2gKxmPZ2nuLjKyUOVec3SdNAuhVY,11456
|
30
|
-
droidrun/agent/planner/prompts.py,sha256=Ci7Oeu3J4TAhx-tKGPZ9l6Wb3a81FSqC8cWW4jW73HI,6046
|
31
|
-
droidrun/agent/utils/__init__.py,sha256=JK6ygRjw7gzcQSG0HBEYLoVGH54QQAxJJ7HpIS5mgyc,44
|
32
|
-
droidrun/agent/utils/async_utils.py,sha256=IQBcWPwevm89B7R_UdMXk0unWeNCBA232b5kQGqoxNI,336
|
33
|
-
droidrun/agent/utils/chat_utils.py,sha256=KzmiNasXb9d0qH12ylRsWooKV4_9LXy_QifaD_xf_O0,12726
|
34
|
-
droidrun/agent/utils/executer.py,sha256=EBDGBMUAL80fJ6yyyt0v4XElhcjEGwi4_K4oU3_Loxo,5203
|
35
|
-
droidrun/agent/utils/llm_picker.py,sha256=V35nrOeSUeXoIV0eDKHBo3ESTAKj-N4NRX75i0LO1JM,7230
|
36
|
-
droidrun/agent/utils/trajectory.py,sha256=xvfj274AdRdIAVz72889ndoj-dD0_iOmLQBVQbXNcP4,19510
|
37
|
-
droidrun/cli/__init__.py,sha256=DuwSRtZ8WILPd-nf-fZ7BaBsRgtofoInOF3JtJ9wag0,167
|
38
|
-
droidrun/cli/logs.py,sha256=-idRi3HTp7OfZRKAe9FPmiavPUYgQEdOqy3j5wXjOZI,9842
|
39
|
-
droidrun/cli/main.py,sha256=yW6TU7nk91zuM9QFHfoJz7wbTdJPNHnpoiXZfuA3gbo,18392
|
40
|
-
droidrun/macro/__init__.py,sha256=333sMt19mA8sfQa4qPKbbCmr8Ej3nvpdxGXUZtVTEqM,344
|
41
|
-
droidrun/macro/__main__.py,sha256=-zj42Bj7309oLPZbNsxZeNwIDaEe7Th1I4zF8yAHasw,193
|
42
|
-
droidrun/macro/cli.py,sha256=GaL1wVWVE_AT0OxHgOJyW-q_kVu4PQ76KZKeYMQdoEk,9057
|
43
|
-
droidrun/macro/replay.py,sha256=q_3ZcHVjvsdDfS2xyt_vuuwXGt9_1t38JD1cPsjzIfU,10764
|
44
|
-
droidrun/telemetry/__init__.py,sha256=D4Mp02iGJH2Tjpv42Bzyo6_WC3NWj9Qy9hQPWFaCkhA,234
|
45
|
-
droidrun/telemetry/events.py,sha256=OIYIs5stZtKz0g82W8WFE_h6q3jh0vUhc9_CwNTJ3a4,529
|
46
|
-
droidrun/telemetry/tracker.py,sha256=Ljue6zivX8KnadXI9DivrayuWxAnUwbJKvCvNtY1Y4Y,2717
|
47
|
-
droidrun/tools/__init__.py,sha256=9ReauavtSKDQG9ya9_Fr9O0TQnDFixgOPaP5n82_iEk,271
|
48
|
-
droidrun/tools/adb.py,sha256=91HmimUJtvGyMcE2HEDJLvTQt95ZYNCXWAJlOs4X9HQ,38302
|
49
|
-
droidrun/tools/ios.py,sha256=imzojiS6gqz4IKexUEz1ga7-flSOaC5QRpHIJTwcgSQ,21807
|
50
|
-
droidrun/tools/tools.py,sha256=Swlzo9A8B8YcgU6XNHRG1LNpo_-RljzhyVhnEYYm-G4,4772
|
51
|
-
droidrun-0.3.8.dist-info/METADATA,sha256=XRxqWy7WDo517RjnWToTMRR0yD11bb2w919wgrtKW7Q,6859
|
52
|
-
droidrun-0.3.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
53
|
-
droidrun-0.3.8.dist-info/entry_points.txt,sha256=o259U66js8TIybQ7zs814Oe_LQ_GpZsp6a9Cr-xm5zE,51
|
54
|
-
droidrun-0.3.8.dist-info/licenses/LICENSE,sha256=s-uxn9qChu-kFdRXUp6v_0HhsaJ_5OANmfNOFVm2zdk,1069
|
55
|
-
droidrun-0.3.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|