droidrun 0.4.0.dev5__tar.gz → 0.4.0.dev7__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 (158) hide show
  1. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/.gitignore +3 -1
  2. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/PKG-INFO +1 -1
  3. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/structured-output.mdx +1 -1
  4. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/overview.mdx +31 -23
  5. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/codeact/codeact_agent.py +1 -77
  6. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/codeact/events.py +0 -5
  7. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/droid/__init__.py +2 -2
  8. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/droid/droid_agent.py +62 -40
  9. droidrun-0.4.0.dev7/droidrun/agent/droid/events.py +124 -0
  10. droidrun-0.4.0.dev5/droidrun/agent/droid/events.py → droidrun-0.4.0.dev7/droidrun/agent/droid/state.py +1 -127
  11. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/executor/executor_agent.py +28 -8
  12. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/manager/events.py +4 -0
  13. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/manager/manager_agent.py +35 -56
  14. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/manager/prompts.py +24 -5
  15. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/scripter/scripter_agent.py +5 -3
  16. droidrun-0.4.0.dev7/droidrun/agent/utils/__init__.py +52 -0
  17. droidrun-0.4.0.dev7/droidrun/agent/utils/chat_utils.py +255 -0
  18. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/llm_picker.py +8 -1
  19. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/tools.py +32 -4
  20. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/cli/main.py +25 -20
  21. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/manager/rev1.jinja2 +11 -3
  22. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/manager/system.jinja2 +18 -6
  23. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_manager/config_manager.py +12 -236
  24. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/tools/adb.py +2 -2
  25. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/tools/portal_client.py +1 -1
  26. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/pyproject.toml +1 -1
  27. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/uv.lock +1 -1
  28. droidrun-0.4.0.dev5/droidrun/agent/context/__init__.py +0 -12
  29. droidrun-0.4.0.dev5/droidrun/agent/context/episodic_memory.py +0 -15
  30. droidrun-0.4.0.dev5/droidrun/agent/context/task_manager.py +0 -149
  31. droidrun-0.4.0.dev5/droidrun/agent/utils/__init__.py +0 -13
  32. droidrun-0.4.0.dev5/droidrun/agent/utils/chat_utils.py +0 -394
  33. droidrun-0.4.0.dev5/droidrun/agent/utils/message_utils.py +0 -85
  34. droidrun-0.4.0.dev5/examples/custom_prompts_example.py +0 -148
  35. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/.github/workflows/black.yml +0 -0
  36. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/.github/workflows/bounty.yml +0 -0
  37. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/.github/workflows/publish.yml +0 -0
  38. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/.python-version +0 -0
  39. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/CHANGELOG.md +0 -0
  40. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/CONTRIBUTING.md +0 -0
  41. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/LICENSE +0 -0
  42. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/MANIFEST.in +0 -0
  43. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/README.md +0 -0
  44. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/docs.json +0 -0
  45. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/favicon.png +0 -0
  46. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/logo/dark.svg +0 -0
  47. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/logo/light.svg +0 -0
  48. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v1/concepts/agent.mdx +0 -0
  49. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v1/concepts/android-control.mdx +0 -0
  50. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v1/concepts/portal-app.mdx +0 -0
  51. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v1/overview.mdx +0 -0
  52. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v1/quickstart.mdx +0 -0
  53. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/concepts/agent.mdx +0 -0
  54. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/concepts/android-control.mdx +0 -0
  55. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/concepts/planning.mdx +0 -0
  56. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/concepts/portal-app.mdx +0 -0
  57. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/concepts/tracing.mdx +0 -0
  58. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/overview.mdx +0 -0
  59. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v2/quickstart.mdx +0 -0
  60. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/concepts/agent.mdx +0 -0
  61. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/concepts/android-tools.mdx +0 -0
  62. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/concepts/models.mdx +0 -0
  63. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/concepts/portal-app.mdx +0 -0
  64. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/cli.mdx +0 -0
  65. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/gemini.mdx +0 -0
  66. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/ollama.mdx +0 -0
  67. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/openailike.mdx +0 -0
  68. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/overview.mdx +0 -0
  69. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/guides/telemetry.mdx +0 -0
  70. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/images/portal_apk.png +0 -0
  71. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/overview.mdx +0 -0
  72. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v3/quickstart.mdx +0 -0
  73. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/agent-architecture.mdx +0 -0
  74. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/events-and-workflows.mdx +0 -0
  75. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/overview.mdx +0 -0
  76. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/prompts.mdx +0 -0
  77. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/scripter-agent.mdx +0 -0
  78. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/concepts/shared-state.mdx +0 -0
  79. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/app-cards.mdx +0 -0
  80. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/cli.mdx +0 -0
  81. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/custom-tools-credentials.mdx +0 -0
  82. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/custom-variables.mdx +0 -0
  83. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/device-setup.mdx +0 -0
  84. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/overview.mdx +0 -0
  85. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/guides/telemetry-tracing.mdx +0 -0
  86. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/quickstart.mdx +0 -0
  87. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk/adb-tools.mdx +0 -0
  88. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk/base-tools.mdx +0 -0
  89. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk/configuration.mdx +0 -0
  90. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk/droid-agent.mdx +0 -0
  91. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk/ios-tools.mdx +0 -0
  92. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/docs/v4/sdk.mdx +0 -0
  93. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/__init__.py +0 -0
  94. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/__main__.py +0 -0
  95. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/__init__.py +0 -0
  96. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/codeact/__init__.py +0 -0
  97. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/common/__init__.py +0 -0
  98. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/common/constants.py +0 -0
  99. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/common/events.py +0 -0
  100. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/executor/__init__.py +0 -0
  101. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/executor/events.py +0 -0
  102. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/executor/prompts.py +0 -0
  103. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/manager/__init__.py +0 -0
  104. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/oneflows/__init__.py +0 -0
  105. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/oneflows/app_starter_workflow.py +0 -0
  106. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/oneflows/structured_output_agent.py +0 -0
  107. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/oneflows/text_manipulator.py +0 -0
  108. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/scripter/__init__.py +0 -0
  109. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/scripter/events.py +0 -0
  110. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/usage.py +0 -0
  111. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/async_utils.py +0 -0
  112. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/device_state_formatter.py +0 -0
  113. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/executer.py +0 -0
  114. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/inference.py +0 -0
  115. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/llm_loader.py +0 -0
  116. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/prompt_resolver.py +0 -0
  117. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/agent/utils/trajectory.py +0 -0
  118. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/__init__.py +0 -0
  119. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/app_card_provider.py +0 -0
  120. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/providers/__init__.py +0 -0
  121. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/providers/composite_provider.py +0 -0
  122. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/providers/local_provider.py +0 -0
  123. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/app_cards/providers/server_provider.py +0 -0
  124. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/cli/__init__.py +0 -0
  125. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/cli/logs.py +0 -0
  126. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/app_cards/README.md +0 -0
  127. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/app_cards/app_cards.json +0 -0
  128. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/app_cards/gmail.md +0 -0
  129. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/credentials_example.yaml +0 -0
  130. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/codeact/system.jinja2 +0 -0
  131. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/codeact/user.jinja2 +0 -0
  132. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/executor/rev1.jinja2 +0 -0
  133. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/executor/system.jinja2 +0 -0
  134. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config/prompts/scripter/system.jinja2 +0 -0
  135. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_example.yaml +0 -0
  136. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_manager/__init__.py +0 -0
  137. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_manager/path_resolver.py +0 -0
  138. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_manager/prompt_loader.py +0 -0
  139. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/config_manager/safe_execution.py +0 -0
  140. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/credential_manager/__init__.py +0 -0
  141. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/credential_manager/credential_loader.py +0 -0
  142. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/credential_manager/credential_manager.py +0 -0
  143. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/macro/__init__.py +0 -0
  144. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/macro/__main__.py +0 -0
  145. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/macro/cli.py +0 -0
  146. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/macro/replay.py +0 -0
  147. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/portal.py +0 -0
  148. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/telemetry/__init__.py +0 -0
  149. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/telemetry/events.py +0 -0
  150. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/telemetry/phoenix.py +0 -0
  151. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/telemetry/tracker.py +0 -0
  152. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/tools/__init__.py +0 -0
  153. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/tools/ios.py +0 -0
  154. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/droidrun/tools/tools.py +0 -0
  155. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/gen-docs-sdk-ref.sh +0 -0
  156. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/setup.py +0 -0
  157. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/static/droidrun-dark.png +0 -0
  158. {droidrun-0.4.0.dev5 → droidrun-0.4.0.dev7}/static/droidrun.png +0 -0
