droidrun 0.3.9__tar.gz → 0.3.10.dev2__tar.gz

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.
Files changed (122) hide show
  1. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/.github/workflows/publish.yml +18 -22
  2. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/PKG-INFO +6 -3
  3. droidrun-0.3.10.dev2/config.yaml +91 -0
  4. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/__init__.py +2 -3
  5. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/__main__.py +1 -1
  6. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/__init__.py +1 -1
  7. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/codeact/__init__.py +1 -4
  8. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/codeact/codeact_agent.py +66 -40
  9. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/codeact/events.py +6 -3
  10. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/codeact/prompts.py +2 -2
  11. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/common/events.py +4 -2
  12. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/__init__.py +1 -3
  13. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/agent_persona.py +2 -1
  14. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/context_injection_manager.py +6 -6
  15. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/episodic_memory.py +5 -3
  16. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/personas/__init__.py +3 -3
  17. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/personas/app_starter.py +3 -3
  18. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/personas/big_agent.py +3 -3
  19. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/personas/default.py +3 -3
  20. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/personas/ui_expert.py +5 -5
  21. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/context/task_manager.py +15 -17
  22. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/droid/__init__.py +1 -1
  23. droidrun-0.3.10.dev2/droidrun/agent/droid/droid_agent.py +637 -0
  24. droidrun-0.3.10.dev2/droidrun/agent/droid/events.py +115 -0
  25. droidrun-0.3.10.dev2/droidrun/agent/executor/__init__.py +13 -0
  26. droidrun-0.3.10.dev2/droidrun/agent/executor/events.py +24 -0
  27. droidrun-0.3.10.dev2/droidrun/agent/executor/executor_agent.py +327 -0
  28. droidrun-0.3.10.dev2/droidrun/agent/executor/prompts.py +136 -0
  29. droidrun-0.3.10.dev2/droidrun/agent/manager/__init__.py +18 -0
  30. droidrun-0.3.10.dev2/droidrun/agent/manager/events.py +20 -0
  31. droidrun-0.3.10.dev2/droidrun/agent/manager/manager_agent.py +459 -0
  32. droidrun-0.3.10.dev2/droidrun/agent/manager/prompts.py +223 -0
  33. droidrun-0.3.10.dev2/droidrun/agent/oneflows/app_starter_workflow.py +118 -0
  34. droidrun-0.3.10.dev2/droidrun/agent/oneflows/text_manipulator.py +204 -0
  35. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/planner/__init__.py +3 -3
  36. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/planner/events.py +6 -3
  37. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/planner/planner_agent.py +27 -42
  38. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/planner/prompts.py +2 -2
  39. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/usage.py +11 -11
  40. droidrun-0.3.10.dev2/droidrun/agent/utils/__init__.py +13 -0
  41. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/utils/async_utils.py +2 -1
  42. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/utils/chat_utils.py +48 -60
  43. droidrun-0.3.10.dev2/droidrun/agent/utils/device_state_formatter.py +177 -0
  44. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/utils/executer.py +12 -11
  45. droidrun-0.3.10.dev2/droidrun/agent/utils/inference.py +114 -0
  46. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/utils/llm_picker.py +2 -0
  47. droidrun-0.3.10.dev2/droidrun/agent/utils/message_utils.py +85 -0
  48. droidrun-0.3.10.dev2/droidrun/agent/utils/tools.py +220 -0
  49. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/utils/trajectory.py +8 -7
  50. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/cli/__init__.py +1 -1
  51. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/cli/logs.py +29 -28
  52. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/cli/main.py +279 -143
  53. droidrun-0.3.10.dev2/droidrun/config_manager/__init__.py +25 -0
  54. droidrun-0.3.10.dev2/droidrun/config_manager/config_manager.py +583 -0
  55. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/macro/__init__.py +2 -2
  56. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/macro/__main__.py +1 -1
  57. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/macro/cli.py +36 -34
  58. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/macro/replay.py +7 -9
  59. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/portal.py +1 -1
  60. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/telemetry/__init__.py +2 -2
  61. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/telemetry/events.py +3 -4
  62. droidrun-0.3.10.dev2/droidrun/telemetry/phoenix.py +173 -0
  63. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/telemetry/tracker.py +7 -5
  64. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/tools/adb.py +210 -82
  65. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/tools/ios.py +7 -5
  66. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/tools/tools.py +25 -8
  67. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/pyproject.toml +10 -4
  68. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/setup.py +1 -1
  69. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/uv.lock +26 -710
  70. droidrun-0.3.9/droidrun/agent/common/default.py +0 -5
  71. droidrun-0.3.9/droidrun/agent/context/reflection.py +0 -20
  72. droidrun-0.3.9/droidrun/agent/droid/droid_agent.py +0 -490
  73. droidrun-0.3.9/droidrun/agent/droid/events.py +0 -33
  74. droidrun-0.3.9/droidrun/agent/oneflows/reflector.py +0 -265
  75. droidrun-0.3.9/droidrun/agent/utils/__init__.py +0 -3
  76. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/.github/workflows/bounty.yml +0 -0
  77. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/.gitignore +0 -0
  78. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/.python-version +0 -0
  79. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/CHANGELOG.md +0 -0
  80. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/CONTRIBUTING.md +0 -0
  81. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/LICENSE +0 -0
  82. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/MANIFEST.in +0 -0
  83. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/README.md +0 -0
  84. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/.generated-files.txt +0 -0
  85. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/docs.json +0 -0
  86. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/favicon.png +0 -0
  87. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/logo/dark.svg +0 -0
  88. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/logo/light.svg +0 -0
  89. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v1/concepts/agent.mdx +0 -0
  90. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v1/concepts/android-control.mdx +0 -0
  91. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v1/concepts/portal-app.mdx +0 -0
  92. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v1/overview.mdx +0 -0
  93. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v1/quickstart.mdx +0 -0
  94. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/concepts/agent.mdx +0 -0
  95. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/concepts/android-control.mdx +0 -0
  96. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/concepts/planning.mdx +0 -0
  97. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/concepts/portal-app.mdx +0 -0
  98. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/concepts/tracing.mdx +0 -0
  99. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/overview.mdx +0 -0
  100. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v2/quickstart.mdx +0 -0
  101. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/concepts/agent.mdx +0 -0
  102. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/concepts/android-tools.mdx +0 -0
  103. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/concepts/models.mdx +0 -0
  104. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/concepts/portal-app.mdx +0 -0
  105. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/cli.mdx +0 -0
  106. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/gemini.mdx +0 -0
  107. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/ollama.mdx +0 -0
  108. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/openailike.mdx +0 -0
  109. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/overview.mdx +0 -0
  110. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/guides/telemetry.mdx +0 -0
  111. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/images/portal_apk.png +0 -0
  112. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/overview.mdx +0 -0
  113. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/quickstart.mdx +0 -0
  114. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/sdk/adb-tools.mdx +0 -0
  115. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/sdk/base-tools.mdx +0 -0
  116. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/sdk/droid-agent.mdx +0 -0
  117. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/docs/v3/sdk/ios-tools.mdx +0 -0
  118. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/agent/common/constants.py +0 -0
  119. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/droidrun/tools/__init__.py +1 -1
  120. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/gen-docs-sdk-ref.sh +0 -0
  121. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/static/droidrun-dark.png +0 -0
  122. {droidrun-0.3.9 → droidrun-0.3.10.dev2}/static/droidrun.png +0 -0
