droidrun 0.3.10.dev5__py3-none-any.whl → 0.3.10.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- droidrun/agent/codeact/codeact_agent.py +21 -29
- droidrun/agent/context/task_manager.py +0 -1
- droidrun/agent/droid/droid_agent.py +1 -3
- droidrun/agent/droid/events.py +6 -3
- droidrun/agent/executor/executor_agent.py +24 -38
- droidrun/agent/executor/prompts.py +0 -108
- droidrun/agent/manager/__init__.py +1 -1
- droidrun/agent/manager/manager_agent.py +104 -87
- droidrun/agent/utils/executer.py +11 -10
- droidrun/agent/utils/llm_picker.py +63 -1
- droidrun/agent/utils/tools.py +30 -1
- droidrun/app_cards/app_card_provider.py +26 -0
- droidrun/app_cards/providers/__init__.py +7 -0
- droidrun/app_cards/providers/composite_provider.py +97 -0
- droidrun/app_cards/providers/local_provider.py +115 -0
- droidrun/app_cards/providers/server_provider.py +126 -0
- droidrun/cli/logs.py +4 -4
- droidrun/cli/main.py +244 -34
- droidrun/config_manager/__init__.py +0 -2
- droidrun/config_manager/config_manager.py +45 -102
- droidrun/config_manager/path_resolver.py +1 -1
- droidrun/config_manager/prompt_loader.py +48 -51
- droidrun/macro/cli.py +0 -1
- droidrun/portal.py +17 -0
- droidrun/tools/adb.py +13 -34
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/METADATA +2 -9
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/RECORD +30 -26
- droidrun/config_manager/app_card_loader.py +0 -148
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/WHEEL +0 -0
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/entry_points.txt +0 -0
- {droidrun-0.3.10.dev5.dist-info → droidrun-0.3.10.dev7.dist-info}/licenses/LICENSE +0 -0
droidrun/cli/main.py
CHANGED
@@ -8,22 +8,22 @@ import os
|
|
8
8
|
import warnings
|
9
9
|
from contextlib import nullcontext
|
10
10
|
from functools import wraps
|
11
|
-
from pathlib import Path
|
12
11
|
|
13
12
|
import click
|
14
13
|
from adbutils import adb
|
15
14
|
from rich.console import Console
|
16
15
|
|
17
16
|
from droidrun.agent.droid import DroidAgent
|
18
|
-
from droidrun.agent.utils.llm_picker import load_llm
|
17
|
+
from droidrun.agent.utils.llm_picker import load_llm, load_llms_from_profiles
|
19
18
|
from droidrun.cli.logs import LogHandler
|
19
|
+
from droidrun.config_manager import ConfigManager
|
20
20
|
from droidrun.config_manager.config_manager import (
|
21
21
|
AgentConfig,
|
22
22
|
CodeActConfig,
|
23
|
-
ManagerConfig,
|
24
|
-
ExecutorConfig,
|
25
23
|
DeviceConfig,
|
24
|
+
ExecutorConfig,
|
26
25
|
LoggingConfig,
|
26
|
+
ManagerConfig,
|
27
27
|
ToolsConfig,
|
28
28
|
TracingConfig,
|
29
29
|
)
|
@@ -38,8 +38,6 @@ from droidrun.portal import (
|
|
38
38
|
)
|
39
39
|
from droidrun.telemetry import print_telemetry_message
|
40
40
|
from droidrun.tools import AdbTools, IOSTools
|
41
|
-
from droidrun.config_manager import ConfigManager
|
42
|
-
|
43
41
|
|
44
42
|
# Suppress all warnings
|
45
43
|
warnings.filterwarnings("ignore")
|
@@ -240,7 +238,7 @@ async def run_command(
|
|
240
238
|
if temperature is not None:
|
241
239
|
overrides = {name: {'temperature': temperature} for name in profile_names}
|
242
240
|
|
243
|
-
llms = config.
|
241
|
+
llms = load_llms_from_profiles(config.llm_profiles, profile_names=profile_names, **overrides)
|
244
242
|
logger.info(f"🧠 Loaded {len(llms)} agent-specific LLMs from profiles")
|
245
243
|
|
246
244
|
# ================================================================
|
@@ -532,29 +530,43 @@ def run(
|
|
532
530
|
):
|
533
531
|
"""Run a command on your Android device using natural language."""
|
534
532
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
533
|
+
try:
|
534
|
+
run_command(
|
535
|
+
command,
|
536
|
+
config,
|
537
|
+
device,
|
538
|
+
provider,
|
539
|
+
model,
|
540
|
+
steps,
|
541
|
+
base_url,
|
542
|
+
api_base,
|
543
|
+
vision,
|
544
|
+
manager_vision,
|
545
|
+
executor_vision,
|
546
|
+
codeact_vision,
|
547
|
+
reasoning,
|
548
|
+
tracing,
|
549
|
+
debug,
|
550
|
+
use_tcp,
|
551
|
+
temperature=temperature,
|
552
|
+
save_trajectory=save_trajectory,
|
553
|
+
allow_drag=allow_drag,
|
554
|
+
ios=ios if ios is not None else False,
|
555
|
+
)
|
556
|
+
finally:
|
557
|
+
# Disable DroidRun keyboard after execution
|
558
|
+
try:
|
559
|
+
if not (ios if ios is not None else False):
|
560
|
+
device_serial = adb.device().serial
|
561
|
+
if device_serial:
|
562
|
+
tools = AdbTools(serial=device, use_tcp=use_tcp if use_tcp is not None else False)
|
563
|
+
if hasattr(tools, 'device') and tools.device:
|
564
|
+
tools.device.shell("ime disable com.droidrun.portal/.DroidrunKeyboardIME")
|
565
|
+
click.echo("DroidRun keyboard disabled successfully")
|
566
|
+
# Cleanup tools
|
567
|
+
del tools
|
568
|
+
except Exception as disable_e:
|
569
|
+
click.echo(f"Warning: Failed to disable DroidRun keyboard: {disable_e}")
|
558
570
|
|
559
571
|
|
560
572
|
@cli.command()
|
@@ -756,8 +768,206 @@ def ping(device: str | None, use_tcp: bool, debug: bool):
|
|
756
768
|
cli.add_command(macro_cli, name="macro")
|
757
769
|
|
758
770
|
|
771
|
+
async def test(command: str):
|
772
|
+
config = ConfigManager(path="config.yaml")
|
773
|
+
# Initialize logging first (use config default if debug not specified)
|
774
|
+
debug_mode = debug if debug is not None else config.logging.debug
|
775
|
+
log_handler = configure_logging(command, debug_mode, config.logging.rich_text)
|
776
|
+
logger = logging.getLogger("droidrun")
|
777
|
+
|
778
|
+
log_handler.update_step("Initializing...")
|
779
|
+
|
780
|
+
with log_handler.render():
|
781
|
+
try:
|
782
|
+
logger.info(f"🚀 Starting: {command}")
|
783
|
+
print_telemetry_message()
|
784
|
+
|
785
|
+
# ================================================================
|
786
|
+
# STEP 1: Build config objects with CLI overrides
|
787
|
+
# ================================================================
|
788
|
+
|
789
|
+
# Build agent-specific configs with vision overrides
|
790
|
+
if vision is not None:
|
791
|
+
# --vision flag overrides all agents
|
792
|
+
manager_vision_val = vision
|
793
|
+
executor_vision_val = vision
|
794
|
+
codeact_vision_val = vision
|
795
|
+
logger.debug(f"CLI override: vision={vision} (all agents)")
|
796
|
+
else:
|
797
|
+
# Use individual overrides or config defaults
|
798
|
+
manager_vision_val = config.agent.manager.vision
|
799
|
+
executor_vision_val = config.agent.executor.vision
|
800
|
+
codeact_vision_val = config.agent.codeact.vision
|
801
|
+
|
802
|
+
manager_cfg = ManagerConfig(
|
803
|
+
vision=manager_vision_val,
|
804
|
+
system_prompt="rev1.jinja2"
|
805
|
+
)
|
806
|
+
|
807
|
+
executor_cfg = ExecutorConfig(
|
808
|
+
vision=executor_vision_val,
|
809
|
+
system_prompt="rev1.jinja2"
|
810
|
+
)
|
811
|
+
|
812
|
+
codeact_cfg = CodeActConfig(
|
813
|
+
vision=codeact_vision_val,
|
814
|
+
system_prompt=config.agent.codeact.system_prompt,
|
815
|
+
user_prompt=config.agent.codeact.user_prompt
|
816
|
+
)
|
817
|
+
|
818
|
+
agent_cfg = AgentConfig(
|
819
|
+
max_steps=steps if steps is not None else config.agent.max_steps,
|
820
|
+
reasoning=reasoning if reasoning is not None else config.agent.reasoning,
|
821
|
+
after_sleep_action=config.agent.after_sleep_action,
|
822
|
+
wait_for_stable_ui=config.agent.wait_for_stable_ui,
|
823
|
+
prompts_dir=config.agent.prompts_dir,
|
824
|
+
manager=manager_cfg,
|
825
|
+
executor=executor_cfg,
|
826
|
+
codeact=codeact_cfg,
|
827
|
+
app_cards=config.agent.app_cards,
|
828
|
+
)
|
829
|
+
|
830
|
+
device_cfg = DeviceConfig(
|
831
|
+
serial=device if device is not None else config.device.serial,
|
832
|
+
use_tcp=use_tcp if use_tcp is not None else config.device.use_tcp,
|
833
|
+
)
|
834
|
+
|
835
|
+
tools_cfg = ToolsConfig(
|
836
|
+
allow_drag=allow_drag if allow_drag is not None else config.tools.allow_drag,
|
837
|
+
)
|
838
|
+
|
839
|
+
logging_cfg = LoggingConfig(
|
840
|
+
debug=debug if debug is not None else config.logging.debug,
|
841
|
+
save_trajectory=save_trajectory if save_trajectory is not None else config.logging.save_trajectory,
|
842
|
+
rich_text=config.logging.rich_text,
|
843
|
+
)
|
844
|
+
|
845
|
+
tracing_cfg = TracingConfig(
|
846
|
+
enabled=tracing if tracing is not None else config.tracing.enabled,
|
847
|
+
)
|
848
|
+
|
849
|
+
# ================================================================
|
850
|
+
# STEP 3: Load LLMs
|
851
|
+
# ================================================================
|
852
|
+
|
853
|
+
log_handler.update_step("Loading LLMs...")
|
854
|
+
|
855
|
+
# No custom provider/model - use profiles from config
|
856
|
+
logger.info("📋 Loading LLMs from config profiles...")
|
857
|
+
|
858
|
+
profile_names = ['manager', 'executor', 'codeact', 'text_manipulator', 'app_opener']
|
859
|
+
|
860
|
+
# Apply temperature override to all profiles if specified
|
861
|
+
overrides = {}
|
862
|
+
if temperature is not None:
|
863
|
+
overrides = {name: {'temperature': temperature} for name in profile_names}
|
864
|
+
|
865
|
+
llms = load_llms_from_profiles(config.llm_profiles, profile_names=profile_names, **overrides)
|
866
|
+
logger.info(f"🧠 Loaded {len(llms)} agent-specific LLMs from profiles")
|
867
|
+
|
868
|
+
# ================================================================
|
869
|
+
# STEP 4: Setup device and tools
|
870
|
+
# ================================================================
|
871
|
+
|
872
|
+
log_handler.update_step("Setting up tools...")
|
873
|
+
|
874
|
+
device_serial = device_cfg.serial
|
875
|
+
if device_serial is None and not ios:
|
876
|
+
logger.info("🔍 Finding connected device...")
|
877
|
+
devices = adb.list()
|
878
|
+
if not devices:
|
879
|
+
raise ValueError("No connected devices found.")
|
880
|
+
device_serial = devices[0].serial
|
881
|
+
device_cfg = DeviceConfig(serial=device_serial, use_tcp=device_cfg.use_tcp)
|
882
|
+
logger.info(f"📱 Using device: {device_serial}")
|
883
|
+
elif device_serial is None and ios:
|
884
|
+
raise ValueError("iOS device not specified. Please specify device base url via --device")
|
885
|
+
else:
|
886
|
+
logger.info(f"📱 Using device: {device_serial}")
|
887
|
+
|
888
|
+
tools = (
|
889
|
+
AdbTools(
|
890
|
+
serial=device_serial,
|
891
|
+
use_tcp=device_cfg.use_tcp,
|
892
|
+
app_opener_llm=llms.get('app_opener'),
|
893
|
+
text_manipulator_llm=llms.get('text_manipulator')
|
894
|
+
)
|
895
|
+
if not ios
|
896
|
+
else IOSTools(url=device_serial)
|
897
|
+
)
|
898
|
+
|
899
|
+
excluded_tools = [] if tools_cfg.allow_drag else ["drag"]
|
900
|
+
|
901
|
+
# ================================================================
|
902
|
+
# STEP 5: Initialize DroidAgent with all settings
|
903
|
+
# ================================================================
|
904
|
+
|
905
|
+
log_handler.update_step("Initializing DroidAgent...")
|
906
|
+
|
907
|
+
mode = "planning with reasoning" if agent_cfg.reasoning else "direct execution"
|
908
|
+
logger.info(f"🤖 Agent mode: {mode}")
|
909
|
+
logger.info(f"👁️ Vision settings: Manager={agent_cfg.manager.vision}, "
|
910
|
+
f"Executor={agent_cfg.executor.vision}, CodeAct={agent_cfg.codeact.vision}")
|
911
|
+
|
912
|
+
if tracing_cfg.enabled:
|
913
|
+
logger.info("🔍 Tracing enabled")
|
914
|
+
|
915
|
+
droid_agent = DroidAgent(
|
916
|
+
goal=command,
|
917
|
+
llms=llms,
|
918
|
+
tools=tools,
|
919
|
+
config=config,
|
920
|
+
agent_config=agent_cfg,
|
921
|
+
device_config=device_cfg,
|
922
|
+
tools_config=tools_cfg,
|
923
|
+
logging_config=logging_cfg,
|
924
|
+
tracing_config=tracing_cfg,
|
925
|
+
excluded_tools=excluded_tools,
|
926
|
+
timeout=1000,
|
927
|
+
)
|
928
|
+
|
929
|
+
# ================================================================
|
930
|
+
# STEP 6: Run agent
|
931
|
+
# ================================================================
|
932
|
+
|
933
|
+
logger.info("▶️ Starting agent execution...")
|
934
|
+
logger.info("Press Ctrl+C to stop")
|
935
|
+
log_handler.update_step("Running agent...")
|
936
|
+
|
937
|
+
try:
|
938
|
+
handler = droid_agent.run()
|
939
|
+
|
940
|
+
async for event in handler.stream_events():
|
941
|
+
log_handler.handle_event(event)
|
942
|
+
result = await handler # noqa: F841
|
943
|
+
|
944
|
+
except KeyboardInterrupt:
|
945
|
+
log_handler.is_completed = True
|
946
|
+
log_handler.is_success = False
|
947
|
+
log_handler.current_step = "Stopped by user"
|
948
|
+
logger.info("⏹️ Stopped by user")
|
949
|
+
|
950
|
+
except Exception as e:
|
951
|
+
log_handler.is_completed = True
|
952
|
+
log_handler.is_success = False
|
953
|
+
log_handler.current_step = f"Error: {e}"
|
954
|
+
logger.error(f"💥 Error: {e}")
|
955
|
+
if logging_cfg.debug:
|
956
|
+
import traceback
|
957
|
+
logger.debug(traceback.format_exc())
|
958
|
+
|
959
|
+
except Exception as e:
|
960
|
+
log_handler.current_step = f"Error: {e}"
|
961
|
+
logger.error(f"💥 Setup error: {e}")
|
962
|
+
debug_mode = debug if debug is not None else config.logging.debug
|
963
|
+
if debug_mode:
|
964
|
+
import traceback
|
965
|
+
logger.debug(traceback.format_exc())
|
966
|
+
|
967
|
+
|
968
|
+
|
759
969
|
if __name__ == "__main__":
|
760
|
-
command = "
|
970
|
+
command = "set gboard to the default keyboard"
|
761
971
|
device = None
|
762
972
|
provider = "GoogleGenAI"
|
763
973
|
model = "models/gemini-2.5-flash"
|
@@ -765,7 +975,7 @@ if __name__ == "__main__":
|
|
765
975
|
api_key = os.getenv("GOOGLE_API_KEY")
|
766
976
|
steps = 15
|
767
977
|
vision = True
|
768
|
-
reasoning =
|
978
|
+
reasoning = False
|
769
979
|
tracing = True
|
770
980
|
debug = True
|
771
981
|
use_tcp = False
|
@@ -774,6 +984,6 @@ if __name__ == "__main__":
|
|
774
984
|
ios = False
|
775
985
|
save_trajectory = "none"
|
776
986
|
allow_drag = False
|
777
|
-
|
778
|
-
command
|
987
|
+
asyncio.run(
|
988
|
+
test(command)
|
779
989
|
)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from droidrun.config_manager.app_card_loader import AppCardLoader
|
2
1
|
from droidrun.config_manager.config_manager import (
|
3
2
|
AgentConfig,
|
4
3
|
AppCardConfig,
|
@@ -23,5 +22,4 @@ __all__ = [
|
|
23
22
|
"TracingConfig",
|
24
23
|
"LoggingConfig",
|
25
24
|
"ToolsConfig",
|
26
|
-
"AppCardLoader",
|
27
25
|
]
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
3
3
|
import os
|
4
4
|
import threading
|
5
5
|
from dataclasses import asdict, dataclass, field
|
6
|
-
from pathlib import Path
|
7
6
|
from typing import Any, Callable, Dict, List, Optional
|
8
7
|
|
9
8
|
import yaml
|
@@ -35,30 +34,38 @@ agent:
|
|
35
34
|
# Enable vision capabilities (screenshots)
|
36
35
|
vision: false
|
37
36
|
# System prompt filename (located in prompts_dir/codeact/)
|
38
|
-
system_prompt: system.
|
37
|
+
system_prompt: system.jinja2
|
39
38
|
# User prompt filename (located in prompts_dir/codeact/)
|
40
|
-
user_prompt: user.
|
39
|
+
user_prompt: user.jinja2
|
41
40
|
|
42
41
|
# Manager Agent Configuration
|
43
42
|
manager:
|
44
43
|
# Enable vision capabilities (screenshots)
|
45
44
|
vision: false
|
46
45
|
# System prompt filename (located in prompts_dir/manager/)
|
47
|
-
system_prompt: system.
|
46
|
+
system_prompt: system.jinja2
|
48
47
|
|
49
48
|
# Executor Agent Configuration
|
50
49
|
executor:
|
51
50
|
# Enable vision capabilities (screenshots)
|
52
51
|
vision: false
|
53
52
|
# System prompt filename (located in prompts_dir/executor/)
|
54
|
-
system_prompt: system.
|
53
|
+
system_prompt: system.jinja2
|
55
54
|
|
56
55
|
# App Cards Configuration
|
57
56
|
app_cards:
|
58
57
|
# Enable app-specific instruction cards
|
59
58
|
enabled: true
|
60
|
-
#
|
59
|
+
# Mode: local (file-based), server (HTTP API), or composite (server with local fallback)
|
60
|
+
mode: local
|
61
|
+
# Directory containing app card files (for local/composite modes)
|
61
62
|
app_cards_dir: config/app_cards
|
63
|
+
# Server URL for remote app cards (for server/composite modes)
|
64
|
+
server_url: null
|
65
|
+
# Server request timeout in seconds
|
66
|
+
server_timeout: 2.0
|
67
|
+
# Number of server retry attempts
|
68
|
+
server_max_retries: 2
|
62
69
|
|
63
70
|
# === LLM Profiles ===
|
64
71
|
# Define LLM configurations for each agent type
|
@@ -170,29 +177,33 @@ class LLMProfile:
|
|
170
177
|
class CodeActConfig:
|
171
178
|
"""CodeAct agent configuration."""
|
172
179
|
vision: bool = False
|
173
|
-
system_prompt: str = "system.
|
174
|
-
user_prompt: str = "user.
|
180
|
+
system_prompt: str = "system.jinja2"
|
181
|
+
user_prompt: str = "user.jinja2"
|
175
182
|
|
176
183
|
|
177
184
|
@dataclass
|
178
185
|
class ManagerConfig:
|
179
186
|
"""Manager agent configuration."""
|
180
187
|
vision: bool = False
|
181
|
-
system_prompt: str = "system.
|
188
|
+
system_prompt: str = "system.jinja2"
|
182
189
|
|
183
190
|
|
184
191
|
@dataclass
|
185
192
|
class ExecutorConfig:
|
186
193
|
"""Executor agent configuration."""
|
187
194
|
vision: bool = False
|
188
|
-
system_prompt: str = "system.
|
195
|
+
system_prompt: str = "system.jinja2"
|
189
196
|
|
190
197
|
|
191
198
|
@dataclass
|
192
199
|
class AppCardConfig:
|
193
200
|
"""App card configuration."""
|
194
201
|
enabled: bool = True
|
202
|
+
mode: str = "local" # local | server | composite
|
195
203
|
app_cards_dir: str = "config/app_cards"
|
204
|
+
server_url: Optional[str] = None
|
205
|
+
server_timeout: float = 2.0
|
206
|
+
server_max_retries: int = 2
|
196
207
|
|
197
208
|
|
198
209
|
@dataclass
|
@@ -210,20 +221,24 @@ class AgentConfig:
|
|
210
221
|
app_cards: AppCardConfig = field(default_factory=AppCardConfig)
|
211
222
|
|
212
223
|
def get_codeact_system_prompt_path(self) -> str:
|
213
|
-
"""Get
|
214
|
-
|
224
|
+
"""Get resolved absolute path to CodeAct system prompt."""
|
225
|
+
path = f"{self.prompts_dir}/codeact/{self.codeact.system_prompt}"
|
226
|
+
return str(PathResolver.resolve(path, must_exist=True))
|
215
227
|
|
216
228
|
def get_codeact_user_prompt_path(self) -> str:
|
217
|
-
"""Get
|
218
|
-
|
229
|
+
"""Get resolved absolute path to CodeAct user prompt."""
|
230
|
+
path = f"{self.prompts_dir}/codeact/{self.codeact.user_prompt}"
|
231
|
+
return str(PathResolver.resolve(path, must_exist=True))
|
219
232
|
|
220
233
|
def get_manager_system_prompt_path(self) -> str:
|
221
|
-
"""Get
|
222
|
-
|
234
|
+
"""Get resolved absolute path to Manager system prompt."""
|
235
|
+
path = f"{self.prompts_dir}/manager/{self.manager.system_prompt}"
|
236
|
+
return str(PathResolver.resolve(path, must_exist=True))
|
223
237
|
|
224
238
|
def get_executor_system_prompt_path(self) -> str:
|
225
|
-
"""Get
|
226
|
-
|
239
|
+
"""Get resolved absolute path to Executor system prompt."""
|
240
|
+
path = f"{self.prompts_dir}/executor/{self.executor.system_prompt}"
|
241
|
+
return str(PathResolver.resolve(path, must_exist=True))
|
227
242
|
|
228
243
|
|
229
244
|
@dataclass
|
@@ -372,6 +387,7 @@ class ConfigManager:
|
|
372
387
|
|
373
388
|
Usage:
|
374
389
|
from droidrun.config_manager.config_manager import ConfigManager
|
390
|
+
from droidrun.agent.utils.llm_picker import load_llms_from_profiles
|
375
391
|
|
376
392
|
# Create config instance (singleton pattern)
|
377
393
|
config = ConfigManager()
|
@@ -379,12 +395,19 @@ class ConfigManager:
|
|
379
395
|
# Access typed config objects
|
380
396
|
print(config.agent.max_steps)
|
381
397
|
|
382
|
-
# Load all LLMs
|
383
|
-
llms = config.
|
398
|
+
# Load all LLMs from profiles
|
399
|
+
llms = load_llms_from_profiles(config.llm_profiles)
|
384
400
|
manager_llm = llms['manager']
|
385
401
|
executor_llm = llms['executor']
|
386
402
|
codeact_llm = llms['codeact']
|
387
403
|
|
404
|
+
# Load specific profiles with overrides
|
405
|
+
llms = load_llms_from_profiles(
|
406
|
+
config.llm_profiles,
|
407
|
+
profile_names=['manager', 'executor'],
|
408
|
+
manager={'temperature': 0.1}
|
409
|
+
)
|
410
|
+
|
388
411
|
# Modify and save
|
389
412
|
config.save()
|
390
413
|
"""
|
@@ -494,86 +517,6 @@ class ConfigManager:
|
|
494
517
|
|
495
518
|
return self._config.llm_profiles[profile_name]
|
496
519
|
|
497
|
-
def load_llm_from_profile(self, profile_name: str, **override_kwargs):
|
498
|
-
"""
|
499
|
-
Load an LLM using a profile configuration.
|
500
|
-
|
501
|
-
Args:
|
502
|
-
profile_name: Name of the profile to use (fast, mid, smart, custom)
|
503
|
-
**override_kwargs: Additional kwargs to override profile settings
|
504
|
-
|
505
|
-
Returns:
|
506
|
-
Initialized LLM instance
|
507
|
-
|
508
|
-
Example:
|
509
|
-
# Use specific profile
|
510
|
-
llm = config.load_llm_from_profile("smart")
|
511
|
-
|
512
|
-
# Override specific settings
|
513
|
-
llm = config.load_llm_from_profile("fast", temperature=0.5)
|
514
|
-
"""
|
515
|
-
from droidrun.agent.utils.llm_picker import load_llm
|
516
|
-
|
517
|
-
profile = self.get_llm_profile(profile_name)
|
518
|
-
|
519
|
-
# Get kwargs from profile
|
520
|
-
kwargs = profile.to_load_llm_kwargs()
|
521
|
-
|
522
|
-
# Override with any provided kwargs
|
523
|
-
kwargs.update(override_kwargs)
|
524
|
-
|
525
|
-
# Load the LLM
|
526
|
-
return load_llm(provider_name=profile.provider, **kwargs)
|
527
|
-
|
528
|
-
def load_all_llms(self, profile_names: Optional[list[str]] = None, **override_kwargs_per_profile):
|
529
|
-
"""
|
530
|
-
Load multiple LLMs from profiles for different use cases.
|
531
|
-
|
532
|
-
Args:
|
533
|
-
profile_names: List of profile names to load. If None, loads agent-specific profiles
|
534
|
-
**override_kwargs_per_profile: Dict of profile-specific overrides
|
535
|
-
Example: manager={'temperature': 0.1}, executor={'max_tokens': 8000}
|
536
|
-
|
537
|
-
Returns:
|
538
|
-
Dict mapping profile names to initialized LLM instances
|
539
|
-
|
540
|
-
Example:
|
541
|
-
# Load all agent-specific profiles
|
542
|
-
llms = config.load_all_llms()
|
543
|
-
manager_llm = llms['manager']
|
544
|
-
executor_llm = llms['executor']
|
545
|
-
codeact_llm = llms['codeact']
|
546
|
-
|
547
|
-
# Load specific profiles
|
548
|
-
llms = config.load_all_llms(['manager', 'executor'])
|
549
|
-
|
550
|
-
# Load with overrides
|
551
|
-
llms = config.load_all_llms(
|
552
|
-
manager={'temperature': 0.1},
|
553
|
-
executor={'max_tokens': 8000}
|
554
|
-
)
|
555
|
-
"""
|
556
|
-
from droidrun.agent.utils.llm_picker import load_llm
|
557
|
-
|
558
|
-
if profile_names is None:
|
559
|
-
profile_names = ["manager", "executor", "codeact", "text_manipulator", "app_opener"]
|
560
|
-
|
561
|
-
llms = {}
|
562
|
-
for profile_name in profile_names:
|
563
|
-
profile = self.get_llm_profile(profile_name)
|
564
|
-
|
565
|
-
# Get kwargs from profile
|
566
|
-
kwargs = profile.to_load_llm_kwargs()
|
567
|
-
|
568
|
-
# Apply profile-specific overrides if provided
|
569
|
-
if profile_name in override_kwargs_per_profile:
|
570
|
-
kwargs.update(override_kwargs_per_profile[profile_name])
|
571
|
-
|
572
|
-
# Load the LLM
|
573
|
-
llms[profile_name] = load_llm(provider_name=profile.provider, **kwargs)
|
574
|
-
|
575
|
-
return llms
|
576
|
-
|
577
520
|
# ---------------- I/O ----------------
|
578
521
|
def _ensure_file_exists(self) -> None:
|
579
522
|
parent = self.path.parent
|
@@ -653,7 +596,7 @@ class ConfigManager:
|
|
653
596
|
|
654
597
|
Example:
|
655
598
|
>>> config.list_available_prompts("manager")
|
656
|
-
['system.
|
599
|
+
['system.jinja2', 'experimental.jinja2', 'minimal.jinja2']
|
657
600
|
"""
|
658
601
|
agent_type = agent_type.lower()
|
659
602
|
if agent_type not in ["codeact", "manager", "executor"]:
|
@@ -667,7 +610,7 @@ class ConfigManager:
|
|
667
610
|
return []
|
668
611
|
|
669
612
|
# List all .md files in the directory
|
670
|
-
return sorted([f.name for f in prompts_dir.glob("*.
|
613
|
+
return sorted([f.name for f in prompts_dir.glob("*.jinja2")])
|
671
614
|
|
672
615
|
# useful for tests to reset singleton state
|
673
616
|
@classmethod
|
@@ -64,7 +64,7 @@ class PathResolver:
|
|
64
64
|
output_dir = PathResolver.resolve("trajectories", create_if_missing=True)
|
65
65
|
|
66
66
|
# Loading prompts (must exist, checks both locations)
|
67
|
-
prompt = PathResolver.resolve("config/prompts/system.
|
67
|
+
prompt = PathResolver.resolve("config/prompts/system.jinja2", must_exist=True)
|
68
68
|
|
69
69
|
# Absolute path (used as-is)
|
70
70
|
abs_path = PathResolver.resolve("/tmp/output")
|