@@ -36,4 +36,6 @@ credentials.yaml
36
36
  !.github/
37
37
 
38
38
  backend/
39
- frontend/
39
+ frontend/
40
+
41
+ reddit_python_posts.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: droidrun
3
- Version: 0.4.0.dev5
3
+ Version: 0.4.0.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
@@ -142,7 +142,7 @@ llm_profiles:
142
142
 
143
143
  **Programmatically:**
144
144
  ```python
145
- from droidrun.llm_utils import load_llm
145
+ from droidrun import load_llm
146
146
 
147
147
  config = DroidrunConfig()
148
148
 
@@ -51,24 +51,28 @@ Droidrun v4 introduces a hierarchical multi-agent system with specialized agents
51
51
  Monitor and debug agent execution in real-time with Droidrun's comprehensive event system:
52
52
 
53
53
  ```python
54
+ import asyncio
54
55
  from droidrun import DroidAgent, ResultEvent
55
56
  from droidrun.agent.droid.events import ManagerPlanEvent, ExecutorResultEvent
56
57
  from droidrun.config_manager.config_manager import DroidrunConfig
57
58
 
58
- # Create config with defaults
59
- config = DroidrunConfig()
59
+ async def main():
60
+ # Create config with defaults
61
+ config = DroidrunConfig()
62
+
63
+ agent = DroidAgent(goal="Open Settings and enable WiFi", config=config)
64
+ handler = agent.run()
60
65
 