@@ -1,12 +1,10 @@
1
1
  name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
2
-
3
2
  on: push
4
3
 
5
4
  jobs:
6
5
  build:
7
6
  name: Build distribution 📦
8
7
  runs-on: ubuntu-latest
9
-
10
8
  steps:
11
9
  - uses: actions/checkout@v4
12
10
  with:
@@ -29,49 +27,47 @@ jobs:
29
27
  name: python-package-distributions
30
28
  path: dist/
31
29
 
32
- publish-to-pypi:
33
- name: >-
34
- Publish Python 🐍 distribution 📦 to PyPI
35
- if: startsWith(github.ref, 'refs/tags/')
30
+ publish-to-testpypi:
31
+ name: Publish Python 🐍 distribution 📦 to TestPyPI
32
+ # Only runs on dev branch
33
+ if: github.ref == 'refs/heads/dev'
36
34
  needs:
37
35
  - build
38
36
  runs-on: ubuntu-latest
39
37
  environment:
40
- name: pypi
41
- url: https://pypi.org/p/droidrun
38
+ name: testpypi
39
+ url: https://test.pypi.org/p/droidrun
42
40
  permissions:
43
41
  id-token: write
44
-
45
42
  steps:
46
43
  - name: Download all the dists
47
44
  uses: actions/download-artifact@v4
48
45
  with:
