droidrun 0.3.10.dev5__py3-none-any.whl → 0.3.10.dev7__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/agent/codeact/codeact_agent.py +21 -29
- droidrun/agent/context/task_manager.py +0 -1
- droidrun/agent/droid/droid_agent.py +1 -3
- droidrun/agent/droid/events.py +6 -3
- droidrun/agent/executor/executor_agent.py +24 -38
- droidrun/agent/executor/prompts.py +0 -108
- droidrun/agent/manager/__init__.py +1 -1
- droidrun/agent/manager/manager_agent.py +104 -87
- droidrun/agent/utils/executer.py +11 -10
- droidrun/agent/utils/llm_picker.py +63 -1
- droidrun/agent/utils/tools.py +30 -1
- droidrun/app_cards/app_card_provider.py +26 -0
- droidrun/app_cards/providers/__init__.py +7 -0
- droidrun/app_cards/providers/composite_provider.py +97 -0
- droidrun/app_cards/providers/local_provider.py +115 -0
- droidrun/app_cards/providers/server_provider.py +126 -0
- droidrun/cli/logs.py +4 -4
- droidrun/cli/main.py +244 -34
- droidrun/config_manager/__init__.py +0 -2
- droidrun/config_manager/config_manager.py +45 -102
- droidrun/config_manager/path_resolver.py +1 -1
- droidrun/config_manager/prompt_loader.py +48 -51
- droidrun/macro/cli.py +0 -1
- droidrun/portal.py +17 -0
- droidrun/tools/adb.py +13 -34
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/METADATA +2 -9
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/RECORD +30 -26
- droidrun/config_manager/app_card_loader.py +0 -148
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/WHEEL +0 -0
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/entry_points.txt +0 -0
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/licenses/LICENSE +0 -0
@@ -1,75 +1,72 @@
|
|
1
1
|
"""
|
2
|
-
Prompt loading utility
|
3
|
-
|
4
|
-
|
5
|
-
-
|
6
|
-
- {
|
7
|
-
-
|
2
|
+
Prompt loading utility using Jinja2 templates.
|
3
|
+
|
4
|
+
Features:
|
5
|
+
- Loads from absolute file paths (resolved by AgentConfig + PathResolver)
|
6
|
+
- Conditional rendering: {% if variable %}...{% endif %}
|
7
|
+
- Loops with slicing: {% for item in items[-5:] %}...{% endfor %}
|
8
|
+
- Filters: {{ variable|default("fallback") }}
|
9
|
+
- Missing variables: silently ignored (renders as empty string)
|
10
|
+
- Extra variables: silently ignored
|
8
11
|
"""
|
9
12
|
|
10
|
-
import re
|
11
13
|
from pathlib import Path
|
12
14
|
from typing import Any, Dict
|
13
15
|
|
14
|
-
from
|
16
|
+
from jinja2 import Environment
|
15
17
|
|
16
18
|
|
17
19
|
class PromptLoader:
|
18
|
-
"""
|
20
|
+
"""Simple Jinja2 template renderer - loads from absolute file paths."""
|
21
|
+
|
22
|
+
_env = None # Cached Jinja2 environment
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
def _get_environment(cls) -> Environment:
|
26
|
+
"""Get or create cached Jinja2 environment."""
|
27
|
+
if cls._env is None:
|
28
|
+
cls._env = Environment(
|
29
|
+
trim_blocks=True, # Remove first newline after block
|
30
|
+
lstrip_blocks=True, # Strip leading whitespace before blocks
|
31
|
+
keep_trailing_newline=False,
|
32
|
+
)
|
33
|
+
|
34
|
+
return cls._env
|
19
35
|
|
20
36
|
@staticmethod
|
21
|
-
def load_prompt(
|
37
|
+
def load_prompt(file_path: str, variables: Dict[str, Any] = None) -> str:
|
22
38
|
"""
|
23
|
-
Load
|
24
|
-
|
25
|
-
Path resolution:
|
26
|
-
- Checks working directory first (for user overrides)
|
27
|
-
- Falls back to project directory (for default prompts)
|
28
|
-
- Example: "config/prompts/codeact/system.md"
|
39
|
+
Load and render Jinja2 template from absolute file path.
|
29
40
|
|
30
|
-
|
31
|
-
|
32
|
-
- {{variable}} → becomes literal {variable} in output
|
33
|
-
- Missing variables → left as {variable} (no error)
|
41
|
+
Path resolution is handled by AgentConfig + PathResolver.
|
42
|
+
This method just loads and renders.
|
34
43
|
|
35
44
|
Args:
|
36
|
-
|
37
|
-
variables: Dict of
|
45
|
+
file_path: ABSOLUTE path to template file (from AgentConfig methods)
|
46
|
+
variables: Dict of variables to pass to template
|
47
|
+
- Missing variables: silently ignored (render as empty string)
|
48
|
+
- Extra variables: silently ignored
|
38
49
|
|
39
50
|
Returns:
|
40
|
-
|
51
|
+
Rendered prompt string
|
41
52
|
|
42
53
|
Raises:
|
43
|
-
FileNotFoundError: If
|
44
|
-
"""
|
45
|
-
# Resolve path (checks working dir, then project dir)
|
46
|
-
prompt_path = PathResolver.resolve(path, must_exist=True)
|
47
|
-
|
48
|
-
prompt_text = prompt_path.read_text(encoding="utf-8")
|
49
|
-
|
50
|
-
if variables is None:
|
51
|
-
return prompt_text
|
54
|
+
FileNotFoundError: If template file doesn't exist
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
escaped_pattern = re.compile(r'\{\{([^}]+)\}\}')
|
56
|
-
placeholders = {}
|
57
|
-
counter = [0]
|
58
|
-
|
59
|
-
def escape_replacer(match):
|
60
|
-
placeholder = f"__ESCAPED_{counter[0]}__"
|
61
|
-
placeholders[placeholder] = "{" + match.group(1) + "}"
|
62
|
-
counter[0] += 1
|
63
|
-
return placeholder
|
56
|
+
"""
|
57
|
+
path = Path(file_path)
|
64
58
|
|
65
|
-
|
59
|
+
if not path.exists():
|
60
|
+
raise FileNotFoundError(f"Prompt file not found: {file_path}")
|
66
61
|
|
67
|
-
#
|
68
|
-
|
69
|
-
prompt_text = prompt_text.replace(f"{{{key}}}", str(value))
|
62
|
+
# Read template content
|
63
|
+
template_content = path.read_text(encoding="utf-8")
|
70
64
|
|
71
|
-
#
|
72
|
-
|
73
|
-
|
65
|
+
# Get cached environment and create template from string
|
66
|
+
env = PromptLoader._get_environment()
|
67
|
+
template = env.from_string(template_content)
|
74
68
|
|
75
|
-
|
69
|
+
# Render with variables (empty dict if None)
|
70
|
+
# Missing variables render as empty string (default Undefined behavior)
|
71
|
+
# Extra variables are silently ignored
|
72
|
+
return template.render(**(variables or {}))
|
droidrun/macro/cli.py
CHANGED
droidrun/portal.py
CHANGED
@@ -190,6 +190,23 @@ def setup_keyboard(device: AdbDevice):
|
|
190
190
|
except Exception as e:
|
191
191
|
raise Exception("Error setting up keyboard") from e
|
192
192
|
|
193
|
+
def disable_keyboard(device: AdbDevice, target_ime: str = "com.droidrun.portal/.DroidrunKeyboardIME"):
|
194
|
+
"""
|
195
|
+
Disable a specific IME (keyboard) and optionally switch to another.
|
196
|
+
By default, disables the DroidRun keyboard.
|
197
|
+
|
198
|
+
Args:
|
199
|
+
target_ime: The IME package/activity to disable (default: DroidRun keyboard)
|
200
|
+
|
201
|
+
Returns:
|
202
|
+
bool: True if disabled successfully, False otherwise
|
203
|
+
"""
|
204
|
+
try:
|
205
|
+
device.shell(f"ime disable {target_ime}")
|
206
|
+
return True
|
207
|
+
except Exception as e:
|
208
|
+
raise Exception("Error disabling keyboard") from e
|
209
|
+
|
193
210
|
def test():
|
194
211
|
device = adb.device()
|
195
212
|
ping_portal(device, debug=False)
|
droidrun/tools/adb.py
CHANGED
@@ -71,7 +71,9 @@ class AdbTools(Tools):
|
|
71
71
|
self.app_opener_llm = app_opener_llm
|
72
72
|
self.text_manipulator_llm = text_manipulator_llm
|
73
73
|
|
74
|
-
|
74
|
+
# Set up keyboard
|
75
|
+
from droidrun.portal import setup_keyboard
|
76
|
+
setup_keyboard(self.device)
|
75
77
|
|
76
78
|
# Set up TCP forwarding if requested
|
77
79
|
if self.use_tcp:
|
@@ -150,24 +152,6 @@ class AdbTools(Tools):
|
|
150
152
|
logger.error(f"Failed to remove TCP port forwarding: {e}")
|
151
153
|
return False
|
152
154
|
|
153
|
-
def setup_keyboard(self) -> bool:
|
154
|
-
"""
|
155
|
-
Set up the DroidRun keyboard as the default input method.
|
156
|
-
Simple setup that just switches to DroidRun keyboard without saving/restoring.
|
157
|
-
|
158
|
-
Returns:
|
159
|
-
bool: True if setup was successful, False otherwise
|
160
|
-
"""
|
161
|
-
try:
|
162
|
-
self.device.shell("ime enable com.droidrun.portal/.DroidrunKeyboardIME")
|
163
|
-
self.device.shell("ime set com.droidrun.portal/.DroidrunKeyboardIME")
|
164
|
-
logger.debug("DroidRun keyboard setup completed")
|
165
|
-
return True
|
166
|
-
|
167
|
-
except Exception as e:
|
168
|
-
logger.error(f"Failed to setup DroidRun keyboard: {e}")
|
169
|
-
return False
|
170
|
-
|
171
155
|
def __del__(self):
|
172
156
|
"""Cleanup when the object is destroyed."""
|
173
157
|
if hasattr(self, "tcp_forwarded") and self.tcp_forwarded:
|
@@ -312,12 +296,9 @@ class AdbTools(Tools):
|
|
312
296
|
# Extract coordinates using the helper function
|
313
297
|
x, y = self._extract_element_coordinates_by_index(index)
|
314
298
|
|
315
|
-
logger.debug(
|
316
|
-
f"Tapping element with index {index} at coordinates ({x}, {y})"
|
317
|
-
)
|
318
299
|
# Get the device and tap at the coordinates
|
319
300
|
self.device.click(x, y)
|
320
|
-
|
301
|
+
print(f"Tapped element with index {index} at coordinates ({x}, {y})")
|
321
302
|
|
322
303
|
# Emit coordinate action event for trajectory recording
|
323
304
|
if self._ctx:
|
@@ -350,8 +331,7 @@ class AdbTools(Tools):
|
|
350
331
|
)
|
351
332
|
self._ctx.write_event_to_stream(tap_event)
|
352
333
|
|
353
|
-
|
354
|
-
time.sleep(0.5)
|
334
|
+
|
355
335
|
|
356
336
|
# Create a descriptive response
|
357
337
|
def find_element_by_index(elements, target_index):
|
@@ -463,7 +443,7 @@ class AdbTools(Tools):
|
|
463
443
|
|
464
444
|
self.device.swipe(start_x, start_y, end_x, end_y, float(duration_ms / 1000))
|
465
445
|
time.sleep(duration_ms / 1000)
|
466
|
-
|
446
|
+
print(
|
467
447
|
f"Swiped from ({start_x}, {start_y}) to ({end_x}, {end_y}) in {duration_ms} milliseconds"
|
468
448
|
)
|
469
449
|
return True
|
@@ -546,7 +526,7 @@ class AdbTools(Tools):
|
|
546
526
|
timeout=10,
|
547
527
|
)
|
548
528
|
|
549
|
-
|
529
|
+
print(
|
550
530
|
f"Keyboard input TCP response: {response.status_code}, {response.text}"
|
551
531
|
)
|
552
532
|
|
@@ -575,7 +555,7 @@ class AdbTools(Tools):
|
|
575
555
|
|
576
556
|
# Execute the command and capture output for better error handling
|
577
557
|
result = self.device.shell(cmd)
|
578
|
-
|
558
|
+
print(f"Content provider result: {result}")
|
579
559
|
|
580
560
|
if self._ctx:
|
581
561
|
input_event = InputTextActionEvent(
|
@@ -585,7 +565,7 @@ class AdbTools(Tools):
|
|
585
565
|
)
|
586
566
|
self._ctx.write_event_to_stream(input_event)
|
587
567
|
|
588
|
-
|
568
|
+
print(
|
589
569
|
f"Text input completed (clear={clear}): {text[:50]}{'...' if len(text) > 50 else ''}"
|
590
570
|
)
|
591
571
|
return f"Text input completed (clear={clear}): {text[:50]}{'...' if len(text) > 50 else ''}"
|
@@ -604,7 +584,7 @@ class AdbTools(Tools):
|
|
604
584
|
This presses the Android back button.
|
605
585
|
"""
|
606
586
|
try:
|
607
|
-
|
587
|
+
print("Pressing key BACK")
|
608
588
|
self.device.keyevent(4)
|
609
589
|
|
610
590
|
if self._ctx:
|
@@ -652,9 +632,8 @@ class AdbTools(Tools):
|
|
652
632
|
)
|
653
633
|
self._ctx.write_event_to_stream(key_event)
|
654
634
|
|
655
|
-
logger.debug(f"Pressing key {key_name}")
|
656
635
|
self.device.keyevent(keycode)
|
657
|
-
|
636
|
+
print(f"Pressed key {key_name}")
|
658
637
|
return f"Pressed key {key_name}"
|
659
638
|
except ValueError as e:
|
660
639
|
return f"Error: {str(e)}"
|
@@ -670,7 +649,7 @@ class AdbTools(Tools):
|
|
670
649
|
"""
|
671
650
|
try:
|
672
651
|
|
673
|
-
|
652
|
+
print(f"Starting app {package} with activity {activity}")
|
674
653
|
if not activity:
|
675
654
|
dumpsys_output = self.device.shell(
|
676
655
|
f"cmd package resolve-activity --brief {package}"
|
@@ -689,7 +668,7 @@ class AdbTools(Tools):
|
|
689
668
|
print(f"Activity: {activity}")
|
690
669
|
|
691
670
|
self.device.app_start(package, activity)
|
692
|
-
|
671
|
+
print(f"App started: {package} with activity {activity}")
|
693
672
|
return f"App started: {package} with activity {activity}"
|
694
673
|
except Exception as e:
|
695
674
|
return f"Error: {str(e)}"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: droidrun
|
3
|
-
Version: 0.3.10.
|
3
|
+
Version: 0.3.10.dev7
|
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
|
@@ -29,6 +29,7 @@ Requires-Python: >=3.11
|
|
29
29
|
Requires-Dist: adbutils>=2.10.2
|
30
30
|
Requires-Dist: apkutils==2.0.0
|
31
31
|
Requires-Dist: arize-phoenix>=12.3.0
|
32
|
+
Requires-Dist: httpx>=0.27.0
|
32
33
|
Requires-Dist: llama-index==0.14.4
|
33
34
|
Requires-Dist: posthog>=6.7.6
|
34
35
|
Requires-Dist: pydantic>=2.11.10
|
@@ -36,14 +37,6 @@ Requires-Dist: rich>=14.1.0
|
|
36
37
|
Provides-Extra: anthropic
|
37
38
|
Requires-Dist: anthropic>=0.67.0; extra == 'anthropic'
|
38
39
|
Requires-Dist: llama-index-llms-anthropic<0.9.0,>=0.8.6; extra == 'anthropic'
|
39
|
-
Provides-Extra: backend
|
40
|
-
Requires-Dist: aiohttp>=3.9.0; extra == 'backend'
|
41
|
-
Requires-Dist: fastapi>=0.104.0; extra == 'backend'
|
42
|
-
Requires-Dist: pydantic-settings>=2.0.0; extra == 'backend'
|
43
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'backend'
|
44
|
-
Requires-Dist: python-multipart>=0.0.6; extra == 'backend'
|
45
|
-
Requires-Dist: uvicorn[standard]>=0.24.0; extra == 'backend'
|
46
|
-
Requires-Dist: websockets>=12.0; extra == 'backend'
|
47
40
|
Provides-Extra: deepseek
|
48
41
|
Requires-Dist: llama-index-llms-deepseek>=0.2.1; extra == 'deepseek'
|
49
42
|
Provides-Extra: dev
|
@@ -1,26 +1,26 @@
|
|
1
1
|
droidrun/__init__.py,sha256=c2exmv8MuTJ6wWXqzPR30pKGENeIgWe5ytY5hSQYuBc,621
|
2
2
|
droidrun/__main__.py,sha256=8HpscyKn49EH05wXIdoxMiU43xPKb1czq8Aze2vIIqI,106
|
3
|
-
droidrun/portal.py,sha256=
|
3
|
+
droidrun/portal.py,sha256=QCfJecUpuyd9io_76ngJizs1ebKubMzVMmCWXpgC6PM,6737
|
4
4
|
droidrun/agent/__init__.py,sha256=91sM0qTmdV5trlXOWE4D_nRhXVPgHKMnYU_9Stc_obQ,209
|
5
5
|
droidrun/agent/usage.py,sha256=6PVeHctNa0EmHmNPTdOUv5e3-EK6AMu6D2Pz5OMqs5c,7145
|
6
6
|
droidrun/agent/codeact/__init__.py,sha256=lagBdrury33kbHN1XEZ-xzJ-RywmpkUUoUidOno9ym8,96
|
7
|
-
droidrun/agent/codeact/codeact_agent.py,sha256=
|
7
|
+
droidrun/agent/codeact/codeact_agent.py,sha256=7EkuazNIpTOX-W1oSG0XmtOwcmNOyaiPddgNxnK10No,20292
|
8
8
|
droidrun/agent/codeact/events.py,sha256=kRKTQPzogPiQwmOCc_fGcg1g1zDXXVeBpDl45GTdpYU,734
|
9
9
|
droidrun/agent/common/constants.py,sha256=q7ywmOXCsJZg8m9ctpzQ-nxvuj5GMn28Pr8z3dMj1Rg,94
|
10
10
|
droidrun/agent/common/events.py,sha256=rbPWdlqNNMdnVjYhJOL2mJcNNORHhjXOkY8XiLPzp7c,1182
|
11
11
|
droidrun/agent/context/__init__.py,sha256=-CiAv66qym_WgFy5vCRfNLxmiprmEbssu6S_2jj0LZw,452
|
12
12
|
droidrun/agent/context/episodic_memory.py,sha256=0WKmOPe_KDWGdxudUXkmNVO1vj7L1g2zpyhAA54E1Lk,308
|
13
|
-
droidrun/agent/context/task_manager.py,sha256=
|
13
|
+
droidrun/agent/context/task_manager.py,sha256=A2COoBMXBOCtrASC4QI8ZdYizNVLOD04e4rzviVIMbk,5013
|
14
14
|
droidrun/agent/droid/__init__.py,sha256=3Kzejs0p2hqKzgMc253W147P-Y84bYnQX7AZ4pybIsU,297
|
15
|
-
droidrun/agent/droid/droid_agent.py,sha256=
|
16
|
-
droidrun/agent/droid/events.py,sha256=
|
15
|
+
droidrun/agent/droid/droid_agent.py,sha256=FRHNsuEyDY7n6jGwxnjoyAAgHhHWRQkbx5-Onen0Zvw,21722
|
16
|
+
droidrun/agent/droid/events.py,sha256=m7FoIpAb4Fd6pcFyoWf9Jx9mYhSV8qMCieHEfYS7Fsg,4059
|
17
17
|
droidrun/agent/executor/__init__.py,sha256=2B531GoY7L1Hs_RJIVu62ARsP9mj86do8MiFl6ejpZ4,456
|
18
18
|
droidrun/agent/executor/events.py,sha256=sYMs24at_VtikPKqSh_yNRYByDt4JpS1jiEob9UjNrs,1377
|
19
|
-
droidrun/agent/executor/executor_agent.py,sha256=
|
20
|
-
droidrun/agent/executor/prompts.py,sha256=
|
21
|
-
droidrun/agent/manager/__init__.py,sha256=
|
19
|
+
droidrun/agent/executor/executor_agent.py,sha256=mBbL-NfZ59w-8TDz_etuku-fgPzrL9DE4h5vi-STEWM,13923
|
20
|
+
droidrun/agent/executor/prompts.py,sha256=amHWdGV-q-lgFkwg8N8VGeshvUqkEdxTM8GHnt7uTUQ,1182
|
21
|
+
droidrun/agent/manager/__init__.py,sha256=A8esHVpxzHd3Epzkl0j5seNkRQqwNEn1a97eeLmbsww,525
|
22
22
|
droidrun/agent/manager/events.py,sha256=X0tUwCX2mU8I4bGR4JW2NmUqiOrX-Hrb017vGVPVyHw,855
|
23
|
-
droidrun/agent/manager/manager_agent.py,sha256=
|
23
|
+
droidrun/agent/manager/manager_agent.py,sha256=nXftmLlSLDs9LLB3rHE3EzpaCnUKa6v1dNfjFTMV9ys,22256
|
24
24
|
droidrun/agent/manager/prompts.py,sha256=qfDYcSbpWpnUaavAuPE6qY6Df6w25LmtY1mEiBUMti0,2060
|
25
25
|
droidrun/agent/oneflows/app_starter_workflow.py,sha256=MSJ6_jfbiCfSIjnw-qfSDFDuqsUS6rUGLsdKVj43wvY,3525
|
26
26
|
droidrun/agent/oneflows/text_manipulator.py,sha256=mO59DF1uif9poUWy90UehrBmHbNxL9ph4Evtgt1ODbQ,8751
|
@@ -28,34 +28,38 @@ droidrun/agent/utils/__init__.py,sha256=Oro0oyiz1xzRpchWLDA1TZJELJNSwBOb2WdGgknt
|
|
28
28
|
droidrun/agent/utils/async_utils.py,sha256=_JhZ_ZfCkRTfPsufFDhUUds_Vp6z1-TokzUG4H8G7pc,338
|
29
29
|
droidrun/agent/utils/chat_utils.py,sha256=mginY1rbP5t06O3hz2RpJJJNzggaE8VhWjnFid844vw,13797
|
30
30
|
droidrun/agent/utils/device_state_formatter.py,sha256=3MuR3XQulnrsdzmMYfTEegA_XkYTTiETXMRtOtyqoC0,6889
|
31
|
-
droidrun/agent/utils/executer.py,sha256=
|
31
|
+
droidrun/agent/utils/executer.py,sha256=mCq-T9gekgFK9oSHz2H9ctHIyJQFzp9MWQgzuxP0TU0,4191
|
32
32
|
droidrun/agent/utils/inference.py,sha256=dupCtMYXUGuBJz9RqTgSsLYe_MOSB0LEhfHIdtFC8x0,3893
|
33
|
-
droidrun/agent/utils/llm_picker.py,sha256=
|
33
|
+
droidrun/agent/utils/llm_picker.py,sha256=KQzrRcHE38NwujDbNth5F9v5so9HVvHjfkQznMsv-cM,9397
|
34
34
|
droidrun/agent/utils/message_utils.py,sha256=_wngf082gg232y_3pC_yn4fnPhHiyYAxhU4ewT78roo,2309
|
35
|
-
droidrun/agent/utils/tools.py,sha256=
|
35
|
+
droidrun/agent/utils/tools.py,sha256=anc10NAKmZx91JslHFpo6wfnUOZ2pnPXJS-5nMVHC_A,9930
|
36
36
|
droidrun/agent/utils/trajectory.py,sha256=Z6C19Y9hsRxjLZWywqYWTApKU7PelvWM-5Tsl3h7KEw,19718
|
37
|
+
droidrun/app_cards/app_card_provider.py,sha256=wy7CGFnBd_EPU58xNdv4ZWUA9F4Plon71N4-5RT5vNg,827
|
38
|
+
droidrun/app_cards/providers/__init__.py,sha256=vN4TvBtsvfdvzgqbIJegIfHhct0aTFZjvJazWFDvdhg,372
|
39
|
+
droidrun/app_cards/providers/composite_provider.py,sha256=oi7dlkv_Hv2rEZMxQlO1jP9fQcTBydr40zCyunCNxQA,3156
|
40
|
+
droidrun/app_cards/providers/local_provider.py,sha256=RRGQ7VR7qHT9uKSOlSvqCTRq_p4W5HzlWue7B6tcbT0,3904
|
41
|
+
droidrun/app_cards/providers/server_provider.py,sha256=rOJyiCE_zTCCK9SAJeee3vLWISytoZrBUiXB6LaJEv8,4148
|
37
42
|
droidrun/cli/__init__.py,sha256=5cO-QBcUl5w35zO18OENj4OShdglQjn8Ne9aqgSh-PM,167
|
38
|
-
droidrun/cli/logs.py,sha256=
|
39
|
-
droidrun/cli/main.py,sha256=
|
40
|
-
droidrun/config_manager/__init__.py,sha256
|
41
|
-
droidrun/config_manager/
|
42
|
-
droidrun/config_manager/
|
43
|
-
droidrun/config_manager/
|
44
|
-
droidrun/config_manager/prompt_loader.py,sha256=nzlL3YMyteY91fOMryQD3XRny_2oytAmaXRZfLBNH2M,2450
|
43
|
+
droidrun/cli/logs.py,sha256=V8rn6oXgYObExX4dG8MUnQXxUdKOk1QlTkOQtI5e6wo,12686
|
44
|
+
droidrun/cli/main.py,sha256=0-63OyiNlT944eOBqjw3fG8Edove88tqNEFkCKVHb8w,35372
|
45
|
+
droidrun/config_manager/__init__.py,sha256=SeLoEYVU5jMEtXLjx76VE_3rxzZXjCMlVPW7hodU128,460
|
46
|
+
droidrun/config_manager/config_manager.py,sha256=hPETII_5wYvfb11e7sJlfCVk9p3WbA7nHPAV3bQQdmE,19930
|
47
|
+
droidrun/config_manager/path_resolver.py,sha256=vQKT5XmnENtSK3B1D-iItL8CpOQTKzfKZ1wTO4khlTs,3421
|
48
|
+
droidrun/config_manager/prompt_loader.py,sha256=JqGHjT4Ik5iwPfnaXkCc1W1cm4QmIqq2duPuye14jSc,2430
|
45
49
|
droidrun/macro/__init__.py,sha256=TKRNlMJqClV1p1dkfES4eo-Bq1VkSiTC1DDMxMjnUWE,357
|
46
50
|
droidrun/macro/__main__.py,sha256=MWdBvQVhOoeKlC8atDwjVbPSn0-XNt4PDbpCCoeJuUk,193
|
47
|
-
droidrun/macro/cli.py,sha256=
|
51
|
+
droidrun/macro/cli.py,sha256=jQqnnrAnH_KTxuPsYsvIdftPlVcvpb5a5yn5v6A6cCg,9151
|
48
52
|
droidrun/macro/replay.py,sha256=ILhnvN3VYhMK13wkaD5oDwP4wCYTniwcgesUON-9L5o,10721
|
49
53
|
droidrun/telemetry/__init__.py,sha256=2G9PwAuVWsd6qRMKSscssvmL57ILlOK5EV0KezPiF1I,271
|
50
54
|
droidrun/telemetry/events.py,sha256=y-i2d5KiPkikVXrzMQu87osy1LAZTBIx8DlPIWGAXG0,486
|
51
55
|
droidrun/telemetry/phoenix.py,sha256=JHdFdRHXu7cleAb4X4_Y5yn5zPSIApwyKCOxoaj_gf4,7117
|
52
56
|
droidrun/telemetry/tracker.py,sha256=YWOkyLE8XiHainVSB77JE37y-rloOYVYs6j53Aw1J8A,2735
|
53
57
|
droidrun/tools/__init__.py,sha256=BbQFKuPn-5MwGzr-3urMDK8S1ZsP96D96y7WTJYB3AA,271
|
54
|
-
droidrun/tools/adb.py,sha256=
|
58
|
+
droidrun/tools/adb.py,sha256=ziMbQ02TDBvm04ffG1wlYUstsYABNopZaq0aOBh0xtA,42985
|
55
59
|
droidrun/tools/ios.py,sha256=GMYbiNNBeHLwVQAo4_fEZ7snr4JCHE6sG11rcuPvSpk,21831
|
56
60
|
droidrun/tools/tools.py,sha256=0eAZFTaY10eiiUcJM4AkURmTGX-O1RRXjpQ5MHj2Ydo,5241
|
57
|
-
droidrun-0.3.10.
|
58
|
-
droidrun-0.3.10.
|
59
|
-
droidrun-0.3.10.
|
60
|
-
droidrun-0.3.10.
|
61
|
-
droidrun-0.3.10.
|
61
|
+
droidrun-0.3.10.dev7.dist-info/METADATA,sha256=gac2d1ul1MhI-nSmx1ttR3XtWJoIhq6lIyZE4mufMRE,7044
|
62
|
+
droidrun-0.3.10.dev7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
63
|
+
droidrun-0.3.10.dev7.dist-info/entry_points.txt,sha256=o259U66js8TIybQ7zs814Oe_LQ_GpZsp6a9Cr-xm5zE,51
|
64
|
+
droidrun-0.3.10.dev7.dist-info/licenses/LICENSE,sha256=s-uxn9qChu-kFdRXUp6v_0HhsaJ_5OANmfNOFVm2zdk,1069
|
65
|
+
droidrun-0.3.10.dev7.dist-info/RECORD,,
|
@@ -1,148 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
App card loading utility for package-specific prompts.
|
3
|
-
|
4
|
-
Supports flexible file path resolution and caches loaded content.
|
5
|
-
"""
|
6
|
-
|
7
|
-
import json
|
8
|
-
from pathlib import Path
|
9
|
-
from typing import Dict, Optional
|
10
|
-
|
11
|
-
from droidrun.config_manager.path_resolver import PathResolver
|
12
|
-
|
13
|
-
|
14
|
-
class AppCardLoader:
|
15
|
-
"""Load app cards based on package names with content caching."""
|
16
|
-
|
17
|
-
_mapping_cache: Optional[Dict[str, str]] = None
|
18
|
-
_cache_dir: Optional[str] = None
|
19
|
-
_content_cache: Dict[str, str] = {}
|
20
|
-
|
21
|
-
@staticmethod
|
22
|
-
def load_app_card(
|
23
|
-
package_name: str, app_cards_dir: str = "config/app_cards"
|
24
|
-
) -> str:
|
25
|
-
"""
|
26
|
-
Load app card for a package name.
|
27
|
-
|
28
|
-
Path resolution:
|
29
|
-
- Checks working directory first (for user overrides)
|
30
|
-
- Falls back to project directory (for default cards)
|
31
|
-
- Supports absolute paths (used as-is)
|
32
|
-
|
33
|
-
File loading from app_cards.json:
|
34
|
-
1. Relative to app_cards_dir (most common):
|
35
|
-
{"com.google.gm": "gmail.md"}
|
36
|
-
→ {app_cards_dir}/gmail.md
|
37
|
-
|
38
|
-
2. Relative path (checks working dir, then project dir):
|
39
|
-
{"com.google.gm": "config/custom_cards/gmail.md"}
|
40
|
-
|
41
|
-
3. Absolute path:
|
42
|
-
{"com.google.gm": "/usr/share/droidrun/cards/gmail.md"}
|
43
|
-
|
44
|
-
Args:
|
45
|
-
package_name: Android package name (e.g., "com.google.android.gm")
|
46
|
-
app_cards_dir: Directory path (relative or absolute)
|
47
|
-
|
48
|
-
Returns:
|
49
|
-
App card content or empty string if not found
|
50
|
-
"""
|
51
|
-
if not package_name:
|
52
|
-
return ""
|
53
|
-
|
54
|
-
# Check content cache first (key: package_name:app_cards_dir)
|
55
|
-
cache_key = f"{package_name}:{app_cards_dir}"
|
56
|
-
if cache_key in AppCardLoader._content_cache:
|
57
|
-
return AppCardLoader._content_cache[cache_key]
|
58
|
-
|
59
|
-
# Load mapping (with cache)
|
60
|
-
mapping = AppCardLoader._load_mapping(app_cards_dir)
|
61
|
-
|
62
|
-
# Get file path from mapping
|
63
|
-
if package_name not in mapping:
|
64
|
-
# Cache the empty result to avoid repeated lookups
|
65
|
-
AppCardLoader._content_cache[cache_key] = ""
|
66
|
-
return ""
|
67
|
-
|
68
|
-
file_path_str = mapping[package_name]
|
69
|
-
file_path = Path(file_path_str)
|
70
|
-
|
71
|
-
# Determine resolution strategy
|
72
|
-
if file_path.is_absolute():
|
73
|
-
# Absolute path: use as-is
|
74
|
-
app_card_path = file_path
|
75
|
-
elif file_path_str.startswith(("config/", "prompts/", "docs/")):
|
76
|
-
# Project-relative path: resolve with unified resolver
|
77
|
-
app_card_path = PathResolver.resolve(file_path_str)
|
78
|
-
else:
|
79
|
-
# App_cards-relative: resolve dir first, then append filename
|
80
|
-
cards_dir_resolved = PathResolver.resolve(app_cards_dir)
|
81
|
-
app_card_path = cards_dir_resolved / file_path_str
|
82
|
-
|
83
|
-
# Read file
|
84
|
-
try:
|
85
|
-
if not app_card_path.exists():
|
86
|
-
# Cache the empty result
|
87
|
-
AppCardLoader._content_cache[cache_key] = ""
|
88
|
-
return ""
|
89
|
-
|
90
|
-
content = app_card_path.read_text(encoding="utf-8")
|
91
|
-
# Cache the content
|
92
|
-
AppCardLoader._content_cache[cache_key] = content
|
93
|
-
return content
|
94
|
-
except Exception:
|
95
|
-
# Cache the empty result on error
|
96
|
-
AppCardLoader._content_cache[cache_key] = ""
|
97
|
-
return ""
|
98
|
-
|
99
|
-
@staticmethod
|
100
|
-
def _load_mapping(app_cards_dir: str) -> Dict[str, str]:
|
101
|
-
"""Load and cache the app_cards.json mapping."""
|
102
|
-
# Cache invalidation: if dir changed, reload
|
103
|
-
if (
|
104
|
-
AppCardLoader._mapping_cache is not None
|
105
|
-
and AppCardLoader._cache_dir == app_cards_dir
|
106
|
-
):
|
107
|
-
return AppCardLoader._mapping_cache
|
108
|
-
|
109
|
-
# Resolve app cards directory
|
110
|
-
cards_dir_resolved = PathResolver.resolve(app_cards_dir)
|
111
|
-
mapping_path = cards_dir_resolved / "app_cards.json"
|
112
|
-
|
113
|
-
try:
|
114
|
-
if not mapping_path.exists():
|
115
|
-
AppCardLoader._mapping_cache = {}
|
116
|
-
AppCardLoader._cache_dir = app_cards_dir
|
117
|
-
return {}
|
118
|
-
|
119
|
-
with open(mapping_path, "r", encoding="utf-8") as f:
|
120
|
-
mapping = json.load(f)
|
121
|
-
|
122
|
-
AppCardLoader._mapping_cache = mapping
|
123
|
-
AppCardLoader._cache_dir = app_cards_dir
|
124
|
-
return mapping
|
125
|
-
except Exception:
|
126
|
-
AppCardLoader._mapping_cache = {}
|
127
|
-
AppCardLoader._cache_dir = app_cards_dir
|
128
|
-
return {}
|
129
|
-
|
130
|
-
@staticmethod
|
131
|
-
def clear_cache() -> None:
|
132
|
-
"""Clear all caches (useful for testing or runtime reloading)."""
|
133
|
-
AppCardLoader._mapping_cache = None
|
134
|
-
AppCardLoader._cache_dir = None
|
135
|
-
AppCardLoader._content_cache.clear()
|
136
|
-
|
137
|
-
@staticmethod
|
138
|
-
def get_cache_stats() -> Dict[str, int]:
|
139
|
-
"""
|
140
|
-
Get cache statistics.
|
141
|
-
|
142
|
-
Returns:
|
143
|
-
Dict with cache stats (useful for debugging)
|
144
|
-
"""
|
145
|
-
return {
|
146
|
-
"mapping_cached": 1 if AppCardLoader._mapping_cache is not None else 0,
|
147
|
-
"content_entries": len(AppCardLoader._content_cache),
|
148
|
-
}
|
File without changes
|
File without changes
|
File without changes
|