61
- agent = DroidAgent(goal="Open Settings and enable WiFi", config=config)
62
- handler = agent.run()
66
+ # Stream events in real-time
67
+ async for event in handler.stream_events():
68
+ if isinstance(event, ManagerPlanEvent):
69
+ print(f"Plan: {event.plan}")
70
+ elif isinstance(event, ExecutorResultEvent):
71
+ print(f"Action: {event.action}")
63
72
 
64
- # Stream events in real-time
65
- async for event in handler.stream_events():
66
- if isinstance(event, ManagerPlanEvent):
67
- print(f"Plan: {event.plan}")
68
- elif isinstance(event, ExecutorResultEvent):
69
- print(f"Action: {event.action}")
73
+ result: ResultEvent = await handler
70
74
 
71
- result: ResultEvent = await handler
75
+ asyncio.run(main())
72
76
  ```
73
77
 
74
78
  Events provide rich metadata for:
@@ -125,6 +129,7 @@ llm_profiles:
125
129
  Extract type-safe, validated data from device interactions using Pydantic models:
126
130
 
127
131
  ```python
132
+ import asyncio
128
133
  from pydantic import BaseModel, Field
129
134
  from droidrun import DroidAgent, ResultEvent
130
135
  from droidrun.config_manager.config_manager import DroidrunConfig
@@ -135,21 +140,24 @@ class ContactInfo(BaseModel):
135
140
  phone: str = Field(description="Phone number")
136
141
  email: str = Field(description="Email address")
137
142
 
138
- # Create config with defaults
139
- config = DroidrunConfig()
143
+ async def main():
144
+ # Create config with defaults
145
+ config = DroidrunConfig()
140
146
 
141
- agent = DroidAgent(
142
- goal="Find John Smith's contact and extract details",
143
- config=config,
144
- output_model=ContactInfo # Automatic structured extraction
145
- )
147
+ agent = DroidAgent(
148
+ goal="Find John Smith's contact and extract details",
149
+ config=config,
150
+ output_model=ContactInfo # Automatic structured extraction
151
+ )
152
+
153
+ handler = agent.run()
154
+ result: ResultEvent = await handler
146
155
 
147
- handler = agent.run()
148
- result: ResultEvent = await handler
156
+ if result.success and result.structured_output:
157
+ contact: ContactInfo = result.structured_output
158
+ print(f"Phone: {contact.phone}")
149
159
 