49
46
  name: python-package-distributions
50
47
  path: dist/
51
- - name: Publish distribution 📦 to PyPI
48
+ - name: Publish distribution 📦 to TestPyPI
52
49
  uses: pypa/gh-action-pypi-publish@release/v1
50
+ with:
51
+ repository-url: https://test.pypi.org/legacy/
53
52
 
54
- publish-to-testpypi:
55
- name: Publish Python 🐍 distribution 📦 to TestPyPI
56
- if: startsWith(github.ref, 'refs/tags/')
53
+ publish-to-pypi:
54
+ name: >-
55
+ Publish Python 🐍 distribution 📦 to PyPI
56
+ # Only runs on production tags (v*)
57
+ if: startsWith(github.ref, 'refs/tags/v')
57
58
  needs:
58
59
  - build
59
60
  runs-on: ubuntu-latest
60
-
61
61
  environment:
62
- name: testpypi
63
- url: https://test.pypi.org/p/droidrun
64
-
62
+ name: pypi
63
+ url: https://pypi.org/p/droidrun
65
64
  permissions:
66
65
  id-token: write
67
-
68
66
  steps:
69
67
  - name: Download all the dists
70
68
  uses: actions/download-artifact@v4
71
69
  with:
72
70
  name: python-package-distributions
73
71
  path: dist/
74
- - name: Publish distribution 📦 to TestPyPI
75
- uses: pypa/gh-action-pypi-publish@release/v1
76
- with:
77
- repository-url: https://test.pypi.org/legacy/
72
+ - name: Publish distribution 📦 to PyPI
73
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: droidrun
3
- Version: 0.3.9
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
@@ -27,10 +27,9 @@ Classifier: Topic :: Software Development :: Testing
27
27
  Classifier: Topic :: Software Development :: Testing :: Acceptance
28
28
  Classifier: Topic :: System :: Emulators
29
29
  Classifier: Topic :: Utilities
30
- Requires-Python: >=3.11
30
+ Requires-Python: >=3.13
31
31
  Requires-Dist: adbutils>=2.10.2
32
32
  Requires-Dist: apkutils==2.0.0
33
- Requires-Dist: llama-index-llms-google-genai>=0.6.2
34
33
  Requires-Dist: llama-index==0.14.4
35
34
  Requires-Dist: posthog>=6.7.6
36
35
  Requires-Dist: pydantic>=2.11.10
@@ -54,6 +53,10 @@ Provides-Extra: openai
54
53
  Requires-Dist: llama-index-llms-openai-like>=0.5.1; extra == 'openai'
55
54
  Requires-Dist: llama-index-llms-openai>=0.5.6; extra == 'openai'
56
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'
57
60
  Description-Content-Type: text/markdown
58
61
 
59
62
  <picture>
@@ -0,0 +1,91 @@
1
+ # DroidRun Configuration File
2
+ # This file is auto-generated. Edit values as needed.
3
+
4
+ # === Agent Settings ===
5
+ agent:
6
+ # Maximum number of steps per task
7
+ max_steps: 15
8
+ # Enable vision capabilities per agent (screenshots)
9
+ vision:
10
+ manager: true
11
+ executor: true
12
+ codeact: true
13
+ # Enable planning with reasoning mode
14
+ reasoning: true
15
+ # Sleep duration after each action, waits for ui state to be updated (seconds)
16
+ after_sleep_action: 1.0
17
+
18
+
19
+ wait_for_stable_ui: 0.3 # TODO: doesn't do anything now
20
+
21
+ # === LLM Profiles ===
22
+ # Define LLM configurations for each agent type
23
+ llm_profiles:
24
+ # Manager: Plans and reasons about task progress
25
+ manager:
26
+ provider: GoogleGenAI
27
+ model: models/gemini-2.5-pro
28
+ temperature: 0.2
29
+ # kwargs: # optional kwargs, add api_key in kwargs if not already in .env
30
+ # max_tokens: 8192
31
+
32
+ # Executor: Selects and executes atomic actions
33
+ executor:
34
+ provider: GoogleGenAI
35
+ model: models/gemini-2.5-pro
36
+ temperature: 0.1
37
+ # kwargs:
38
+ # max_tokens: 4096
39
+
40
+ # CodeAct: Generates and executes code actions
41
+ codeact:
42
+ provider: GoogleGenAI
43
+ model: models/gemini-2.5-pro
44
+ temperature: 0.2
45
+ # kwargs:
46
+ # max_tokens: 8192
47
+
48
+ # Text Manipulator: Edits text in input fields
49
+ text_manipulator:
50
+ provider: GoogleGenAI
51
+ model: models/gemini-2.5-flash
52
+ temperature: 0.3
53
+ # kwargs:
54
+ # max_tokens: 4096
55
+
56
+ # App Opener: Opens apps by name/description
57
+ app_opener:
58
+ provider: GoogleGenAI
59
+ model: models/gemini-2.5-flash
60
+ temperature: 0.0
61
+ # kwargs:
62
+ # max_tokens: 512
63
+
64
+ # === Device Settings ===
65
+ device:
66
+ # Default device serial (null = auto-detect)
67
+ serial: null
68
+ # Use TCP communication instead of usb
69
+ use_tcp: false
70
+
71
+ # === Telemetry Settings ===
72
+ telemetry:
73
+ # Enable anonymous telemetry
74
+ enabled: false
75
+
76
+ # === Tracing Settings ===
77
+ tracing:
78
+ # Enable Arize Phoenix tracing
79
+ enabled: false
80
+
81
+ # === Logging Settings ===
82
+ logging:
83
+ # Enable debug logging
84
+ debug: true
85
+ # Trajectory saving level (none, step, action)
86
+ save_trajectory: none
87
+
88
+ # === Tool Settings ===
89
+ tools:
90
+ # Enable drag tool
91
+ allow_drag: false # this does nothing now place holder for now
@@ -5,13 +5,12 @@ DroidRun - A framework for controlling Android devices through LLM agents.
5
5
  __version__ = "0.3.0"
