droidrun 0.3.10.dev10__tar.gz → 0.3.10.dev12__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.
- droidrun-0.3.10.dev12/.github/black.yml +19 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/PKG-INFO +1 -1
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/codeact/codeact_agent.py +15 -2
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/droid/droid_agent.py +142 -18
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/droid/events.py +36 -20
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/executor/executor_agent.py +8 -3
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/manager/manager_agent.py +20 -1
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/manager/prompts.py +20 -11
- droidrun-0.3.10.dev12/droidrun/agent/scripter/__init__.py +7 -0
- droidrun-0.3.10.dev12/droidrun/agent/scripter/events.py +36 -0
- droidrun-0.3.10.dev12/droidrun/agent/scripter/scripter_agent.py +281 -0
- droidrun-0.3.10.dev12/droidrun/agent/utils/async_utils.py +42 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/executer.py +40 -5
- droidrun-0.3.10.dev12/droidrun/agent/utils/llm_loader.py +180 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/tools.py +43 -2
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/cli/main.py +137 -298
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/executor/system.jinja2 +1 -1
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/manager/rev1.jinja2 +55 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/manager/system.jinja2 +51 -0
- droidrun-0.3.10.dev12/droidrun/config/prompts/scripter/system.jinja2 +86 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config_example.yaml +79 -0
- droidrun-0.3.10.dev12/droidrun/config_manager/__init__.py +52 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config_manager/config_manager.py +123 -1
- droidrun-0.3.10.dev12/droidrun/config_manager/safe_execution.py +226 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/pyproject.toml +1 -1
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/uv.lock +1 -1
- droidrun-0.3.10.dev10/droidrun/agent/utils/async_utils.py +0 -18
- droidrun-0.3.10.dev10/droidrun/config_manager/__init__.py +0 -25
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/.github/workflows/bounty.yml +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/.github/workflows/publish.yml +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/.gitignore +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/.python-version +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/CHANGELOG.md +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/CONTRIBUTING.md +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/LICENSE +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/MANIFEST.in +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/README.md +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/.generated-files.txt +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/docs.json +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/favicon.png +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/logo/dark.svg +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/logo/light.svg +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v1/concepts/agent.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v1/concepts/android-control.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v1/concepts/portal-app.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v1/overview.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v1/quickstart.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/concepts/agent.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/concepts/android-control.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/concepts/planning.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/concepts/portal-app.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/concepts/tracing.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/overview.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v2/quickstart.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/concepts/agent.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/concepts/android-tools.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/concepts/models.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/concepts/portal-app.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/cli.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/gemini.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/ollama.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/openailike.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/overview.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/guides/telemetry.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/images/portal_apk.png +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/overview.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/quickstart.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/sdk/adb-tools.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/sdk/base-tools.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/sdk/droid-agent.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/docs/v3/sdk/ios-tools.mdx +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/__main__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/codeact/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/codeact/events.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/common/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/common/constants.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/common/events.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/context/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/context/episodic_memory.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/context/task_manager.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/droid/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/executor/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/executor/events.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/executor/prompts.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/manager/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/manager/events.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/oneflows/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/oneflows/app_starter_workflow.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/oneflows/text_manipulator.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/usage.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/chat_utils.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/device_state_formatter.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/inference.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/llm_picker.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/message_utils.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/agent/utils/trajectory.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/app_card_provider.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/providers/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/providers/composite_provider.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/providers/local_provider.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/app_cards/providers/server_provider.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/cli/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/cli/logs.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/app_cards/README.md +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/app_cards/app_cards.json +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/app_cards/gmail.md +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/codeact/system.jinja2 +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/codeact/user.jinja2 +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config/prompts/executor/rev1.jinja2 +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config_manager/path_resolver.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/config_manager/prompt_loader.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/macro/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/macro/__main__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/macro/cli.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/macro/replay.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/portal.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/telemetry/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/telemetry/events.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/telemetry/phoenix.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/telemetry/tracker.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/tools/__init__.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/tools/adb.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/tools/ios.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/tools/portal_client.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/droidrun/tools/tools.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/gen-docs-sdk-ref.sh +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/setup.py +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/static/droidrun-dark.png +0 -0
- {droidrun-0.3.10.dev10 → droidrun-0.3.10.dev12}/static/droidrun.png +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
lint:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
|
|
11
|
+
- uses: actions/setup-python@v5
|
|
12
|
+
with:
|
|
13
|
+
python-version: "3.13"
|
|
14
|
+
|
|
15
|
+
- uses: psf/black@stable
|
|
16
|
+
with:
|
|
17
|
+
options: "--check --diff --verbose"
|
|
18
|
+
src: "."
|
|
19
|
+
version: "25.9.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: droidrun
|
|
3
|
-
Version: 0.3.10.
|
|
3
|
+
Version: 0.3.10.dev12
|
|
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
|
|
@@ -53,8 +53,10 @@ class CodeActAgent(Workflow):
|
|
|
53
53
|
agent_config: AgentConfig,
|
|
54
54
|
tools_instance: "Tools",
|
|
55
55
|
custom_tools: dict = None,
|
|
56
|
+
atomic_tools: dict = None,
|
|
56
57
|
debug: bool = False,
|
|
57
58
|
shared_state: Optional["DroidAgentState"] = None,
|
|
59
|
+
safe_execution_config=None,
|
|
58
60
|
*args,
|
|
59
61
|
**kwargs,
|
|
60
62
|
):
|
|
@@ -77,8 +79,10 @@ class CodeActAgent(Workflow):
|
|
|
77
79
|
self.goal = None
|
|
78
80
|
self.code_exec_counter = 0
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
if atomic_tools is None:
|
|
83
|
+
atomic_tools = ATOMIC_ACTION_SIGNATURES
|
|
84
|
+
|
|
85
|
+
merged_signatures = {**atomic_tools, **(custom_tools or {})}
|
|
82
86
|
|
|
83
87
|
self.tool_list = {}
|
|
84
88
|
for action_name, signature in merged_signatures.items():
|
|
@@ -104,11 +108,20 @@ class CodeActAgent(Workflow):
|
|
|
104
108
|
)
|
|
105
109
|
self.system_prompt = ChatMessage(role="system", content=system_prompt_text)
|
|
106
110
|
|
|
111
|
+
# Get safety settings
|
|
112
|
+
safe_mode = self.config.safe_execution
|
|
113
|
+
safe_config = safe_execution_config
|
|
114
|
+
|
|
107
115
|
self.executor = SimpleCodeExecutor(
|
|
108
116
|
loop=asyncio.get_event_loop(),
|
|
109
117
|
locals={},
|
|
110
118
|
tools=self.tool_list,
|
|
111
119
|
globals={"__builtins__": __builtins__},
|
|
120
|
+
safe_mode=safe_mode,
|
|
121
|
+
allowed_modules=safe_config.get_allowed_modules() if safe_config and safe_mode else None,
|
|
122
|
+
blocked_modules=safe_config.get_blocked_modules() if safe_config and safe_mode else None,
|
|
123
|
+
allowed_builtins=safe_config.get_allowed_builtins() if safe_config and safe_mode else None,
|
|
124
|
+
blocked_builtins=safe_config.get_blocked_builtins() if safe_config and safe_mode else None,
|
|
112
125
|
)
|
|
113
126
|
|
|
114
127
|
logger.info("✅ CodeActAgent initialized successfully.")
|
|
@@ -7,9 +7,10 @@ Architecture:
|
|
|
7
7
|
- When reasoning=True: Uses Manager (planning) + Executor (action) workflows
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
import asyncio
|
|
10
11
|
import logging
|
|
11
12
|
from typing import List
|
|
12
|
-
|
|
13
|
+
from droidrun.agent.utils.tools import create_tools_from_config
|
|
13
14
|
import llama_index.core
|
|
14
15
|
from llama_index.core.llms.llm import LLM
|
|
15
16
|
from llama_index.core.workflow import Context, StartEvent, StopEvent, Workflow, step
|
|
@@ -29,9 +30,13 @@ from droidrun.agent.droid.events import (
|
|
|
29
30
|
FinalizeEvent,
|
|
30
31
|
ManagerInputEvent,
|
|
31
32
|
ManagerPlanEvent,
|
|
33
|
+
ScripterExecutorInputEvent,
|
|
34
|
+
ScripterExecutorResultEvent,
|
|
32
35
|
)
|
|
33
36
|
from droidrun.agent.executor import ExecutorAgent
|
|
34
37
|
from droidrun.agent.manager import ManagerAgent
|
|
38
|
+
from droidrun.agent.scripter import ScripterAgent
|
|
39
|
+
from droidrun.agent.utils.async_utils import wrap_async_tools
|
|
35
40
|
from droidrun.agent.utils.tools import ATOMIC_ACTION_SIGNATURES, open_app
|
|
36
41
|
from droidrun.agent.utils.trajectory import Trajectory
|
|
37
42
|
from droidrun.config_manager.config_manager import (
|
|
@@ -51,6 +56,7 @@ from droidrun.telemetry import (
|
|
|
51
56
|
)
|
|
52
57
|
from droidrun.telemetry.phoenix import arize_phoenix_callback_handler
|
|
53
58
|
from droidrun.tools import Tools
|
|
59
|
+
from droidrun.agent.utils.llm_loader import load_agent_llms, validate_llm_dict
|
|
54
60
|
|
|
55
61
|
logger = logging.getLogger("droidrun")
|
|
56
62
|
|
|
@@ -89,9 +95,8 @@ class DroidAgent(Workflow):
|
|
|
89
95
|
def __init__(
|
|
90
96
|
self,
|
|
91
97
|
goal: str,
|
|
92
|
-
llms: dict[str, LLM] | LLM,
|
|
93
|
-
tools: Tools,
|
|
94
98
|
config: DroidRunConfig | None = None,
|
|
99
|
+
llms: dict[str, LLM] | LLM | None = None,
|
|
95
100
|
agent_config: AgentConfig | None = None,
|
|
96
101
|
device_config: DeviceConfig | None = None,
|
|
97
102
|
tools_config: ToolsConfig | None = None,
|
|
@@ -109,9 +114,9 @@ class DroidAgent(Workflow):
|
|
|
109
114
|
|
|
110
115
|
Args:
|
|
111
116
|
goal: User's goal or command
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
config: Full config (required if llms not provided)
|
|
118
|
+
llms: Optional dict of agent-specific LLMs or single LLM for all.
|
|
119
|
+
If not provided, LLMs will be loaded from config profiles.
|
|
115
120
|
agent_config: Agent config override (optional)
|
|
116
121
|
device_config: Device config override (optional)
|
|
117
122
|
tools_config: Tools config override (optional)
|
|
@@ -141,10 +146,31 @@ class DroidAgent(Workflow):
|
|
|
141
146
|
llm_profiles=base_config.llm_profiles,
|
|
142
147
|
)
|
|
143
148
|
|
|
149
|
+
# Create tools from config
|
|
150
|
+
tools = create_tools_from_config(self.config.device)
|
|
151
|
+
|
|
144
152
|
super().__init__(*args, timeout=timeout, **kwargs)
|
|
145
153
|
|
|
146
154
|
self._configure_default_logging(debug=self.config.logging.debug)
|
|
147
155
|
|
|
156
|
+
# Load LLMs if not provided
|
|
157
|
+
if llms is None:
|
|
158
|
+
if config is None:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"Either 'llms' or 'config' must be provided. "
|
|
161
|
+
"If llms is not provided, config is required to load LLMs from profiles."
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
logger.info("🔄 Loading LLMs from config (llms not provided)...")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
llms = load_agent_llms(
|
|
169
|
+
config=self.config,
|
|
170
|
+
**kwargs
|
|
171
|
+
)
|
|
172
|
+
validate_llm_dict(self.config, llms)
|
|
173
|
+
|
|
148
174
|
if self.config.tracing.enabled:
|
|
149
175
|
try:
|
|
150
176
|
handler = arize_phoenix_callback_handler()
|
|
@@ -167,11 +193,7 @@ class DroidAgent(Workflow):
|
|
|
167
193
|
self.codeact_llm = llms.get('codeact')
|
|
168
194
|
self.text_manipulator_llm = llms.get('text_manipulator')
|
|
169
195
|
self.app_opener_llm = llms.get('app_opener')
|
|
170
|
-
|
|
171
|
-
if self.config.agent.reasoning and (not self.manager_llm or not self.executor_llm):
|
|
172
|
-
raise ValueError("When reasoning=True, 'manager' and 'executor' LLMs must be provided in llms dict")
|
|
173
|
-
if not self.codeact_llm:
|
|
174
|
-
raise ValueError("'codeact' LLM must be provided in llms dict")
|
|
196
|
+
self.scripter_llm = llms.get('scripter', self.codeact_llm)
|
|
175
197
|
|
|
176
198
|
logger.info("📚 Using agent-specific LLMs from dictionary")
|
|
177
199
|
else:
|
|
@@ -181,6 +203,7 @@ class DroidAgent(Workflow):
|
|
|
181
203
|
self.codeact_llm = llms
|
|
182
204
|
self.text_manipulator_llm = llms
|
|
183
205
|
self.app_opener_llm = llms
|
|
206
|
+
self.scripter_llm = llms
|
|
184
207
|
|
|
185
208
|
|
|
186
209
|
self.trajectory = Trajectory(goal=self.shared_state.instruction)
|
|
@@ -188,12 +211,13 @@ class DroidAgent(Workflow):
|
|
|
188
211
|
self.task_iter = None
|
|
189
212
|
self.current_episodic_memory = None
|
|
190
213
|
|
|
214
|
+
self.atomic_tools = ATOMIC_ACTION_SIGNATURES.copy()
|
|
215
|
+
|
|
191
216
|
open_app_tool = {
|
|
192
217
|
"arguments": ["text"],
|
|
193
218
|
"description": "Open an app by name. Usage example: {\"action\": \"open_app\", \"text\": \"the name of app\"}",
|
|
194
219
|
"function": open_app,
|
|
195
220
|
}
|
|
196
|
-
# Merge with user-provided custom tools
|
|
197
221
|
self.custom_tools = {**self.custom_tools, "open_app": open_app_tool}
|
|
198
222
|
|
|
199
223
|
logger.info("🤖 Initializing DroidAgent...")
|
|
@@ -201,8 +225,9 @@ class DroidAgent(Workflow):
|
|
|
201
225
|
|
|
202
226
|
self.tools_instance = tools
|
|
203
227
|
self.tools_instance.save_trajectories = self.config.logging.save_trajectory
|
|
204
|
-
# Set
|
|
228
|
+
# Set LLMs on tools instance for helper tools
|
|
205
229
|
self.tools_instance.app_opener_llm = self.app_opener_llm
|
|
230
|
+
self.tools_instance.text_manipulator_llm = self.text_manipulator_llm
|
|
206
231
|
|
|
207
232
|
|
|
208
233
|
if self.config.agent.reasoning:
|
|
@@ -289,8 +314,10 @@ class DroidAgent(Workflow):
|
|
|
289
314
|
agent_config=self.config.agent,
|
|
290
315
|
tools_instance=self.tools_instance,
|
|
291
316
|
custom_tools=self.custom_tools,
|
|
317
|
+
atomic_tools=self.atomic_tools,
|
|
292
318
|
debug=self.config.logging.debug,
|
|
293
319
|
shared_state=self.shared_state,
|
|
320
|
+
safe_execution_config=self.config.safe_execution,
|
|
294
321
|
timeout=self.timeout,
|
|
295
322
|
)
|
|
296
323
|
|
|
@@ -356,6 +383,13 @@ class DroidAgent(Workflow):
|
|
|
356
383
|
logger.info(f"🚀 Running DroidAgent to achieve goal: {self.shared_state.instruction}")
|
|
357
384
|
ctx.write_event_to_stream(ev)
|
|
358
385
|
|
|
386
|
+
if not hasattr(self, '_tools_wrapped') and not self.config.agent.reasoning:
|
|
387
|
+
|
|
388
|
+
self.atomic_tools = wrap_async_tools(self.atomic_tools)
|
|
389
|
+
self.custom_tools = wrap_async_tools(self.custom_tools)
|
|
390
|
+
|
|
391
|
+
self._tools_wrapped = True
|
|
392
|
+
logger.debug("✅ Async tools wrapped for synchronous execution contexts")
|
|
359
393
|
|
|
360
394
|
if not self.config.agent.reasoning:
|
|
361
395
|
logger.info(f"🔄 Direct execution mode - executing goal: {self.shared_state.instruction}")
|
|
@@ -416,11 +450,11 @@ class DroidAgent(Workflow):
|
|
|
416
450
|
self,
|
|
417
451
|
ctx: Context,
|
|
418
452
|
ev: ManagerPlanEvent
|
|
419
|
-
) -> ExecutorInputEvent | FinalizeEvent:
|
|
453
|
+
) -> ExecutorInputEvent | ScripterExecutorInputEvent | FinalizeEvent:
|
|
420
454
|
"""
|
|
421
455
|
Process Manager output and decide next step.
|
|
422
456
|
|
|
423
|
-
Checks if task is complete or if Executor should take action.
|
|
457
|
+
Checks if task is complete, if ScripterAgent should run, or if Executor should take action.
|
|
424
458
|
"""
|
|
425
459
|
# Check for answer-type termination
|
|
426
460
|
if ev.manager_answer.strip():
|
|
@@ -432,6 +466,21 @@ class DroidAgent(Workflow):
|
|
|
432
466
|
reason=ev.manager_answer
|
|
433
467
|
)
|
|
434
468
|
|
|
469
|
+
# Check for <script> tag in current_subgoal, then extract from full plan
|
|
470
|
+
if '<script>' in ev.current_subgoal:
|
|
471
|
+
# Found script tag in subgoal - now search the entire plan
|
|
472
|
+
start_idx = ev.plan.find('<script>')
|
|
473
|
+
end_idx = ev.plan.find('</script>')
|
|
474
|
+
|
|
475
|
+
if start_idx != -1 and end_idx != -1 and end_idx > start_idx:
|
|
476
|
+
# Extract content between first <script> and first </script> in plan
|
|
477
|
+
task = ev.plan[start_idx + len('<script>'):end_idx].strip()
|
|
478
|
+
logger.info(f"🐍 Routing to ScripterAgent: {task[:80]}...")
|
|
479
|
+
return ScripterExecutorInputEvent(task=task)
|
|
480
|
+
else:
|
|
481
|
+
# <script> found in subgoal but not properly closed in plan - log warning
|
|
482
|
+
logger.warning("⚠️ Found <script> in subgoal but not properly closed in plan, treating as regular subgoal")
|
|
483
|
+
|
|
435
484
|
# Continue to Executor with current subgoal
|
|
436
485
|
logger.info(f"▶️ Proceeding to Executor with subgoal: {ev.current_subgoal}")
|
|
437
486
|
return ExecutorInputEvent(current_subgoal=ev.current_subgoal)
|
|
@@ -507,7 +556,82 @@ class DroidAgent(Workflow):
|
|
|
507
556
|
return ManagerInputEvent()
|
|
508
557
|
|
|
509
558
|
# ========================================================================
|
|
510
|
-
#
|
|
559
|
+
# Script Executor Workflow Steps
|
|
560
|
+
# ========================================================================
|
|
561
|
+
|
|
562
|
+
@step
|
|
563
|
+
async def run_scripter(
|
|
564
|
+
self,
|
|
565
|
+
ctx: Context,
|
|
566
|
+
ev: ScripterExecutorInputEvent
|
|
567
|
+
) -> ScripterExecutorResultEvent:
|
|
568
|
+
"""
|
|
569
|
+
Instantiate and run ScripterAgent for off-device operations.
|
|
570
|
+
"""
|
|
571
|
+
logger.info(f"🐍 Starting ScripterAgent for task: {ev.task[:2000]}...")
|
|
572
|
+
|
|
573
|
+
# Create fresh ScripterAgent instance for this task
|
|
574
|
+
scripter_agent = ScripterAgent(
|
|
575
|
+
llm=self.scripter_llm,
|
|
576
|
+
agent_config=self.config.agent,
|
|
577
|
+
shared_state=self.shared_state,
|
|
578
|
+
task=ev.task,
|
|
579
|
+
safe_execution_config=self.config.safe_execution,
|
|
580
|
+
timeout=self.timeout
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# Run ScripterAgent workflow
|
|
584
|
+
handler = scripter_agent.run()
|
|
585
|
+
|
|
586
|
+
# Stream nested events
|
|
587
|
+
async for nested_ev in handler.stream_events():
|
|
588
|
+
ctx.write_event_to_stream(nested_ev)
|
|
589
|
+
|
|
590
|
+
result = await handler
|
|
591
|
+
|
|
592
|
+
# Store in shared state
|
|
593
|
+
script_record = {
|
|
594
|
+
'task': ev.task,
|
|
595
|
+
'message': result['message'],
|
|
596
|
+
'success': result['success'],
|
|
597
|
+
'code_executions': result.get('code_executions', 0)
|
|
598
|
+
}
|
|
599
|
+
self.shared_state.scripter_history.append(script_record)
|
|
600
|
+
self.shared_state.last_scripter_message = result['message']
|
|
601
|
+
self.shared_state.last_scripter_success = result['success']
|
|
602
|
+
|
|
603
|
+
logger.info(f"🐍 ScripterAgent finished: {result['message'][:2000]}...")
|
|
604
|
+
|
|
605
|
+
return ScripterExecutorResultEvent(
|
|
606
|
+
task=ev.task,
|
|
607
|
+
message=result['message'],
|
|
608
|
+
success=result['success'],
|
|
609
|
+
code_executions=result.get('code_executions', 0)
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
@step
|
|
613
|
+
async def handle_scripter_result(
|
|
614
|
+
self,
|
|
615
|
+
ctx: Context,
|
|
616
|
+
ev: ScripterExecutorResultEvent
|
|
617
|
+
) -> ManagerInputEvent:
|
|
618
|
+
"""
|
|
619
|
+
Process ScripterAgent result and loop back to Manager.
|
|
620
|
+
"""
|
|
621
|
+
if ev.success:
|
|
622
|
+
logger.info(f"✅ Script completed successfully in {ev.code_executions} steps")
|
|
623
|
+
else:
|
|
624
|
+
logger.warning(f"⚠️ Script failed or reached max steps: {ev.message}")
|
|
625
|
+
|
|
626
|
+
# Increment DroidAgent step counter
|
|
627
|
+
self.shared_state.step_number += 1
|
|
628
|
+
logger.info(f"🔄 Step {self.shared_state.step_number}/{self.config.agent.max_steps} complete, looping to Manager")
|
|
629
|
+
|
|
630
|
+
# Loop back to Manager (script result in shared_state)
|
|
631
|
+
return ManagerInputEvent()
|
|
632
|
+
|
|
633
|
+
# ========================================================================
|
|
634
|
+
# End Manager/Executor/Script Workflow Steps
|
|
511
635
|
# ========================================================================
|
|
512
636
|
|
|
513
637
|
@step
|
|
@@ -518,8 +642,8 @@ class DroidAgent(Workflow):
|
|
|
518
642
|
success=ev.success,
|
|
519
643
|
reason=ev.reason,
|
|
520
644
|
steps=self.shared_state.step_number,
|
|
521
|
-
unique_packages_count=len(self.shared_state.
|
|
522
|
-
unique_activities_count=len(self.shared_state.
|
|
645
|
+
unique_packages_count=len(self.shared_state.visited_packages),
|
|
646
|
+
unique_activities_count=len(self.shared_state.visited_activities),
|
|
523
647
|
),
|
|
524
648
|
self.user_id,
|
|
525
649
|
)
|
|
@@ -60,10 +60,10 @@ class DroidAgentState(BaseModel):
|
|
|
60
60
|
phone_state: Dict = Field(default_factory=dict)
|
|
61
61
|
|
|
62
62
|
# Private fields
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
current_package_name: str = ""
|
|
64
|
+
current_activity_name: str = ""
|
|
65
|
+
visited_packages: set = Field(default_factory=set)
|
|
66
|
+
visited_activities: set = Field(default_factory=set)
|
|
67
67
|
|
|
68
68
|
# Previous device state (for before/after comparison in Manager)
|
|
69
69
|
previous_formatted_device_state: str = ""
|
|
@@ -103,19 +103,14 @@ class DroidAgentState(BaseModel):
|
|
|
103
103
|
error_flag_plan: bool = False
|
|
104
104
|
err_to_manager_thresh: int = 2
|
|
105
105
|
|
|
106
|
+
# Script execution tracking
|
|
107
|
+
scripter_history: List[Dict] = Field(default_factory=list)
|
|
108
|
+
last_scripter_message: str = ""
|
|
109
|
+
last_scripter_success: bool = True
|
|
110
|
+
|
|
106
111
|
# Output
|
|
107
112
|
output_dir: str = ""
|
|
108
113
|
|
|
109
|
-
@property
|
|
110
|
-
def current_package_name(self) -> str:
|
|
111
|
-
"""Get current package name"""
|
|
112
|
-
return self._current_package_name
|
|
113
|
-
|
|
114
|
-
@property
|
|
115
|
-
def current_activity_name(self) -> str:
|
|
116
|
-
"""Get current activity name"""
|
|
117
|
-
return self._current_activity_name
|
|
118
|
-
|
|
119
114
|
def update_current_app(self, package_name: str, activity_name: str):
|
|
120
115
|
"""
|
|
121
116
|
Update package and activity together, capturing telemetry event only once.
|
|
@@ -123,21 +118,21 @@ class DroidAgentState(BaseModel):
|
|
|
123
118
|
This prevents duplicate PackageVisitEvents when both package and activity change.
|
|
124
119
|
"""
|
|
125
120
|
# Check if either changed
|
|
126
|
-
package_changed = package_name != self.
|
|
127
|
-
activity_changed = activity_name != self.
|
|
121
|
+
package_changed = package_name != self.current_package_name
|
|
122
|
+
activity_changed = activity_name != self.current_activity_name
|
|
128
123
|
|
|
129
124
|
if not (package_changed or activity_changed):
|
|
130
125
|
return # No change, nothing to do
|
|
131
126
|
|
|
132
127
|
# Update tracking sets
|
|
133
128
|
if package_changed and package_name:
|
|
134
|
-
self.
|
|
129
|
+
self.visited_packages.add(package_name)
|
|
135
130
|
if activity_changed and activity_name:
|
|
136
|
-
self.
|
|
131
|
+
self.visited_activities.add(activity_name)
|
|
137
132
|
|
|
138
133
|
# Update values
|
|
139
|
-
self.
|
|
140
|
-
self.
|
|
134
|
+
self.current_package_name = package_name
|
|
135
|
+
self.current_activity_name = activity_name
|
|
141
136
|
|
|
142
137
|
# Capture telemetry event for any change
|
|
143
138
|
# This ensures we track when apps close or transitions to empty state occur
|
|
@@ -189,3 +184,24 @@ class ExecutorResultEvent(Event):
|
|
|
189
184
|
outcome: bool
|
|
190
185
|
error: str
|
|
191
186
|
summary: str
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# ============================================================================
|
|
190
|
+
# Script executor coordination events
|
|
191
|
+
# ============================================================================
|
|
192
|
+
|
|
193
|
+
class ScripterExecutorInputEvent(Event):
|
|
194
|
+
"""Trigger ScripterAgent workflow for off-device operations"""
|
|
195
|
+
task: str
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class ScripterExecutorResultEvent(Event):
|
|
199
|
+
"""
|
|
200
|
+
Coordination event from ScripterAgent to DroidAgent.
|
|
201
|
+
|
|
202
|
+
Used for workflow step routing only (NOT streamed to frontend).
|
|
203
|
+
"""
|
|
204
|
+
task: str
|
|
205
|
+
message: str # Response from response() function
|
|
206
|
+
success: bool
|
|
207
|
+
code_executions: int
|
|
@@ -67,7 +67,12 @@ class ExecutorAgent(Workflow):
|
|
|
67
67
|
self.vision = agent_config.executor.vision
|
|
68
68
|
self.tools_instance = tools_instance
|
|
69
69
|
self.shared_state = shared_state
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
# Merge custom_tools with atomic actions (same as CodeActAgent)
|
|
72
|
+
atomic_tools = ATOMIC_ACTION_SIGNATURES
|
|
73
|
+
merged_signatures = {**atomic_tools, **(custom_tools or {})}
|
|
74
|
+
self.all_actions = merged_signatures # Store merged dict for prompt
|
|
75
|
+
self.custom_tools = custom_tools or {} # Keep for execution lookup
|
|
71
76
|
|
|
72
77
|
logger.info("✅ ExecutorAgent initialized successfully.")
|
|
73
78
|
|
|
@@ -120,7 +125,7 @@ class ExecutorAgent(Workflow):
|
|
|
120
125
|
"plan": self.shared_state.plan,
|
|
121
126
|
"subgoal": subgoal,
|
|
122
127
|
"progress_status": self.shared_state.progress_status,
|
|
123
|
-
"atomic_actions":
|
|
128
|
+
"atomic_actions": self.all_actions, # Now includes custom tools!
|
|
124
129
|
"action_history": action_history
|
|
125
130
|
}
|
|
126
131
|
)
|
|
@@ -296,7 +301,7 @@ class ExecutorAgent(Workflow):
|
|
|
296
301
|
if text is None:
|
|
297
302
|
return False, "Missing 'text' parameter", "Failed: open_app requires text"
|
|
298
303
|
|
|
299
|
-
result = open_app(self.tools_instance, text)
|
|
304
|
+
result = await open_app(self.tools_instance, text)
|
|
300
305
|
return True, "None", f"Opened app: {text}"
|
|
301
306
|
|
|
302
307
|
else:
|
|
@@ -161,7 +161,9 @@ class ManagerAgent(Workflow):
|
|
|
161
161
|
"important_notes": "", # TODO: implement
|
|
162
162
|
"error_history": error_history,
|
|
163
163
|
"text_manipulation_enabled": has_text_to_modify,
|
|
164
|
-
"custom_tools_descriptions": build_custom_tool_descriptions(self.custom_tools)
|
|
164
|
+
"custom_tools_descriptions": build_custom_tool_descriptions(self.custom_tools),
|
|
165
|
+
"scripter_execution_enabled": self.agent_config.scripter.enabled,
|
|
166
|
+
"scripter_max_steps": self.agent_config.scripter.max_steps,
|
|
165
167
|
}
|
|
166
168
|
)
|
|
167
169
|
|
|
@@ -219,6 +221,23 @@ class ManagerAgent(Workflow):
|
|
|
219
221
|
if screenshot and self.vision:
|
|
220
222
|
messages[last_user_idx]['content'].append({"image": screenshot})
|
|
221
223
|
|
|
224
|
+
# Add script result if available
|
|
225
|
+
if self.shared_state.last_scripter_message:
|
|
226
|
+
status = "SUCCESS" if self.shared_state.last_scripter_success else "FAILED"
|
|
227
|
+
script_context = (
|
|
228
|
+
f"\n<script_result status=\"{status}\">\n"
|
|
229
|
+
f"{self.shared_state.last_scripter_message}\n"
|
|
230
|
+
f"</script_result>\n"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if messages[last_user_idx]['content'] and 'text' in messages[last_user_idx]['content'][0]:
|
|
234
|
+
messages[last_user_idx]['content'][0]['text'] += script_context
|
|
235
|
+
else:
|
|
236
|
+
messages[last_user_idx]['content'].insert(0, {"text": script_context})
|
|
237
|
+
|
|
238
|
+
# Clear after injection (avoid duplicate injection)
|
|
239
|
+
self.shared_state.last_scripter_message = ""
|
|
240
|
+
|
|
222
241
|
# Add PREVIOUS device state to SECOND-TO-LAST user message (if exists)
|
|
223
242
|
if len(user_indices) >= 2:
|
|
224
243
|
second_last_user_idx = user_indices[-2]
|
|
@@ -17,6 +17,7 @@ def parse_manager_response(response: str) -> dict:
|
|
|
17
17
|
|
|
18
18
|
Also derives:
|
|
19
19
|
- current_subgoal: first line of plan (with list markers removed)
|
|
20
|
+
- If first item is <script> tag, extract script content as current_subgoal
|
|
20
21
|
|
|
21
22
|
Args:
|
|
22
23
|
response: Raw LLM response text
|
|
@@ -26,7 +27,7 @@ def parse_manager_response(response: str) -> dict:
|
|
|
26
27
|
- thought: str
|
|
27
28
|
- memory: str
|
|
28
29
|
- plan: str
|
|
29
|
-
- current_subgoal: str (first line of plan, cleaned)
|
|
30
|
+
- current_subgoal: str (first line of plan, cleaned, or script content)
|
|
30
31
|
- request_accomplished: str (from request_accomplished tag)
|
|
31
32
|
"""
|
|
32
33
|
def extract(tag: str) -> str:
|
|
@@ -42,19 +43,27 @@ def parse_manager_response(response: str) -> dict:
|
|
|
42
43
|
|
|
43
44
|
# Parse current subgoal from first line of plan
|
|
44
45
|
current_goal_text = plan
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
|
|
47
|
+
# Check if first item is a <script> tag
|
|
48
|
+
script_match = re.search(r'^\s*<script>(.*?)</script>', current_goal_text, re.DOTALL)
|
|
49
|
+
|
|
50
|
+
if script_match:
|
|
51
|
+
# Script is first task - extract script content with tag
|
|
52
|
+
current_subgoal = f"<script>{script_match.group(1).strip()}</script>"
|
|
49
53
|
else:
|
|
50
|
-
|
|
54
|
+
# Regular subgoal - use existing logic
|
|
55
|
+
plan_lines = [line.strip() for line in current_goal_text.splitlines() if line.strip()]
|
|
56
|
+
if plan_lines:
|
|
57
|
+
first_line = plan_lines[0]
|
|
58
|
+
else:
|
|
59
|
+
first_line = current_goal_text.strip()
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
# Remove common list markers like "1.", "-", "*", or bullet characters
|
|
62
|
+
first_line = re.sub(r"^\s*\d+\.\s*", "", first_line) # Remove "1. ", "2. ", etc.
|
|
63
|
+
first_line = re.sub(r"^\s*[-*]\s*", "", first_line) # Remove "- " or "* "
|
|
64
|
+
first_line = re.sub(r"^\s*•\s*", "", first_line) # Remove bullet "• "
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
current_subgoal = first_line.strip()
|
|
58
67
|
|
|
59
68
|
return {
|
|
60
69
|
"thought": thought,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Events for ScripterAgent workflow.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
from llama_index.core.workflow import Event
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ScripterInputEvent(Event):
|
|
11
|
+
"""Input to LLM (chat history)."""
|
|
12
|
+
input: List # List of ChatMessages
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ScripterThinkingEvent(Event):
|
|
16
|
+
"""LLM generated thought + code."""
|
|
17
|
+
thoughts: str
|
|
18
|
+
code: Optional[str] = None
|
|
19
|
+
full_response: str = "" # Full LLM response (for fallback when no code)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ScripterExecutionEvent(Event):
|
|
23
|
+
"""Trigger code execution."""
|
|
24
|
+
code: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ScripterExecutionResultEvent(Event):
|
|
28
|
+
"""Code execution result."""
|
|
29
|
+
output: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ScripterEndEvent(Event):
|
|
33
|
+
"""Script agent finished."""
|
|
34
|
+
message: str # Message to Manager
|
|
35
|
+
success: bool # True if response() called, False if max_steps
|
|
36
|
+
code_executions: int = 0
|