150
- if result.success and result.structured_output:
151
- contact: ContactInfo = result.structured_output
152
- print(f"Phone: {contact.phone}")
160
+ asyncio.run(main())
153
161
  ```
154
162
 
155
163
  <Card title="Structured Output Guide" icon="table" href="/v4/guides/structured-output">
@@ -18,7 +18,6 @@ from llama_index.core.memory import Memory
18
18
  from llama_index.core.workflow import Context, StartEvent, StopEvent, Workflow, step
19
19
 
20
20
  from droidrun.agent.codeact.events import (
21
- EpisodicMemoryEvent,
22
21
  TaskEndEvent,
23
22
  TaskExecutionEvent,
24
23
  TaskExecutionResultEvent,
@@ -27,7 +26,6 @@ from droidrun.agent.codeact.events import (
27
26
  )
28
27
  from droidrun.agent.common.constants import LLM_HISTORY_LIMIT
29
28
  from droidrun.agent.common.events import RecordUIStateEvent, ScreenshotEvent
30
- from droidrun.agent.context.episodic_memory import EpisodicMemory, EpisodicMemoryStep
31
29
  from droidrun.agent.usage import get_usage_from_response
32
30
  from droidrun.agent.utils import chat_utils
33
31
  from droidrun.agent.utils.device_state_formatter import format_device_state
@@ -43,7 +41,7 @@ from droidrun.config_manager.prompt_loader import PromptLoader
43
41
  from droidrun.tools import Tools
44
42
 
45
43
  if TYPE_CHECKING:
46
- from droidrun.agent.droid.droid_agent import DroidAgentState
44
+ from droidrun.agent.droid import DroidAgentState
47
45
 
48
46
  logger = logging.getLogger("droidrun")
49
47
 
@@ -85,7 +83,6 @@ class CodeActAgent(Workflow):
85
83
  self.prompt_resolver = prompt_resolver or PromptResolver()
86
84
 
87
85
  self.chat_memory = None
88
- self.episodic_memory = EpisodicMemory()
89
86
  self.remembered_info = None
90
87
 
91
88
  self.goal = None
@@ -459,10 +456,6 @@ Now, describe the next step you will take to address the original goal: {goal}""
459
456
  self.tools.finished = False
460
457
  await ctx.store.set("chat_memory", self.chat_memory)
461
458
 
462
- # Add final state observation to episodic memory
463
- if self.vision:
464
- await self._add_final_state_observation(ctx)
465
-
466
459
  result = {}
467
460
  result.update(
468
461
  {
@@ -472,10 +465,6 @@ Now, describe the next step you will take to address the original goal: {goal}""
472
465
  }
473
466
  )
474
467
 
475
- ctx.write_event_to_stream(
476
- EpisodicMemoryEvent(episodic_memory=self.episodic_memory)
477
- )
478
-
479
468
  return StopEvent(result)
480
469
 
481
470
  async def _get_llm_response(
@@ -500,26 +489,6 @@ Now, describe the next step you will take to address the original goal: {goal}""
500
489
  ]
501
490
  filtered_chat_history.append(filtered_msg)
502
491
 
503
- # Convert chat history and response to JSON strings
504
- chat_history_str = json.dumps(
505
- [
506
- {"role": msg.role, "content": msg.content}
507
- for msg in filtered_chat_history
508
- ]
509
- )
510
- response_str = json.dumps(
511
- {"role": response.message.role, "content": response.message.content}
512
- )
513
-
514
- step = EpisodicMemoryStep(
515
- chat_history=chat_history_str,
516
- response=response_str,
517
- timestamp=time.time(),
518
- screenshot=(await ctx.store.get("screenshot", None)),
519
- )
520
-
521
- self.episodic_memory.steps.append(step)
522
-
523
492
  assert hasattr(
524
493
  response, "message"
525
494
  ), f"LLM response does not have a message attribute.\nResponse: {response}"
@@ -577,48 +546,3 @@ Now, describe the next step you will take to address the original goal: {goal}""
577
546
  preserved_head = []
578
547
 
579
548
  return preserved_head + tail
580
-
581
- async def _add_final_state_observation(self, ctx: Context) -> None:
582
- """Add the current UI state and screenshot as the final observation step."""
583
- try:
584
- # Get current screenshot and UI state
585
- screenshot = None
586
-
587
- try:
588
- _, screenshot_bytes = self.tools.take_screenshot()
589
- screenshot = screenshot_bytes
590
- except Exception as e:
591
- logger.warning(f"Failed to capture final screenshot: {e}")
592
-
593
- try:
594
- state = self.tools.get_state()
595
- a11y_tree = state.get("a11y_tree", "")
596
- phone_state = state.get("phone_state", "") # noqa: F841
597
- except Exception as e:
598
- raise Exception(f"Failed to capture final UI state: {e}") from e
599
-
600
- # Create final observation chat history and response
601
- final_chat_history = [
602
- {
603
- "role": "system",
604
- "content": "Final state observation after task completion",
605
- }
606
- ]
607
- final_response = {
608
- "role": "user",
609
- "content": f"Final State Observation:\nUI State: {a11y_tree}\nScreenshot: {'Available' if screenshot else 'Not available'}",
610
- }
611
-
612
- # Create final episodic memory step
613
- final_step = EpisodicMemoryStep(
614
- chat_history=json.dumps(final_chat_history),
615
- response=json.dumps(final_response),
616
- timestamp=time.time(),
617
- screenshot=screenshot,
618
- )
619
-
620
- self.episodic_memory.steps.append(final_step)
621
- logger.info("Added final state observation to episodic memory")
622
-
623
- except Exception as e:
624
- logger.error(f"Failed to add final state observation: {e}")
@@ -3,7 +3,6 @@ from typing import Optional
3
3
  from llama_index.core.llms import ChatMessage
4
4
  from llama_index.core.workflow import Event
5
5
 
6
- from droidrun.agent.context.episodic_memory import EpisodicMemory
7
6
  from droidrun.agent.usage import UsageResult
8
7
 
9
8
 
@@ -30,7 +29,3 @@ class TaskExecutionResultEvent(Event):
30
29
  class TaskEndEvent(Event):
31
30
  success: bool
32
31
  reason: str
33
-
34
-
35
- class EpisodicMemoryEvent(Event):
36
- episodic_memory: EpisodicMemory
@@ -4,7 +4,7 @@ Droidrun Agent Module.
4
4
  This module provides a ReAct agent for automating Android devices using reasoning and acting.
5
5
  """
6
6
 
7
- from droidrun.agent.codeact.codeact_agent import CodeActAgent
8
7
  from droidrun.agent.droid.droid_agent import DroidAgent
8
+ from droidrun.agent.droid.state import DroidAgentState
9
9
 
10
- __all__ = ["CodeActAgent", "DroidAgent"]
10
+ __all__ = ["DroidAgent", "DroidAgentState"]
@@ -18,13 +18,10 @@ from llama_index.core.workflow import Context, StartEvent, StopEvent, Workflow,
18
18
  from workflows.events import Event
19
19
  from workflows.handler import WorkflowHandler
20
20
  from droidrun.agent.codeact import CodeActAgent
21
- from droidrun.agent.codeact.events import EpisodicMemoryEvent
22
21
  from droidrun.agent.common.events import MacroEvent, RecordUIStateEvent, ScreenshotEvent
23
- from droidrun.agent.context.task_manager import Task, TaskManager
24
22
  from droidrun.agent.droid.events import (
25
23
  CodeActExecuteEvent,
26
24
  CodeActResultEvent,
27
- DroidAgentState,
28
25
  ExecutorInputEvent,
29
26
  ExecutorResultEvent,
30
27
  FinalizeEvent,
@@ -34,6 +31,7 @@ from droidrun.agent.droid.events import (
34
31
  ScripterExecutorInputEvent,
35
32
  ScripterExecutorResultEvent,
36
33
  )
34
+ from droidrun.agent.droid.state import DroidAgentState
37
35
  from droidrun.agent.executor import ExecutorAgent
38
36
  from droidrun.agent.manager import ManagerAgent
39
37
  from droidrun.agent.scripter import ScripterAgent
@@ -269,9 +267,6 @@ class DroidAgent(Workflow):
269
267
  self.structured_output_llm = llms
270
268
 
271
269
  self.trajectory = Trajectory(goal=self.shared_state.instruction)
272
- self.task_manager = TaskManager()
273
- self.task_iter = None
274
- self.current_episodic_memory = None
275
270
 
276
271
  self.atomic_tools = ATOMIC_ACTION_SIGNATURES.copy()
277
272
 
@@ -378,14 +373,13 @@ class DroidAgent(Workflow):
378
373
  Execute a single task using the CodeActAgent.
379
374
 
380
375
  Args:
381
- task: Task dictionary with description and status
376
+ instruction: task of what the agent shall do
382
377
 
383
378
  Returns:
384
379
  Tuple of (success, reason)
385
380
  """
386
- task: Task = ev.task
387
381
 
388
- logger.info(f"🔧 Executing task: {task.description}")
382
+ logger.info(f"🔧 Executing task: {ev.instruction}")
389
383
 
390
384
  try:
391
385
  codeact_agent = CodeActAgent(
@@ -403,7 +397,7 @@ class DroidAgent(Workflow):
403
397
  )
404
398
 
405
399
  handler = codeact_agent.run(
406
- input=task.description,
400
+ input=ev.instruction,
407
401
  remembered_info=self.tools_instance.memory,
408
402
  )
409
403
 
@@ -413,17 +407,21 @@ class DroidAgent(Workflow):
413
407
  result = await handler
414
408
 
415
409
  if "success" in result and result["success"]:
416
- return CodeActResultEvent(
410
+ event = CodeActResultEvent(
417
411
  success=True,
418
412
  reason=result["reason"],
419
- task=task,
413
+ instruction=ev.instruction,
420
414
  )
415
+ ctx.write_event_to_stream(event)
416
+ return event
421
417
  else:
422
- return CodeActResultEvent(
418
+ event = CodeActResultEvent(
423
419
  success=False,
424
420
  reason=result["reason"],
425
- task=task,
421
+ instruction=ev.instruction,
426
422
  )
423
+ ctx.write_event_to_stream(event)
424
+ return event
427
425
 
428
426
  except Exception as e:
429
427
  logger.error(f"Error during task execution: {e}")
@@ -431,26 +429,32 @@ class DroidAgent(Workflow):
431
429
  import traceback
432
430
 
433
431
  logger.error(traceback.format_exc())
434
- return CodeActResultEvent(
435
- success=False, reason=f"Error: {str(e)}", task=task
432
+ event = CodeActResultEvent(
433
+ success=False, reason=f"Error: {str(e)}", instruction=ev.instruction
436
434
  )
435
+ ctx.write_event_to_stream(event)
436
+ return event
437
437
 
438
438
  @step
439
439
  async def handle_codeact_execute(
440
440
  self, ctx: Context, ev: CodeActResultEvent
441
441
  ) -> FinalizeEvent:
442
442
  try:
443
- return FinalizeEvent(success=ev.success, reason=ev.reason)
443
+ event = FinalizeEvent(success=ev.success, reason=ev.reason)
444
+ ctx.write_event_to_stream(event)
445
+ return event
444
446
  except Exception as e:
445
447
  logger.error(f"❌ Error during DroidAgent execution: {e}")
446
448
  if self.config.logging.debug:
447
449
  import traceback
448
450
 
449
451
  logger.error(traceback.format_exc())
450
- return FinalizeEvent(
452
+ event = FinalizeEvent(
451
453
  success=False,
452
454
  reason=str(e),
453
455
  )
456
+ ctx.write_event_to_stream(event)
457
+ return event
454
458
 
455
459
  @step
456
460
  async def start_handler(
@@ -480,15 +484,14 @@ class DroidAgent(Workflow):
480
484
  logger.info(
481
485
  f"🔄 Direct execution mode - executing goal: {self.shared_state.instruction}"
482
486
  )
483
- task = Task(
484
- description=self.shared_state.instruction,
485
- status=self.task_manager.STATUS_PENDING,
486
- agent_type="Default",
487
- )
488
- return CodeActExecuteEvent(task=task)
487
+ event = CodeActExecuteEvent(instruction=self.shared_state.instruction)
488
+ ctx.write_event_to_stream(event)
489
+ return event
489
490
 
490
491
  logger.info("🧠 Reasoning mode - initializing Manager/Executor workflow")
491
- return ManagerInputEvent()
492
+ event = ManagerInputEvent()
493
+ ctx.write_event_to_stream(event)
494
+ return event
492
495
 
493
496
  # ========================================================================
494
497
  # Manager/Executor Workflow Steps
@@ -506,10 +509,12 @@ class DroidAgent(Workflow):
506
509
  """
507
510
  if self.shared_state.step_number >= self.config.agent.max_steps:
508
511
  logger.warning(f"⚠️ Reached maximum steps ({self.config.agent.max_steps})")
509
- return FinalizeEvent(
512
+ event = FinalizeEvent(
510
513
  success=False,
511
514
  reason=f"Reached maximum steps ({self.config.agent.max_steps})",
512
515
  )
516
+ ctx.write_event_to_stream(event)
517
+ return event
513
518
 
514
519
  logger.info(
515
520
  f"📋 Running Manager for planning... (step {self.shared_state.step_number}/{self.config.agent.max_steps})"
@@ -525,12 +530,15 @@ class DroidAgent(Workflow):
525
530
  result = await handler
526
531
 
527
532
  # Manager already updated shared_state, just return event with results
528
- return ManagerPlanEvent(
533
+ event = ManagerPlanEvent(
529
534
  plan=result["plan"],
530
535
  current_subgoal=result["current_subgoal"],
531
536
  thought=result["thought"],
532
537
  manager_answer=result.get("manager_answer", ""),
538
+ success=result.get("success"),
533
539
  )
540
+ ctx.write_event_to_stream(event)
541
+ return event
534
542
 
535
543
  @step
536
544
  async def handle_manager_plan(
@@ -543,10 +551,16 @@ class DroidAgent(Workflow):
543
551
  """
544
552
  # Check for answer-type termination
545
553
  if ev.manager_answer.strip():
546
- logger.info(f"💬 Manager provided answer: {ev.manager_answer}")
554
+ # Use success field from manager, default to True if not set for backward compatibility
555
+ success = ev.success if ev.success is not None else True
556
+ logger.info(
557
+ f"💬 Manager provided answer (success={success}): {ev.manager_answer}"
558
+ )
547
559
  self.shared_state.progress_status = f"Answer: {ev.manager_answer}"
548
560
 
549
- return FinalizeEvent(success=True, reason=ev.manager_answer)
561
+ event = FinalizeEvent(success=success, reason=ev.manager_answer)
562
+ ctx.write_event_to_stream(event)
563
+ return event
550
564
 
551
565
  # Check for <script> tag in current_subgoal, then extract from full plan
552
566
  if "<script>" in ev.current_subgoal:
@@ -558,7 +572,9 @@ class DroidAgent(Workflow):
558
572
  # Extract content between first <script> and first </script> in plan
559
573
  task = ev.plan[start_idx + len("<script>") : end_idx].strip()
560
574
  logger.info(f"🐍 Routing to ScripterAgent: {task[:80]}...")
561
- return ScripterExecutorInputEvent(task=task)
575
+ event = ScripterExecutorInputEvent(task=task)
576
+ ctx.write_event_to_stream(event)
577
+ return event
562
578
  else:
563
579
  # <script> found in subgoal but not properly closed in plan - log warning
564
580
  logger.warning(
@@ -567,7 +583,9 @@ class DroidAgent(Workflow):
567
583
 
568
584
  # Continue to Executor with current subgoal
569
585
  logger.info(f"▶️ Proceeding to Executor with subgoal: {ev.current_subgoal}")
570
- return ExecutorInputEvent(current_subgoal=ev.current_subgoal)
586
+ event = ExecutorInputEvent(current_subgoal=ev.current_subgoal)
587
+ ctx.write_event_to_stream(event)
588
+ return event
571
589
 
572
590
  @step
573
591
  async def run_executor(
@@ -599,12 +617,14 @@ class DroidAgent(Workflow):
599
617
  self.shared_state.last_action_thought = result.get("thought", "")
600
618
  self.shared_state.action_pool.append(result["action_json"])
601
619
 
602
- return ExecutorResultEvent(
620
+ event = ExecutorResultEvent(
603
621
  action=result["action"],
604
622
  outcome=result["outcome"],
605
623
  error=result["error"],
606
624
  summary=result["summary"],
607
625
  )
626
+ ctx.write_event_to_stream(event)
627
+ return event
608
628
 
609
629
  @step
610
630
  async def handle_executor_result(
@@ -635,7 +655,9 @@ class DroidAgent(Workflow):
635
655
  f"🔄 Step {self.shared_state.step_number}/{self.config.agent.max_steps} complete, looping to Manager"
636
656
  )
637
657
 
638
- return ManagerInputEvent()
658
+ event = ManagerInputEvent()
659
+ ctx.write_event_to_stream(event)
660
+ return event
639
661
 
640
662
  # ========================================================================
641
663
  # Script Executor Workflow Steps
@@ -682,12 +704,14 @@ class DroidAgent(Workflow):
682
704
 
683
705
  logger.info(f"🐍 ScripterAgent finished: {result['message'][:2000]}...")
684
706
 
685
- return ScripterExecutorResultEvent(
707
+ event = ScripterExecutorResultEvent(
686
708
  task=ev.task,
687
709
  message=result["message"],
688
710
  success=result["success"],
689
711
  code_executions=result.get("code_executions", 0),
690
712
  )
713
+ ctx.write_event_to_stream(event)
714
+ return event
691
715
 
692
716
  @step
693
717
  async def handle_scripter_result(
@@ -710,7 +734,9 @@ class DroidAgent(Workflow):
710
734
  )
711
735
 
712
736
  # Loop back to Manager (script result in shared_state)
713
- return ManagerInputEvent()
737
+ event = ManagerInputEvent()
738
+ ctx.write_event_to_stream(event)
739
+ return event
714
740
 
715
741
  # ========================================================================
716
742
  # End Manager/Executor/Script Workflow Steps
@@ -751,7 +777,7 @@ class DroidAgent(Workflow):
751
777
  timeout=self.timeout,
752
778
  )
753
779
 
754
- handler = await structured_agent.run()
780
+ handler = structured_agent.run()
755
781
 
756
782
  # Stream nested events
757
783
  async for nested_ev in handler.stream_events():
@@ -782,10 +808,6 @@ class DroidAgent(Workflow):
782
808
  return result
783
809
 
784
810
  def handle_stream_event(self, ev: Event, ctx: Context):
785
- if isinstance(ev, EpisodicMemoryEvent):
786
- self.current_episodic_memory = ev.episodic_memory
787
- return
788
-
789
811
  if not isinstance(ev, StopEvent):
790
812
  ctx.write_event_to_stream(ev)
791
813
 
@@ -0,0 +1,124 @@
1
+ """
2
+ DroidAgent coordination events.
3
+
4
+ These events are used for WORKFLOW COORDINATION between DroidAgent and its child agents.
5
+ They carry minimal data needed for routing workflow steps.
6
+
7
+ For internal events with full debugging metadata, see:
8
+ - manager/events.py (ManagerInternalPlanEvent)
9
+ - executor/events.py (ExecutorInternalActionEvent, ExecutorInternalResultEvent)
10
+ """
11
+
12
+ from typing import Dict
13
+
14
+ from llama_index.core.workflow import Event, StopEvent
15
+ from pydantic import BaseModel
16
+
17
+
18
+ class CodeActExecuteEvent(Event):
19
+ instruction: str
20
+
21
+
22
+ class CodeActResultEvent(Event):
23
+ success: bool
24
+ reason: str
25
+ instruction: str
26
+
27
+
28
+ class FinalizeEvent(Event):
29
+ success: bool
30
+ reason: str
31
+
32
+
33
+ class ResultEvent(StopEvent):
34
+ """
35
+ DroidAgent final result event.
36
+
37
+ Returned by DroidAgent.run() with attributes:
38
+ - success: Whether the task completed successfully
39
+ - reason: Explanation of the result or error message
40
+ - steps: Number of steps taken
41
+ - structured_output: Extracted structured data (if output_model was provided)
42
+ """
43
+
44
+ success: bool
45
+ reason: str
46
+ steps: int
47
+ structured_output: BaseModel | None
48
+
49
+
50
+ class TaskRunnerEvent(Event):
51
+ pass
52
+
53
+
54
+ # ============================================================================
55
+ # Manager/Executor coordination events
56
+ # ============================================================================
57
+
58
+
59
+ class ManagerInputEvent(Event):
60
+ """Trigger Manager workflow for planning"""
61
+
62
+ pass
63
+
64
+
65
+ class ManagerPlanEvent(Event):
66
+ """
67
+ Coordination event from ManagerAgent to DroidAgent.
68
+
69
+ Used for workflow step routing only (NOT streamed to frontend).
70
+ For internal events with memory_update metadata, see ManagerInternalPlanEvent.
71
+ """
72
+
73
+ plan: str
74
+ current_subgoal: str
75
+ thought: str
76
+ manager_answer: str = ""
77
+ success: bool | None = (
78
+ None # True/False if task complete, None if still in progress
79
+ )
80
+
81
+
82
+ class ExecutorInputEvent(Event):
83
+ """Trigger Executor workflow for action execution"""
84
+
85
+ current_subgoal: str
86
+
87
+
88
+ class ExecutorResultEvent(Event):
89
+ """
90
+ Coordination event from ExecutorAgent to DroidAgent.
91
+
92
+ Used for workflow step routing only (NOT streamed to frontend).
93
+ For internal events with thought/action_json metadata, see ExecutorInternalResultEvent.
94
+ """
95
+
96
+ action: Dict
97
+ outcome: bool
98
+ error: str
99
+ summary: str
100
+ full_response: str = ""
101
+
102
+
103
+ # ============================================================================
104
+ # Script executor coordination events
105
+ # ============================================================================
106
+
107
+
108
+ class ScripterExecutorInputEvent(Event):
109
+ """Trigger ScripterAgent workflow for off-device operations"""
110
+
111
+ task: str
112
+
113
+
114
+ class ScripterExecutorResultEvent(Event):
115
+ """
116
+ Coordination event from ScripterAgent to DroidAgent.
117
+
118
+ Used for workflow step routing only (NOT streamed to frontend).
119
+ """
120
+
121
+ task: str
122
+ message: str # Response from response() function
123
+ success: bool
124
+ code_executions: int