6
6
 
7
7
  # Import main classes for easier access
8
- from droidrun.agent.utils.llm_picker import load_llm
9
- from droidrun.tools import Tools, AdbTools, IOSTools
10
8
  from droidrun.agent.droid import DroidAgent
9
+ from droidrun.agent.utils.llm_picker import load_llm
11
10
 
12
11
  # Import macro functionality
13
12
  from droidrun.macro import MacroPlayer, replay_macro_file, replay_macro_folder
14
-
13
+ from droidrun.tools import AdbTools, IOSTools, Tools
15
14
 
16
15
  # Make main components available at package level
17
16
  __all__ = [
@@ -4,4 +4,4 @@ DroidRun main entry point
4
4
  from droidrun.cli.main import cli
5
5
 
6
6
  if __name__ == '__main__':
7
- cli()
7
+ cli()
@@ -3,4 +3,4 @@
3
3
  #logger = logging.getLogger("droidrun")
4
4
  #logger.propagate = False # Don't send to root logger
5
5
  #logger.handlers = [] # No handlers by default
6
- #logger.setLevel(logging.INFO) # Or WARNING
6
+ #logger.setLevel(logging.INFO) # Or WARNING
@@ -1,8 +1,5 @@
1
1
  from droidrun.agent.codeact.codeact_agent import CodeActAgent
2
- from droidrun.agent.codeact.prompts import (
3
- DEFAULT_CODE_ACT_USER_PROMPT,
4
- DEFAULT_NO_THOUGHTS_PROMPT
5
- )
2
+ from droidrun.agent.codeact.prompts import DEFAULT_CODE_ACT_USER_PROMPT, DEFAULT_NO_THOUGHTS_PROMPT
6
3
 
7
4
  __all__ = [
8
5
  "CodeActAgent",
@@ -1,37 +1,37 @@
1
+ import asyncio
2
+ import json
1
3
  import logging
2
4
  import re
3
5
  import time
4
- import asyncio
5
- import json
6
- import os
7
- from typing import List, Optional, Tuple, Union
6
+ from typing import List, Union
7
+
8
8
  from llama_index.core.base.llms.types import ChatMessage, ChatResponse
9
- from llama_index.core.prompts import PromptTemplate
10
9
  from llama_index.core.llms.llm import LLM
11
- from llama_index.core.workflow import Workflow, StartEvent, StopEvent, Context, step
12
10
  from llama_index.core.memory import Memory
11
+ from llama_index.core.prompts import PromptTemplate
12
+ from llama_index.core.workflow import Context, StartEvent, StopEvent, Workflow, step
13
+
13
14
  from droidrun.agent.codeact.events import (
14
- TaskInputEvent,
15
+ EpisodicMemoryEvent,
15
16
  TaskEndEvent,
16
17
  TaskExecutionEvent,
17
18
  TaskExecutionResultEvent,
19
+ TaskInputEvent,
18
20
  TaskThinkingEvent,
19
- EpisodicMemoryEvent,
20
21
  )
21
- from droidrun.agent.common.constants import LLM_HISTORY_LIMIT
22
- from droidrun.agent.common.events import RecordUIStateEvent, ScreenshotEvent
23
- from droidrun.agent.usage import get_usage_from_response
24
- from droidrun.agent.utils import chat_utils
25
- from droidrun.agent.utils.executer import SimpleCodeExecutor
26
22
  from droidrun.agent.codeact.prompts import (
27
23
  DEFAULT_CODE_ACT_USER_PROMPT,
28
24
  DEFAULT_NO_THOUGHTS_PROMPT,
29
25
  )
30
-
26
+ from droidrun.agent.common.constants import LLM_HISTORY_LIMIT
27
+ from droidrun.agent.common.events import RecordUIStateEvent, ScreenshotEvent
28
+ from droidrun.agent.context.agent_persona import AgentPersona
31
29
  from droidrun.agent.context.episodic_memory import EpisodicMemory, EpisodicMemoryStep
30
+ from droidrun.agent.usage import get_usage_from_response
31
+ from droidrun.agent.utils import chat_utils
32
+ from droidrun.agent.utils.executer import SimpleCodeExecutor
33
+ from droidrun.agent.utils.tools import ATOMIC_ACTION_SIGNATURES, get_atomic_tool_descriptions, build_custom_tool_descriptions
32
34
  from droidrun.tools import Tools
33
- from typing import Optional, Dict, Tuple, List, Any, Callable
34
- from droidrun.agent.context.agent_persona import AgentPersona
35
35
 
36
36
  logger = logging.getLogger("droidrun")
37
37
 
@@ -49,8 +49,8 @@ class CodeActAgent(Workflow):
49
49
  persona: AgentPersona,
50
50
  vision: bool,
51
51
  tools_instance: "Tools",
52
- all_tools_list: Dict[str, Callable[..., Any]],
53
52
  max_steps: int = 5,
53
+ custom_tools: dict = None,
54
54
  debug: bool = False,
55
55
  *args,
56
56
  **kwargs,
@@ -78,13 +78,40 @@ class CodeActAgent(Workflow):
78
78
 
79
79
  self.tools = tools_instance
80
80
 
81
+ # Merge custom_tools with ATOMIC_ACTION_SIGNATURES
82
+ # Custom tools are treated the same as atomic actions by CodeAct
83
+ merged_signatures = {**ATOMIC_ACTION_SIGNATURES, **(custom_tools or {})}
84
+
85
+ # Build tool_list from merged signatures
81
86
  self.tool_list = {}
87
+ for action_name, signature in merged_signatures.items():
88
+ func = signature["function"]
89
+ # Create bound function (curry tools_instance as first argument)
90
+ # Handle both sync and async functions
91
+ if asyncio.iscoroutinefunction(func):
92
+ async def make_async_bound(f, ti):
93
+ async def bound_func(*args, **kwargs):
94
+ return await f(ti, *args, **kwargs)
95
+ return bound_func
96
+ self.tool_list[action_name] = asyncio.run(make_async_bound(func, tools_instance))
97
+ else:
98
+ self.tool_list[action_name] = lambda *args, f=func, ti=tools_instance: f(ti, *args)
99
+
100
+ # Add non-atomic tools (remember, complete) from tools_instance
101
+ self.tool_list["remember"] = tools_instance.remember
102
+ self.tool_list["complete"] = tools_instance.complete
82
103
 
83
- for tool_name in persona.allowed_tools:
84
- if tool_name in all_tools_list:
85
- self.tool_list[tool_name] = all_tools_list[tool_name]
104
+ # Get tool descriptions from ATOMIC_ACTION_SIGNATURES and custom_tools
105
+ self.tool_descriptions = get_atomic_tool_descriptions()
86
106
 
87
- self.tool_descriptions = chat_utils.parse_tool_descriptions(self.tool_list)
107
+ # Add custom tool descriptions if provided
108
+ custom_descriptions = build_custom_tool_descriptions(custom_tools or {})
109
+ if custom_descriptions:
110
+ self.tool_descriptions += "\n" + custom_descriptions
111
+
112
+ # Add descriptions for remember/complete
113
+ self.tool_descriptions += "\n- remember(information: str): Remember information for later use"
114
+ self.tool_descriptions += "\n- complete(success: bool, reason: str): Mark task as complete"
88
115
 
89
116
  self.system_prompt_content = persona.system_prompt.format(
90
117
  tool_descriptions=self.tool_descriptions
@@ -162,7 +189,7 @@ class CodeActAgent(Workflow):
162
189
  logger.info(f"🧠 Step {self.steps_counter}: Thinking...")
163
190
 
164
191
  model = self.llm.class_name()
165
-
192
+
166
193
  if "remember" in self.tool_list and self.remembered_info:
167
194
  await ctx.store.set("remembered_info", self.remembered_info)
168
195
  chat_history = await chat_utils.add_memory_block(self.remembered_info, chat_history)
@@ -178,7 +205,7 @@ class CodeActAgent(Workflow):
178
205
  logger.warning(
179
206
  "[yellow]DeepSeek doesnt support images. Disabling screenshots[/]"
180
207
  )
181
- elif self.vision == True: # if vision is enabled, add screenshot to chat history
208
+ elif self.vision: # if vision is enabled, add screenshot to chat history
182
209
  chat_history = await chat_utils.add_screenshot_image_block(screenshot, chat_history)
183
210
 
184
211
  if context == "ui_state":
@@ -190,8 +217,8 @@ class CodeActAgent(Workflow):
190
217
  state["a11y_tree"], chat_history
191
218
  )
192
219
  chat_history = await chat_utils.add_phone_state_block(state["phone_state"], chat_history)
193
- except Exception as e:
194
- logger.warning(f"⚠️ Error retrieving state from the connected device. Is the Accessibility Service enabled?")
220
+ except Exception:
221
+ logger.warning("⚠️ Error retrieving state from the connected device. Is the Accessibility Service enabled?")
195
222
 
196
223
 
197
224
  if context == "packages":
@@ -254,7 +281,7 @@ class CodeActAgent(Workflow):
254
281
  """Execute the code and return the result."""
255
282
  code = ev.code
256
283
  assert code, "Code cannot be empty."
257
- logger.info(f"⚡ Executing action...")
284
+ logger.info("⚡ Executing action...")
258
285
  logger.info(f"Code to execute:\n```python\n{code}\n```")
259
286
 
260
287
  try:
@@ -269,16 +296,16 @@ class CodeActAgent(Workflow):
269
296
  for ui_state in ui_states[:-1]:
270
297
  ctx.write_event_to_stream(RecordUIStateEvent(ui_state=ui_state['a11y_tree']))
271
298
 
272
- if self.tools.finished == True:
299
+ if self.tools.finished:
273
300
  logger.debug(" - Task completed.")
274
301
  event = TaskEndEvent(
275
302
  success=self.tools.success, reason=self.tools.reason
276
303
  )
277
304
  ctx.write_event_to_stream(event)
278
305
  return event
279
-
306
+
280
307
  self.remembered_info = self.tools.memory
281
-
308
+
282
309
  event = TaskExecutionResultEvent(output=str(result['output']))
283
310
  ctx.write_event_to_stream(event)
284
311
  return event
@@ -323,11 +350,11 @@ class CodeActAgent(Workflow):
323
350
  """Finalize the workflow."""
324
351
  self.tools.finished = False
325
352
  await ctx.store.set("chat_memory", self.chat_memory)
326
-
353
+
327
354
  # Add final state observation to episodic memory
328
355
  if self.vision:
329
356
  await self._add_final_state_observation(ctx)
330
-
357
+
331
358
  result = {}
332
359
  result.update(
333
360
  {
@@ -403,7 +430,7 @@ class CodeActAgent(Workflow):
403
430
  logger.error(f"Rate limit error. Retrying in {seconds} seconds...")
404
431
  time.sleep(seconds)
405
432
  else:
406
- logger.error(f"Rate limit error. Retrying in 5 seconds...")
433
+ logger.error("Rate limit error. Retrying in 5 seconds...")
407
434
  time.sleep(40)
408
435
  logger.debug("🔍 Retrying call to LLM...")
409
436
  response = await self.llm.achat(messages=messages_to_send)
@@ -452,26 +479,25 @@ class CodeActAgent(Workflow):
452
479
  try:
453
480
  # Get current screenshot and UI state
454
481
  screenshot = None
455
- ui_state = None
456
-
482
+
457
483
  try:
458
484
  _, screenshot_bytes = self.tools.take_screenshot()
459
485
  screenshot = screenshot_bytes
460
486
  except Exception as e:
461
487
  logger.warning(f"Failed to capture final screenshot: {e}")
462
-
488
+
463
489
  try:
464
490
  (a11y_tree, phone_state) = self.tools.get_state()
465
491
  except Exception as e:
466
492
  logger.warning(f"Failed to capture final UI state: {e}")
467
-
493
+
468
494
  # Create final observation chat history and response
469
495
  final_chat_history = [{"role": "system", "content": "Final state observation after task completion"}]
470
496
  final_response = {
471
- "role": "user",
497
+ "role": "user",
472
498
  "content": f"Final State Observation:\nUI State: {a11y_tree}\nScreenshot: {'Available' if screenshot else 'Not available'}"
473
499
  }
474
-
500
+
475
501
  # Create final episodic memory step
476
502
  final_step = EpisodicMemoryStep(
477
503
  chat_history=json.dumps(final_chat_history),
@@ -479,9 +505,9 @@ class CodeActAgent(Workflow):
479
505
  timestamp=time.time(),
480
506
  screenshot=screenshot
481
507
  )
482
-
508
+
483
509
  self.episodic_memory.steps.append(final_step)
484
510
  logger.info("Added final state observation to episodic memory")
485
-
511
+
486
512
  except Exception as e:
487
513
  logger.error(f"Failed to add final state observation: {e}")
@@ -1,10 +1,13 @@
1
+ from typing import Optional
2
+
1
3
  from llama_index.core.llms import ChatMessage
2
4
  from llama_index.core.workflow import Event
3
- from typing import Optional
4
5
 
5
6
  from droidrun.agent.usage import UsageResult
7
+
6
8
  from ..context.episodic_memory import EpisodicMemory
7
9
 
10
+
8
11
  class TaskInputEvent(Event):
9
12
  input: list[ChatMessage]
10
13
 
@@ -12,7 +15,7 @@ class TaskInputEvent(Event):
12
15
 
13
16
  class TaskThinkingEvent(Event):
14
17
  thoughts: Optional[str] = None
15
- code: Optional[str] = None
18
+ code: Optional[str] = None
16
19
  usage: Optional[UsageResult] = None
17
20
 
18
21
  class TaskExecutionEvent(Event):
@@ -28,4 +31,4 @@ class TaskEndEvent(Event):
28
31
  reason: str
29
32
 
30
33
  class EpisodicMemoryEvent(Event):
31
- episodic_memory: EpisodicMemory
34
+ episodic_memory: EpisodicMemory
@@ -21,6 +21,6 @@ Now, describe the next step you will take to address the original goal: {goal}""
21
21
 
22
22
  # Export all prompts
23
23
  __all__ = [
24
- "DEFAULT_CODE_ACT_USER_PROMPT",
24
+ "DEFAULT_CODE_ACT_USER_PROMPT",
25
25
  "DEFAULT_NO_THOUGHTS_PROMPT"
26
- ]
26
+ ]
@@ -1,5 +1,7 @@
1
+ from typing import Any, Dict
2
+
1
3
  from llama_index.core.workflow import Event
2
- from typing import Dict, Any
4
+
3
5
 
4
6
  class ScreenshotEvent(Event):
5
7
  screenshot: bytes
@@ -16,7 +18,7 @@ class TapActionEvent(MacroEvent):
16
18
  element_index: int = None
17
19
  element_text: str = ""
18
20
  element_bounds: str = ""
19
-
21
+
20
22
  class SwipeActionEvent(MacroEvent):
21
23
  """Event for swipe actions with coordinates"""
22
24
  start_x: int
@@ -9,15 +9,13 @@ This module contains:
9
9
  from .agent_persona import AgentPersona
10
10
  from .context_injection_manager import ContextInjectionManager
11
11
  from .episodic_memory import EpisodicMemory, EpisodicMemoryStep
12
- from .reflection import Reflection
13
- from .task_manager import TaskManager, Task
12
+ from .task_manager import Task, TaskManager
14
13
 
15
14
  __all__ = [
16
15
  "AgentPersona",
17
16
  "ContextInjectionManager",
18
17
  "EpisodicMemory",
19
18
  "EpisodicMemoryStep",
20
- "Reflection",
21
19
  "TaskManager",
22
20
  "Task"
23
21
  ]
@@ -1,5 +1,6 @@
1
- from typing import Dict, List, Callable, Any, Optional
2
1
  from dataclasses import dataclass
2
+ from typing import List
3
+
3
4
 
4
5
  @dataclass
5
6
  class AgentPersona:
@@ -5,12 +5,12 @@ This module provides the ContextInjectionManager class that manages different ag
5
5
  each with specific system prompts, contexts, and tool subsets tailored for specialized tasks.
6
6
  """
7
7
 
8
- import logging
9
- from typing import Optional, List
10
- from droidrun.agent.context.agent_persona import AgentPersona
11
8
  #import chromadb
12
9
  import json
13
- from pathlib import Path
10
+ import logging
11
+ from typing import List, Optional
12
+
13
+ from droidrun.agent.context.agent_persona import AgentPersona
14
14
 
15
15
  logger = logging.getLogger("droidrun")
16
16
 
@@ -59,8 +59,8 @@ class ContextInjectionManager:
59
59
  Returns:
60
60
  AgentPersona instance or None if not found
61
61
  """
62
-
62
+
63
63
  return self.personas.get(agent_type)
64
-
64
+
65
65
  def get_all_personas(self) -> List[str]:
66
66
  return self.personas
@@ -1,7 +1,9 @@
1
1
  from dataclasses import dataclass, field
2
- from droidrun.agent.context.agent_persona import AgentPersona
3
2
  from typing import List, Optional
4
3
 
4
+ from droidrun.agent.context.agent_persona import AgentPersona
5
+
6
+
5
7
  @dataclass
6
8
  class EpisodicMemoryStep:
7
9
  chat_history: str
@@ -9,7 +11,7 @@ class EpisodicMemoryStep:
9
11
  timestamp: float
10
12
  screenshot: Optional[bytes]
11
13
 
12
- @dataclass
14
+ @dataclass
13
15
  class EpisodicMemory:
14
16
  persona: AgentPersona
15
- steps: List[EpisodicMemoryStep] = field(default_factory=list)
17
+ steps: List[EpisodicMemoryStep] = field(default_factory=list)
@@ -1,11 +1,11 @@
1
- from .default import DEFAULT
2
- from .ui_expert import UI_EXPERT
3
1
  from .app_starter import APP_STARTER_EXPERT
4
2
  from .big_agent import BIG_AGENT
3
+ from .default import DEFAULT
4
+ from .ui_expert import UI_EXPERT
5
5
 
6
6
  __all__ = [
7
7
  'DEFAULT',
8
8
  'UI_EXPERT',
9
9
  'APP_STARTER_EXPERT',
10
10
  'BIG_AGENT',
11
- ]
11
+ ]
@@ -2,7 +2,7 @@ from droidrun.agent.context.agent_persona import AgentPersona
2
2
  from droidrun.tools import Tools
3
3
 
4
4
  APP_STARTER_EXPERT = AgentPersona(
5
- name="AppStarterExpert",
5
+ name="AppStarterExpert",
6
6
  description="Specialized in app launching",
7
7
  expertise_areas=[
8
8
  "app launching"
@@ -37,8 +37,8 @@ APP_STARTER_EXPERT = AgentPersona(
37
37
  In addition to the Python Standard Library and any functions you have already written, you can use the following functions:
38
38
  {tool_descriptions}
39
39
 
40
- Reminder: Always place your Python code between ```...``` tags when you want to run code.
40
+ Reminder: Always place your Python code between ```...``` tags when you want to run code.
41
41
 
42
42
  You focus ONLY on app launching and package management - UI interactions within apps are handled by UI specialists.""",
43
43
 
44
- )
44
+ )
@@ -5,7 +5,7 @@ BIG_AGENT = AgentPersona(
5
5
  name="Big Agent",
6
6
  description="Big Agent. Use this as your Big Agent",
7
7
  expertise_areas=[
8
- "UI navigation", "button interactions", "text input",
8
+ "UI navigation", "button interactions", "text input",
9
9
  "menu navigation", "form filling", "scrolling", "app launching"
10
10
  ],
11
11
  allowed_tools=[
@@ -90,7 +90,7 @@ BIG_AGENT = AgentPersona(
90
90
  - Present the results clearly and concisely as if you computed them directly
91
91
  - Structure your response like you're directly answering the user's query, not explaining how you solved it
92
92
 
93
- Reminder: Always place your Python code between ```...``` tags when you want to run code.
93
+ Reminder: Always place your Python code between ```...``` tags when you want to run code.
94
94
  """
95
95
 
96
- )
96
+ )