harmonyrun 0.4.9__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.
Files changed (309) hide show
  1. harmonyrun/__init__.py +186 -0
  2. harmonyrun/__main__.py +8 -0
  3. harmonyrun/agent/__init__.py +5 -0
  4. harmonyrun/agent/events/__init__.py +18 -0
  5. harmonyrun/agent/events/_render.py +258 -0
  6. harmonyrun/agent/events/handler.py +36 -0
  7. harmonyrun/agent/events/render_registry.py +41 -0
  8. harmonyrun/agent/execution/__init__.py +27 -0
  9. harmonyrun/agent/execution/anti_loop.py +410 -0
  10. harmonyrun/agent/execution/base_agent.py +991 -0
  11. harmonyrun/agent/execution/failure_classifier.py +332 -0
  12. harmonyrun/agent/execution/formatting.py +23 -0
  13. harmonyrun/agent/execution/handle.py +124 -0
  14. harmonyrun/agent/execution/interventions.py +89 -0
  15. harmonyrun/agent/execution/thresholds.py +99 -0
  16. harmonyrun/agent/fast_agent/__init__.py +3 -0
  17. harmonyrun/agent/fast_agent/fast_agent.py +972 -0
  18. harmonyrun/agent/harmony/__init__.py +29 -0
  19. harmonyrun/agent/harmony/harmony_agent.py +1413 -0
  20. harmonyrun/agent/harmony/resources.py +10 -0
  21. harmonyrun/agent/harmony/services.py +358 -0
  22. harmonyrun/agent/llm/__init__.py +70 -0
  23. harmonyrun/agent/llm/cache.py +72 -0
  24. harmonyrun/agent/llm/inference.py +359 -0
  25. harmonyrun/agent/llm/introspect.py +36 -0
  26. harmonyrun/agent/llm/loader.py +274 -0
  27. harmonyrun/agent/llm/messages.py +144 -0
  28. harmonyrun/agent/llm/picker.py +253 -0
  29. harmonyrun/agent/llm/usage.py +203 -0
  30. harmonyrun/agent/manager/__init__.py +9 -0
  31. harmonyrun/agent/manager/base_manager.py +215 -0
  32. harmonyrun/agent/manager/executor_agent.py +409 -0
  33. harmonyrun/agent/manager/manager_agent.py +487 -0
  34. harmonyrun/agent/memory/__init__.py +56 -0
  35. harmonyrun/agent/memory/distiller.py +164 -0
  36. harmonyrun/agent/memory/keys.py +21 -0
  37. harmonyrun/agent/memory/models.py +108 -0
  38. harmonyrun/agent/memory/recall.py +39 -0
  39. harmonyrun/agent/memory/store.py +158 -0
  40. harmonyrun/agent/oneflows/__init__.py +11 -0
  41. harmonyrun/agent/oneflows/app_matcher.py +85 -0
  42. harmonyrun/agent/oneflows/app_starter_workflow.py +177 -0
  43. harmonyrun/agent/oneflows/structured_output_agent.py +80 -0
  44. harmonyrun/agent/prompt/__init__.py +114 -0
  45. harmonyrun/agent/prompt/_env.py +45 -0
  46. harmonyrun/agent/prompt/constants.py +60 -0
  47. harmonyrun/agent/prompt/packing.py +367 -0
  48. harmonyrun/agent/prompt/resolver.py +68 -0
  49. harmonyrun/agent/prompt/state_user.py +402 -0
  50. harmonyrun/agent/prompt/system/__init__.py +27 -0
  51. harmonyrun/agent/prompt/system/executor.py +44 -0
  52. harmonyrun/agent/prompt/system/fast_agent.py +64 -0
  53. harmonyrun/agent/prompt/system/manager.py +194 -0
  54. harmonyrun/agent/prompt/templates/executor/README.md +39 -0
  55. harmonyrun/agent/prompt/templates/executor/system.en.j2 +63 -0
  56. harmonyrun/agent/prompt/templates/executor/system.zh.j2 +63 -0
  57. harmonyrun/agent/prompt/templates/executor/user.en.j2 +75 -0
  58. harmonyrun/agent/prompt/templates/executor/user.zh.j2 +75 -0
  59. harmonyrun/agent/prompt/templates/fast_agent/README.md +53 -0
  60. harmonyrun/agent/prompt/templates/fast_agent/system.en.j2 +157 -0
  61. harmonyrun/agent/prompt/templates/fast_agent/system.zh.j2 +156 -0
  62. harmonyrun/agent/prompt/templates/manager/README.md +26 -0
  63. harmonyrun/agent/prompt/templates/manager/system.en.j2 +164 -0
  64. harmonyrun/agent/prompt/templates/manager/system.zh.j2 +164 -0
  65. harmonyrun/agent/prompt/user_blocks/__init__.py +53 -0
  66. harmonyrun/agent/prompt/user_blocks/delta_trail.py +182 -0
  67. harmonyrun/agent/prompt/user_blocks/device_state.py +306 -0
  68. harmonyrun/agent/prompt/user_blocks/executor_user.py +57 -0
  69. harmonyrun/agent/prompt/user_blocks/goal.py +142 -0
  70. harmonyrun/agent/prompt/user_blocks/history.py +162 -0
  71. harmonyrun/agent/prompt/user_blocks/labels.py +24 -0
  72. harmonyrun/agent/prompt/user_blocks/next_step.py +32 -0
  73. harmonyrun/agent/prompt/user_blocks/task_plan.py +50 -0
  74. harmonyrun/agent/state/__init__.py +72 -0
  75. harmonyrun/agent/state/flow_states.py +85 -0
  76. harmonyrun/agent/state/observations.py +202 -0
  77. harmonyrun/agent/state/state.py +402 -0
  78. harmonyrun/agent/state/state_components.py +204 -0
  79. harmonyrun/agent/tools/__init__.py +49 -0
  80. harmonyrun/agent/tools/actions.py +653 -0
  81. harmonyrun/agent/tools/context.py +44 -0
  82. harmonyrun/agent/tools/dispatcher.py +85 -0
  83. harmonyrun/agent/tools/gestures.py +120 -0
  84. harmonyrun/agent/tools/registry.py +501 -0
  85. harmonyrun/agent/tools/result.py +16 -0
  86. harmonyrun/agent/tools/schemas.py +276 -0
  87. harmonyrun/app_cards/__init__.py +55 -0
  88. harmonyrun/app_cards/app_card_provider.py +26 -0
  89. harmonyrun/app_cards/loading.py +69 -0
  90. harmonyrun/app_cards/provider_factory.py +60 -0
  91. harmonyrun/app_cards/providers/__init__.py +7 -0
  92. harmonyrun/app_cards/providers/composite_provider.py +104 -0
  93. harmonyrun/app_cards/providers/local_provider.py +113 -0
  94. harmonyrun/app_cards/providers/server_provider.py +120 -0
  95. harmonyrun/app_cards/suite_resolve.py +112 -0
  96. harmonyrun/app_cards/writing.py +74 -0
  97. harmonyrun/batch/__init__.py +49 -0
  98. harmonyrun/batch/execution/__init__.py +34 -0
  99. harmonyrun/batch/execution/device_gate.py +73 -0
  100. harmonyrun/batch/execution/driver_factory.py +60 -0
  101. harmonyrun/batch/execution/phase.py +152 -0
  102. harmonyrun/batch/execution/resources.py +169 -0
  103. harmonyrun/batch/execution/runner.py +687 -0
  104. harmonyrun/batch/execution/scheduler.py +159 -0
  105. harmonyrun/batch/loading/__init__.py +29 -0
  106. harmonyrun/batch/loading/levels.py +23 -0
  107. harmonyrun/batch/loading/loader.py +285 -0
  108. harmonyrun/batch/loading/prompts/README.md +29 -0
  109. harmonyrun/batch/loading/prompts/__init__.py +114 -0
  110. harmonyrun/batch/loading/prompts/agent_goal/en.j2 +22 -0
  111. harmonyrun/batch/loading/prompts/agent_goal/zh.j2 +23 -0
  112. harmonyrun/batch/loading/prompts/postcondition/en.j2 +8 -0
  113. harmonyrun/batch/loading/prompts/postcondition/zh.j2 +8 -0
  114. harmonyrun/batch/loading/prompts/precondition/en.j2 +8 -0
  115. harmonyrun/batch/loading/prompts/precondition/zh.j2 +8 -0
  116. harmonyrun/batch/loading/prompts/test_execution/en.j2 +13 -0
  117. harmonyrun/batch/loading/prompts/test_execution/zh.j2 +13 -0
  118. harmonyrun/batch/loading/validation.py +60 -0
  119. harmonyrun/batch/models.py +149 -0
  120. harmonyrun/batch/reporting/__init__.py +49 -0
  121. harmonyrun/batch/reporting/_common.py +26 -0
  122. harmonyrun/batch/reporting/html_report.py +84 -0
  123. harmonyrun/batch/reporting/json_report.py +97 -0
  124. harmonyrun/batch/reporting/live.py +323 -0
  125. harmonyrun/batch/reporting/paths.py +37 -0
  126. harmonyrun/batch/reporting/templates/report.html +1191 -0
  127. harmonyrun/batch/reporting/viewer.py +309 -0
  128. harmonyrun/batch/schemas/report.schema.json +123 -0
  129. harmonyrun/batch/schemas/test_suite.schema.json +129 -0
  130. harmonyrun/batch/suite_runner.py +487 -0
  131. harmonyrun/cli/__init__.py +9 -0
  132. harmonyrun/cli/_capture.py +202 -0
  133. harmonyrun/cli/_logging.py +21 -0
  134. harmonyrun/cli/_runtime.py +55 -0
  135. harmonyrun/cli/feedback.py +60 -0
  136. harmonyrun/cli/main.py +332 -0
  137. harmonyrun/cli/mcp.py +219 -0
  138. harmonyrun/cli/memory_cmd.py +145 -0
  139. harmonyrun/cli/run.py +150 -0
  140. harmonyrun/cli/view.py +37 -0
  141. harmonyrun/config/__init__.py +88 -0
  142. harmonyrun/config/config_example.yaml +96 -0
  143. harmonyrun/config/manager.py +322 -0
  144. harmonyrun/config/paths.py +66 -0
  145. harmonyrun/config/schema/__init__.py +32 -0
  146. harmonyrun/config/schema/agent.py +182 -0
  147. harmonyrun/config/schema/llm.py +28 -0
  148. harmonyrun/config/schema/mcp.py +18 -0
  149. harmonyrun/config/schema/overrides.py +262 -0
  150. harmonyrun/config/schema/root.py +247 -0
  151. harmonyrun/config/schema/runtime.py +121 -0
  152. harmonyrun/diagnostics/__init__.py +13 -0
  153. harmonyrun/diagnostics/checks.py +498 -0
  154. harmonyrun/diagnostics/results.py +64 -0
  155. harmonyrun/diagnostics/runner.py +130 -0
  156. harmonyrun/env_keys.py +80 -0
  157. harmonyrun/events/__init__.py +34 -0
  158. harmonyrun/events/bus.py +83 -0
  159. harmonyrun/events/model/__init__.py +122 -0
  160. harmonyrun/events/model/agent.py +378 -0
  161. harmonyrun/events/model/base.py +73 -0
  162. harmonyrun/events/model/catalog.py +32 -0
  163. harmonyrun/events/model/device.py +129 -0
  164. harmonyrun/events/model/llm.py +53 -0
  165. harmonyrun/events/transports/__init__.py +15 -0
  166. harmonyrun/events/transports/langgraph.py +85 -0
  167. harmonyrun/farm/CLAUDE.md +280 -0
  168. harmonyrun/farm/__init__.py +27 -0
  169. harmonyrun/farm/_bootstrap.py +38 -0
  170. harmonyrun/farm/cli.py +397 -0
  171. harmonyrun/farm/endpoint.py +36 -0
  172. harmonyrun/farm/remote_driver.py +426 -0
  173. harmonyrun/farm/server/__init__.py +3 -0
  174. harmonyrun/farm/server/app.py +266 -0
  175. harmonyrun/farm/server/archive.py +141 -0
  176. harmonyrun/farm/server/auth.py +41 -0
  177. harmonyrun/farm/server/dispatch.py +155 -0
  178. harmonyrun/farm/server/pool.py +168 -0
  179. harmonyrun/farm/server/schemas.py +70 -0
  180. harmonyrun/farm/server/session.py +206 -0
  181. harmonyrun/feedback/__init__.py +13 -0
  182. harmonyrun/feedback/context.py +19 -0
  183. harmonyrun/feedback/discovery.py +85 -0
  184. harmonyrun/feedback/flow.py +111 -0
  185. harmonyrun/feedback/github.py +224 -0
  186. harmonyrun/feedback/issue.py +109 -0
  187. harmonyrun/feedback/packaging.py +76 -0
  188. harmonyrun/hdcutils/__init__.py +52 -0
  189. harmonyrun/hdcutils/agent/__init__.py +37 -0
  190. harmonyrun/hdcutils/agent/diagnostic.py +82 -0
  191. harmonyrun/hdcutils/agent/installer.py +189 -0
  192. harmonyrun/hdcutils/agent/spec.py +166 -0
  193. harmonyrun/hdcutils/agent/uitest_agent_1.1.12.so +0 -0
  194. harmonyrun/hdcutils/agent/uitest_agent_1.1.3.so +0 -0
  195. harmonyrun/hdcutils/agent/uitest_agent_1.1.5.so +0 -0
  196. harmonyrun/hdcutils/agent/uitest_agent_1.2.3.so +0 -0
  197. harmonyrun/hdcutils/agent/uitest_agent_x86_1.1.9.so +0 -0
  198. harmonyrun/hdcutils/client.py +108 -0
  199. harmonyrun/hdcutils/device/__init__.py +3 -0
  200. harmonyrun/hdcutils/device/apps.py +391 -0
  201. harmonyrun/hdcutils/device/core.py +181 -0
  202. harmonyrun/hdcutils/device/display.py +219 -0
  203. harmonyrun/hdcutils/device/display_state.py +589 -0
  204. harmonyrun/hdcutils/device/files.py +54 -0
  205. harmonyrun/hdcutils/device/forwards.py +90 -0
  206. harmonyrun/hdcutils/device/input.py +99 -0
  207. harmonyrun/hdcutils/device/recording.py +337 -0
  208. harmonyrun/hdcutils/device/screen.py +376 -0
  209. harmonyrun/hdcutils/device/system.py +82 -0
  210. harmonyrun/hdcutils/emulator/__init__.py +25 -0
  211. harmonyrun/hdcutils/emulator/scenario.py +297 -0
  212. harmonyrun/hdcutils/errors.py +41 -0
  213. harmonyrun/hdcutils/hilog.py +441 -0
  214. harmonyrun/hdcutils/keycode.py +361 -0
  215. harmonyrun/hdcutils/rpc/__init__.py +5 -0
  216. harmonyrun/hdcutils/rpc/client.py +462 -0
  217. harmonyrun/hdcutils/rpc/framing.py +103 -0
  218. harmonyrun/hdcutils/rpc/recovery.py +114 -0
  219. harmonyrun/hdcutils/transport/__init__.py +23 -0
  220. harmonyrun/hdcutils/transport/ports.py +128 -0
  221. harmonyrun/hdcutils/transport/recording.py +93 -0
  222. harmonyrun/hdcutils/transport/runner.py +204 -0
  223. harmonyrun/hdcutils/types.py +43 -0
  224. harmonyrun/hdcutils/version.py +12 -0
  225. harmonyrun/hdcutils/wake.py +258 -0
  226. harmonyrun/hypium/__init__.py +12 -0
  227. harmonyrun/hypium/action_mapper.py +159 -0
  228. harmonyrun/hypium/assertion_builder.py +280 -0
  229. harmonyrun/hypium/cli.py +140 -0
  230. harmonyrun/hypium/code_polisher.py +203 -0
  231. harmonyrun/hypium/component_resolver.py +221 -0
  232. harmonyrun/hypium/generator.py +306 -0
  233. harmonyrun/hypium/template.py +157 -0
  234. harmonyrun/hypium/trajectory_loader.py +280 -0
  235. harmonyrun/log_handlers.py +68 -0
  236. harmonyrun/mcp/__init__.py +28 -0
  237. harmonyrun/mcp/schemas.py +107 -0
  238. harmonyrun/mcp/server.py +96 -0
  239. harmonyrun/mcp/session.py +124 -0
  240. harmonyrun/mcp/tools/__init__.py +5 -0
  241. harmonyrun/mcp/tools/actions.py +218 -0
  242. harmonyrun/mcp/tools/connection.py +62 -0
  243. harmonyrun/mcp/tools/perception.py +233 -0
  244. harmonyrun/mcp/transport.py +19 -0
  245. harmonyrun/tools/__init__.py +79 -0
  246. harmonyrun/tools/contracts.py +39 -0
  247. harmonyrun/tools/driver/__init__.py +25 -0
  248. harmonyrun/tools/driver/app_catalog.py +113 -0
  249. harmonyrun/tools/driver/base.py +362 -0
  250. harmonyrun/tools/driver/factory.py +82 -0
  251. harmonyrun/tools/driver/harmony.py +1185 -0
  252. harmonyrun/tools/driver/perceiving.py +89 -0
  253. harmonyrun/tools/driver/proxy.py +228 -0
  254. harmonyrun/tools/driver/recording.py +603 -0
  255. harmonyrun/tools/driver/stealth.py +217 -0
  256. harmonyrun/tools/monitors/__init__.py +26 -0
  257. harmonyrun/tools/monitors/hilog_monitor.py +463 -0
  258. harmonyrun/tools/monitors/screen_recorder.py +208 -0
  259. harmonyrun/tools/perception/__init__.py +59 -0
  260. harmonyrun/tools/perception/processors/__init__.py +68 -0
  261. harmonyrun/tools/perception/processors/bundle_serde.py +139 -0
  262. harmonyrun/tools/perception/processors/constants.py +54 -0
  263. harmonyrun/tools/perception/processors/converters/__init__.py +5 -0
  264. harmonyrun/tools/perception/processors/converters/a11y_converter.py +116 -0
  265. harmonyrun/tools/perception/processors/extractors/__init__.py +5 -0
  266. harmonyrun/tools/perception/processors/extractors/nav_state.py +232 -0
  267. harmonyrun/tools/perception/processors/extractors/phone_state.py +399 -0
  268. harmonyrun/tools/perception/processors/filters/__init__.py +40 -0
  269. harmonyrun/tools/perception/processors/filters/base.py +24 -0
  270. harmonyrun/tools/perception/processors/filters/concise_filter.py +123 -0
  271. harmonyrun/tools/perception/processors/filters/detailed_filter.py +173 -0
  272. harmonyrun/tools/perception/processors/filters/passthrough_filter.py +23 -0
  273. harmonyrun/tools/perception/processors/formatters/__init__.py +10 -0
  274. harmonyrun/tools/perception/processors/formatters/base.py +39 -0
  275. harmonyrun/tools/perception/processors/formatters/indexed_formatter.py +941 -0
  276. harmonyrun/tools/perception/processors/pipeline.py +137 -0
  277. harmonyrun/tools/perception/processors/simplifiers/__init__.py +20 -0
  278. harmonyrun/tools/perception/processors/simplifiers/highlight_marker.py +58 -0
  279. harmonyrun/tools/perception/processors/simplifiers/system_ui_pruner.py +171 -0
  280. harmonyrun/tools/perception/processors/simplifiers/tree_simplifier.py +227 -0
  281. harmonyrun/tools/perception/processors/utils/__init__.py +42 -0
  282. harmonyrun/tools/perception/processors/utils/coordinate.py +25 -0
  283. harmonyrun/tools/perception/processors/utils/geometry.py +148 -0
  284. harmonyrun/tools/perception/processors/utils/semantic.py +58 -0
  285. harmonyrun/tools/perception/ui/__init__.py +47 -0
  286. harmonyrun/tools/perception/ui/config.py +80 -0
  287. harmonyrun/tools/perception/ui/offline.py +140 -0
  288. harmonyrun/tools/perception/ui/provider.py +341 -0
  289. harmonyrun/tools/perception/ui/screenshot.py +272 -0
  290. harmonyrun/tools/perception/ui/snapshot.py +178 -0
  291. harmonyrun/tools/perception/ui/state.py +261 -0
  292. harmonyrun/tools/perception/ui/stealth_state.py +106 -0
  293. harmonyrun/traces/__init__.py +50 -0
  294. harmonyrun/traces/case_report.py +274 -0
  295. harmonyrun/traces/folder.py +221 -0
  296. harmonyrun/traces/format.py +33 -0
  297. harmonyrun/traces/llm_log.py +212 -0
  298. harmonyrun/traces/recorder.py +293 -0
  299. harmonyrun/traces/serializers.py +138 -0
  300. harmonyrun/traces/sinks.py +60 -0
  301. harmonyrun/traces/telemetry/__init__.py +22 -0
  302. harmonyrun/traces/telemetry/tracker.py +180 -0
  303. harmonyrun/traces/templates/case_report.html +1908 -0
  304. harmonyrun/traces/writer.py +309 -0
  305. harmonyrun-0.4.9.dist-info/METADATA +401 -0
  306. harmonyrun-0.4.9.dist-info/RECORD +309 -0
  307. harmonyrun-0.4.9.dist-info/WHEEL +4 -0
  308. harmonyrun-0.4.9.dist-info/entry_points.txt +2 -0
  309. harmonyrun-0.4.9.dist-info/licenses/LICENSE +21 -0
harmonyrun/__init__.py ADDED
@@ -0,0 +1,186 @@
1
+ """
2
+ HarmonyRun - A framework for automating HarmonyOS devices through LLM agents.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ import os
9
+ from importlib import import_module
10
+ from importlib.metadata import PackageNotFoundError, version
11
+ from typing import TYPE_CHECKING
12
+
13
+ # Silence ``transformers`` "None of PyTorch, TensorFlow >= 2.0, or Flax have
14
+ # been found." advisory. ``langchain_core`` imports ``transformers`` purely to
15
+ # pull in ``GPT2TokenizerFast``; we never run model inference through it, so
16
+ # the advisory is noise. Must be set *before* the transitive transformers
17
+ # import (triggered by any langchain import), hence done here at package root.
18
+ os.environ.setdefault("TRANSFORMERS_NO_ADVISORY_WARNINGS", "1")
19
+
20
+ try:
21
+ __version__ = version("harmonyrun")
22
+ except PackageNotFoundError:
23
+ # Running from a checkout without installing the distribution (e.g. scripts).
24
+ __version__ = "0.0.0+unknown"
25
+
26
+ # Attach a default CLILogHandler so that every consumer (CLI, SDK, tools-only)
27
+ # gets visible output without explicit setup. CLI may replace this via
28
+ # ``configure_logging()``.
29
+ _logger = logging.getLogger("harmonyrun")
30
+ try:
31
+ from harmonyrun.log_handlers import CLILogHandler
32
+
33
+ _logger.addHandler(CLILogHandler())
34
+ _logger.setLevel(logging.INFO)
35
+ _logger.propagate = False
36
+ except ImportError:
37
+ # e.g. ``rich`` not installed — skip; subpackages like ``hdcutils`` still import.
38
+ pass
39
+
40
+ # Type checking imports for static analyzers
41
+ if TYPE_CHECKING:
42
+ from harmonyrun.agent.harmony import HarmonyAgent
43
+ from harmonyrun.events import ResultEvent
44
+ from harmonyrun.agent.llm import load_llm
45
+ from harmonyrun.agent.state import StepObservation
46
+ from harmonyrun.events import FastAgentToolCallEvent
47
+ from harmonyrun.config import (
48
+ AgentConfig,
49
+ AppCardConfig,
50
+ ConfigManager,
51
+ DeviceConfig,
52
+ HarmonyRunConfig,
53
+ ExecutorConfig,
54
+ FastAgentConfig,
55
+ LLMProfile,
56
+ LoggingConfig,
57
+ ManagerConfig,
58
+ ToolsConfig,
59
+ )
60
+ from harmonyrun.env_keys import load_runtime_dotenv
61
+ from harmonyrun.hdcutils import hdc
62
+ from harmonyrun.mcp import create_server as create_mcp_server
63
+ from harmonyrun.mcp import serve_stdio as serve_mcp_stdio
64
+ from harmonyrun.tools.driver.base import DeviceDriver
65
+ from harmonyrun.tools.driver.harmony import HarmonyDriver
66
+ from harmonyrun.tools.driver.recording import RecordingDriver
67
+ from harmonyrun.tools.perception.ui.provider import StateProvider as TreeStateProvider
68
+ from harmonyrun.tools.perception.ui.state import UIState
69
+ from harmonyrun.tools.perception.ui.offline import OfflineStateProvider
70
+ from harmonyrun.tools.perception.processors import load_capture_bundle, load_device_info
71
+ from harmonyrun.config.schema.overrides import apply_overrides
72
+ from harmonyrun.traces.case_report import render_case_html
73
+ from harmonyrun.traces.folder import TraceFolder
74
+ from harmonyrun.tools.driver.factory import build_harmony_driver
75
+ from harmonyrun.batch.loading.validation import iter_json_schema_errors
76
+ from harmonyrun.batch.reporting import find_latest_suite_run
77
+ from harmonyrun.batch.loading.loader import load_test_cases
78
+ from harmonyrun.batch.loading.prompts import build_test_execution_goal
79
+ from harmonyrun.batch.models import SuiteMeta, TestCase, TestCaseResult
80
+ from harmonyrun.batch.execution.runner import run_test_case
81
+
82
+ _LAZY_EXPORTS: dict[str, tuple[str, str]] = {
83
+ "ResultEvent": ("harmonyrun.events", "ResultEvent"),
84
+ "HarmonyAgent": ("harmonyrun.agent.harmony", "HarmonyAgent"),
85
+ "load_llm": ("harmonyrun.agent.llm", "load_llm"),
86
+ "StepObservation": ("harmonyrun.agent.state", "StepObservation"),
87
+ "FastAgentToolCallEvent": ("harmonyrun.events", "FastAgentToolCallEvent"),
88
+ "AgentConfig": ("harmonyrun.config", "AgentConfig"),
89
+ "AppCardConfig": ("harmonyrun.config", "AppCardConfig"),
90
+ "FastAgentConfig": ("harmonyrun.config", "FastAgentConfig"),
91
+ "DeviceConfig": ("harmonyrun.config", "DeviceConfig"),
92
+ "HarmonyRunConfig": ("harmonyrun.config", "HarmonyRunConfig"),
93
+ "ExecutorConfig": ("harmonyrun.config", "ExecutorConfig"),
94
+ "LLMProfile": ("harmonyrun.config", "LLMProfile"),
95
+ "LoggingConfig": ("harmonyrun.config", "LoggingConfig"),
96
+ "ManagerConfig": ("harmonyrun.config", "ManagerConfig"),
97
+ "ToolsConfig": ("harmonyrun.config", "ToolsConfig"),
98
+ "ConfigManager": ("harmonyrun.config", "ConfigManager"),
99
+ "load_runtime_dotenv": ("harmonyrun.env_keys", "load_runtime_dotenv"),
100
+ "hdc": ("harmonyrun.hdcutils", "hdc"),
101
+ "DeviceDriver": ("harmonyrun.tools", "DeviceDriver"),
102
+ "TreeStateProvider": ("harmonyrun.tools", "TreeStateProvider"),
103
+ "HarmonyDriver": ("harmonyrun.tools", "HarmonyDriver"),
104
+ "RecordingDriver": ("harmonyrun.tools", "RecordingDriver"),
105
+ "UIState": ("harmonyrun.tools.perception.ui.state", "UIState"),
106
+ "OfflineStateProvider": ("harmonyrun.tools.perception.ui.offline", "OfflineStateProvider"),
107
+ "load_capture_bundle": ("harmonyrun.tools.perception.processors", "load_capture_bundle"),
108
+ "load_device_info": ("harmonyrun.tools.perception.processors", "load_device_info"),
109
+ "apply_overrides": ("harmonyrun.config.schema.overrides", "apply_overrides"),
110
+ "create_mcp_server": ("harmonyrun.mcp", "create_server"),
111
+ "serve_mcp_stdio": ("harmonyrun.mcp", "serve_stdio"),
112
+ "render_case_html": ("harmonyrun.traces.case_report", "render_case_html"),
113
+ "TraceFolder": ("harmonyrun.traces.folder", "TraceFolder"),
114
+ "build_harmony_driver": ("harmonyrun.tools.driver.factory", "build_harmony_driver"),
115
+ "iter_json_schema_errors": ("harmonyrun.batch.loading.validation", "iter_json_schema_errors"),
116
+ "find_latest_suite_run": ("harmonyrun.batch.reporting", "find_latest_suite_run"),
117
+ "load_test_cases": ("harmonyrun.batch.loading.loader", "load_test_cases"),
118
+ "SuiteMeta": ("harmonyrun.batch.models", "SuiteMeta"),
119
+ "TestCase": ("harmonyrun.batch.models", "TestCase"),
120
+ "TestCaseResult": ("harmonyrun.batch.models", "TestCaseResult"),
121
+ "DeviceRequirements": ("harmonyrun.batch.models", "DeviceRequirements"),
122
+ "run_test_case": ("harmonyrun.batch.execution.runner", "run_test_case"),
123
+ "build_test_execution_goal": ("harmonyrun.batch.loading.prompts", "build_test_execution_goal"),
124
+ }
125
+
126
+
127
+ def __getattr__(name: str) -> object:
128
+ spec = _LAZY_EXPORTS.get(name)
129
+ if spec is None:
130
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
131
+ mod_name, attr = spec
132
+ return getattr(import_module(mod_name), attr)
133
+
134
+
135
+ def __dir__() -> list[str]:
136
+ return sorted({*globals().keys(), *_LAZY_EXPORTS.keys(), "__version__"})
137
+
138
+
139
+ # Make main components available at package level
140
+ __all__ = [
141
+ # Agent
142
+ "HarmonyAgent",
143
+ "load_llm",
144
+ "ResultEvent",
145
+ # Tools / Drivers
146
+ "DeviceDriver",
147
+ "TreeStateProvider",
148
+ "HarmonyDriver",
149
+ "RecordingDriver",
150
+ # Configuration
151
+ "ConfigManager",
152
+ "HarmonyRunConfig",
153
+ "AgentConfig",
154
+ "FastAgentConfig",
155
+ "ManagerConfig",
156
+ "ExecutorConfig",
157
+ "AppCardConfig",
158
+ "DeviceConfig",
159
+ "LoggingConfig",
160
+ "ToolsConfig",
161
+ "LLMProfile",
162
+ # Env / secrets
163
+ "load_runtime_dotenv",
164
+ # Device enumeration / connection (async hdc client singleton)
165
+ "hdc",
166
+ # MCP
167
+ "create_mcp_server",
168
+ "serve_mcp_stdio",
169
+ # Agent internals (advanced users)
170
+ "FastAgentToolCallEvent",
171
+ # Perception facade (offline eval)
172
+ "OfflineStateProvider",
173
+ "load_capture_bundle",
174
+ "load_device_info",
175
+ # Config override engine
176
+ "apply_overrides",
177
+ # Traces
178
+ "render_case_html",
179
+ "TraceFolder",
180
+ # Driver factory
181
+ "build_harmony_driver",
182
+ # Schema validation
183
+ "iter_json_schema_errors",
184
+ # Batch helpers
185
+ "find_latest_suite_run",
186
+ ]
harmonyrun/__main__.py ADDED
@@ -0,0 +1,8 @@
1
+ """
2
+ HarmonyRun main entry point
3
+ """
4
+
5
+ from harmonyrun.cli.main import cli
6
+
7
+ if __name__ == "__main__":
8
+ cli()
@@ -0,0 +1,5 @@
1
+ """HarmonyRun agent layer.
2
+
3
+ Event types are imported from the ``harmonyrun.events`` vocabulary leaf, not
4
+ re-exported here.
5
+ """
@@ -0,0 +1,18 @@
1
+ """Agent-side event **consumption** + wiring.
2
+
3
+ The event *vocabulary*, the ``EventBus`` and the stream ``WorkflowEventEmitter``
4
+ all live in the ``harmonyrun.events`` leaf — import them from there. This
5
+ package holds only the agent-layer consumer side:
6
+
7
+ - ``handler`` — ``ConsoleSink``, the stream-transport console renderer.
8
+ - ``render_registry`` — the type→renderer dispatch table that each sub-agent's
9
+ ``_render`` module self-registers into (IoC; the registry imports no concrete
10
+ event class).
11
+ - ``_render`` — coordination + ``traces`` device-event renderers.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from harmonyrun.agent.events.handler import ConsoleSink
17
+
18
+ __all__ = ["ConsoleSink"]
@@ -0,0 +1,258 @@
1
+ """Log renderers for every workflow event, centralized in one module.
2
+
3
+ The events themselves live in the ``harmonyrun.events`` vocabulary leaf; their
4
+ *consumer-side* CLI rendering belongs here in the agent layer. Renderers used to
5
+ be scattered across each sub-agent package ("co-located with the event"), but
6
+ once the event vocabulary sank to the ``events/`` leaf that justification went
7
+ away — the per-agent ``_render`` modules imported only the leaf event classes
8
+ plus the registry, never their own package. So all renderers now live here and
9
+ register on this module's import (triggered by ``handler.py``), which also makes
10
+ registration deterministic instead of depending on which sub-agent packages got
11
+ imported first.
12
+
13
+ Grouping below is by *publisher* (orchestrator/coordination + traces, then each
14
+ sub-agent's own telemetry). This module imports only ``harmonyrun.events`` event
15
+ classes and ``render_registry`` — never a sub-agent package — so the IoC rule
16
+ (registry/ConsoleSink never reach up into ``fast_agent``/``manager``/``executor``)
17
+ still holds.
18
+
19
+ Rendering strings are byte-identical to the historical isinstance chain — do not
20
+ reword without updating ``tests/unit/agent/events/test_handler_render.py`` and
21
+ running an on-device smoke.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import logging
27
+
28
+ from harmonyrun.agent.events.render_registry import register
29
+ from harmonyrun.events import (
30
+ ActiveInterventionEvent,
31
+ ExecutorActionEvent,
32
+ ExecutorActionResultEvent,
33
+ ExecutorResponseEvent,
34
+ ExecutorResultEvent,
35
+ FastAgentEndEvent,
36
+ FastAgentExecuteEvent,
37
+ FastAgentInputEvent,
38
+ FastAgentOutputEvent,
39
+ FastAgentResponseEvent,
40
+ FastAgentResultEvent,
41
+ FastAgentToolCallEvent,
42
+ FinalizeEvent,
43
+ ManagerContextEvent,
44
+ ManagerPlanDetailsEvent,
45
+ ManagerResponseEvent,
46
+ RecordUIStateEvent,
47
+ ScreenshotEvent,
48
+ StructuredFailureEvent,
49
+ )
50
+
51
+ logger = logging.getLogger("harmonyrun")
52
+
53
+
54
+ # ---- coordination (orchestrator-published) + traces/device ----
55
+
56
+
57
+ def _render_screenshot(event: ScreenshotEvent) -> None:
58
+ logger.debug("📸 Taking screenshot...")
59
+
60
+
61
+ def _render_record_ui_state(event: RecordUIStateEvent) -> None:
62
+ logger.debug("✏️ Recording UI state")
63
+
64
+
65
+ def _render_executor_result(event: ExecutorResultEvent) -> None:
66
+ logger.debug("Step complete", extra={"color": "magenta"})
67
+
68
+
69
+ def _render_fast_agent_execute(event: FastAgentExecuteEvent) -> None:
70
+ logger.debug("🔧 Starting task execution...", extra={"color": "magenta"})
71
+
72
+
73
+ def _render_fast_agent_result(event: FastAgentResultEvent) -> None:
74
+ if event.success:
75
+ logger.debug(f"Task result: {event.reason}", extra={"color": "green"})
76
+ else:
77
+ logger.debug(f"Task failed: {event.reason}", extra={"color": "red"})
78
+
79
+
80
+ def _render_finalize(event: FinalizeEvent) -> None:
81
+ if event.success:
82
+ logger.info(f"🎉 Goal achieved: {event.reason}", extra={"color": "green"})
83
+ else:
84
+ logger.info(f"❌ Goal failed: {event.reason}", extra={"color": "red"})
85
+
86
+
87
+ # ---- fast_agent telemetry ----
88
+
89
+
90
+ def _render_input(event: FastAgentInputEvent) -> None:
91
+ logger.debug("💬 Task input received...")
92
+
93
+
94
+ def _render_response(event: FastAgentResponseEvent) -> None:
95
+ logger.debug("FastAgent response", extra={"color": "magenta"})
96
+ if event.thought:
97
+ preview = (
98
+ event.thought[:150] + "..."
99
+ if len(event.thought) > 150
100
+ else event.thought
101
+ )
102
+ logger.debug(f"🧠 Thinking: {preview}", extra={"color": "cyan"})
103
+ if event.code:
104
+ logger.debug("💻 Executing action code", extra={"color": "yellow"})
105
+ logger.debug(f"{event.code}", extra={"color": "blue"})
106
+ usage_line = event.usage.summary_line() if event.usage else ""
107
+ if usage_line:
108
+ logger.debug(
109
+ f"📊 fast_agent tokens — {usage_line}",
110
+ extra={"color": "cyan"},
111
+ )
112
+
113
+
114
+ def _render_tool_call(event: FastAgentToolCallEvent) -> None:
115
+ logger.debug("⚡ Executing tool calls...", extra={"color": "yellow"})
116
+
117
+
118
+ def _render_output(event: FastAgentOutputEvent) -> None:
119
+ if event.output:
120
+ output = str(event.output)
121
+ preview = output[:100] + "..." if len(output) > 100 else output
122
+ if "Error" in output or "Exception" in output:
123
+ logger.debug(f"❌ Action error: {preview}", extra={"color": "red"})
124
+ else:
125
+ logger.debug(f"⚡ Action result: {preview}", extra={"color": "green"})
126
+
127
+
128
+ def _render_end(event: FastAgentEndEvent) -> None:
129
+ status = "done" if event.success else "failed"
130
+ color = "green" if event.success else "red"
131
+ logger.debug(
132
+ f"■ {status}: {event.reason} ({event.tool_call_count} runs)",
133
+ extra={"color": color},
134
+ )
135
+
136
+
137
+ def _render_structured_failure(event: StructuredFailureEvent) -> None:
138
+ logger.warning(
139
+ f"🧩 Structured failure [{event.mode}/{event.severity}]: "
140
+ f"{event.conclusion} (target={event.target_ref})",
141
+ extra={"color": "red"},
142
+ )
143
+
144
+
145
+ def _render_active_intervention(event: ActiveInterventionEvent) -> None:
146
+ logger.warning(
147
+ f"🛠️ Active intervention [{event.kind}] → {event.target} "
148
+ f"(#{event.count}): {event.reason}",
149
+ extra={"color": "yellow"},
150
+ )
151
+
152
+
153
+ # ---- manager telemetry ----
154
+
155
+
156
+ def _render_context(event: ManagerContextEvent) -> None:
157
+ logger.debug("🧠 Manager preparing context...")
158
+
159
+
160
+ def _render_manager_response(event: ManagerResponseEvent) -> None:
161
+ logger.debug("📥 Manager received LLM response")
162
+ usage_line = event.usage.summary_line() if event.usage else ""
163
+ if usage_line:
164
+ logger.debug(f"📊 manager tokens — {usage_line}", extra={"color": "cyan"})
165
+
166
+
167
+ def _render_plan_details(event: ManagerPlanDetailsEvent) -> None:
168
+ if event.thought:
169
+ preview = (
170
+ event.thought[:120] + "..."
171
+ if len(event.thought) > 120
172
+ else event.thought
173
+ )
174
+ logger.debug(f"💭 Thought: {preview}", extra={"color": "cyan"})
175
+ if event.subgoal:
176
+ preview = (
177
+ event.subgoal[:150] + "..."
178
+ if len(event.subgoal) > 150
179
+ else event.subgoal
180
+ )
181
+ logger.debug(f"📋 Next step: {preview}", extra={"color": "yellow"})
182
+ if event.answer:
183
+ preview = (
184
+ event.answer[:200] + "..."
185
+ if len(event.answer) > 200
186
+ else event.answer
187
+ )
188
+ logger.debug(f"💬 Answer: {preview}", extra={"color": "green"})
189
+ if event.plan:
190
+ logger.debug(f"▸ {event.plan}", extra={"color": "yellow"})
191
+ if event.memory_update:
192
+ mem = event.memory_update
193
+ mem_preview = mem[:100] + "..." if len(mem) > 100 else mem
194
+ logger.debug(
195
+ f"🧠 Memory: {mem_preview}",
196
+ extra={"color": "cyan"},
197
+ )
198
+
199
+
200
+ # ---- executor telemetry ----
201
+ # ``ExecutorContextEvent`` is intentionally NOT registered — the former
202
+ # ``EventHandler`` had no branch for it, so it falls through to the generic
203
+ # fallback exactly as before.
204
+
205
+
206
+ def _render_executor_response(event: ExecutorResponseEvent) -> None:
207
+ usage_line = event.usage.summary_line() if event.usage else ""
208
+ if usage_line:
209
+ logger.debug(
210
+ f"📊 executor tokens — {usage_line}",
211
+ extra={"color": "cyan"},
212
+ )
213
+
214
+
215
+ def _render_action(event: ExecutorActionEvent) -> None:
216
+ if event.description:
217
+ logger.debug(f"🎯 Action: {event.description}", extra={"color": "yellow"})
218
+ if event.thought:
219
+ preview = (
220
+ event.thought[:120] + "..."
221
+ if len(event.thought) > 120
222
+ else event.thought
223
+ )
224
+ logger.debug(f"💭 Reasoning: {preview}", extra={"color": "cyan"})
225
+
226
+
227
+ def _render_action_result(event: ExecutorActionResultEvent) -> None:
228
+ if event.success:
229
+ logger.debug(f"✅ {event.summary}", extra={"color": "green"})
230
+ else:
231
+ error_msg = event.error or "Unknown error"
232
+ logger.debug(f"❌ {event.summary} ({error_msg})", extra={"color": "red"})
233
+
234
+
235
+ # ---- registration (centralized; handler.py's import triggers all of it) ----
236
+
237
+ register(ScreenshotEvent, _render_screenshot)
238
+ register(RecordUIStateEvent, _render_record_ui_state)
239
+ register(ExecutorResultEvent, _render_executor_result)
240
+ register(FastAgentExecuteEvent, _render_fast_agent_execute)
241
+ register(FastAgentResultEvent, _render_fast_agent_result)
242
+ register(FinalizeEvent, _render_finalize)
243
+
244
+ register(FastAgentInputEvent, _render_input)
245
+ register(FastAgentResponseEvent, _render_response)
246
+ register(FastAgentToolCallEvent, _render_tool_call)
247
+ register(FastAgentOutputEvent, _render_output)
248
+ register(FastAgentEndEvent, _render_end)
249
+ register(StructuredFailureEvent, _render_structured_failure)
250
+ register(ActiveInterventionEvent, _render_active_intervention)
251
+
252
+ register(ManagerContextEvent, _render_context)
253
+ register(ManagerResponseEvent, _render_manager_response)
254
+ register(ManagerPlanDetailsEvent, _render_plan_details)
255
+
256
+ register(ExecutorResponseEvent, _render_executor_response)
257
+ register(ExecutorActionEvent, _render_action)
258
+ register(ExecutorActionResultEvent, _render_action_result)
@@ -0,0 +1,36 @@
1
+ """Workflow event → logger translator shared by CLI and batch runner.
2
+
3
+ Pure dispatch: every renderer is centralized in ``_render.py`` (imported here
4
+ for its registration side-effect) and registered against an exact event type.
5
+ ``handle`` just looks the renderer up and applies a generic fallback for unknown
6
+ events — so this module references no concrete event type and no sub-agent
7
+ package (the registry holds only ``type -> callable``).
8
+
9
+ Renderers emit ``logging`` calls with ``extra`` params (color, etc.); the
10
+ attached ``logging.Handler`` (typically CLILogHandler) does the rendering.
11
+ """
12
+
13
+ import logging
14
+
15
+ # Import side-effect: registers every renderer (coordination/traces + all
16
+ # sub-agent telemetry, centralized in ``_render``).
17
+ import harmonyrun.agent.events._render # noqa: F401
18
+ from harmonyrun.agent.events.render_registry import render
19
+
20
+ logger = logging.getLogger("harmonyrun")
21
+
22
+
23
+ class ConsoleSink:
24
+ """Console-rendering sink (consumption ④) for the LangGraph stream transport.
25
+
26
+ Despite the name, this sink writes **no** console output itself — it only
27
+ translates workflow events into ``logging`` records (with ``extra`` params
28
+ such as ``color``) via the render registry, and the attached cli-layer
29
+ ``CLILogHandler`` does the actual terminal rendering. No UI state tracking.
30
+ The CLI / batch runners consume ``AgentHandle.stream_events()`` and feed each
31
+ event to :meth:`handle`.
32
+ """
33
+
34
+ def handle(self, event) -> None:
35
+ if not render(event):
36
+ logger.debug(f"🔄 {event.__class__.__name__}")
@@ -0,0 +1,41 @@
1
+ """Event → log-rendering dispatch registry (pure infra, knows no event types).
2
+
3
+ ``EventHandler`` used to be a ~150-line ``isinstance`` chain that imported the
4
+ three sub-agents' telemetry events — an inversion (events/ is a shared *leaf*
5
+ infra layer, yet reached *up* into ``fast_agent`` / ``manager`` / ``executor``).
6
+
7
+ This registry inverts that control: all renderers live in ``_render.py`` (which
8
+ imports only ``harmonyrun.events`` event classes — never a sub-agent package)
9
+ and self-register here on import. The registry itself holds only
10
+ ``type -> callable`` and imports no concrete event class, so neither it nor
11
+ ``handler.py`` references any sub-agent package.
12
+
13
+ Lookup is exact-type (events are leaf classes; no subclass fan-out is needed),
14
+ matching the old ``isinstance`` chain's first-match-wins behaviour.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Any, Callable
20
+
21
+ EventRenderer = Callable[[Any], None]
22
+
23
+ _RENDERERS: dict[type, EventRenderer] = {}
24
+
25
+
26
+ def register(event_type: type, renderer: EventRenderer) -> None:
27
+ """Register the renderer for an exact event type (last registration wins)."""
28
+ _RENDERERS[event_type] = renderer
29
+
30
+
31
+ def render(event: Any) -> bool:
32
+ """Render ``event`` via its registered renderer.
33
+
34
+ Returns ``True`` if a renderer handled it, ``False`` otherwise (caller
35
+ applies the generic fallback). Exact-type lookup only.
36
+ """
37
+ renderer = _RENDERERS.get(type(event))
38
+ if renderer is None:
39
+ return False
40
+ renderer(event)
41
+ return True
@@ -0,0 +1,27 @@
1
+ """Execution scaffolding shared by every agent that drives a LangGraph run.
2
+
3
+ Two public concepts live here:
4
+
5
+ - ``BaseExecutionAgent`` — the thin base class for ManagerAgent /
6
+ ExecutorAgent / FastAgent. Consolidates the cross-cutting code every
7
+ per-LLM-call agent needs: device-state capture, UI mirroring into the
8
+ shared state, hilog event draining, screenshot annotation, app-card
9
+ refresh, and usage recording. Anti-loop detection (``anti_loop`` /
10
+ ``thresholds``) is part of this scaffolding.
11
+ - ``AgentHandle`` — the awaitable wrapper every agent's ``run()`` returns
12
+ over a compiled LangGraph (``await handle`` / ``handle.stream_events()``).
13
+ """
14
+
15
+ from harmonyrun.agent.execution.base_agent import (
16
+ BaseExecutionAgent,
17
+ build_record_ui_state_event,
18
+ )
19
+ from harmonyrun.agent.execution.formatting import compact_args_repr
20
+ from harmonyrun.agent.execution.handle import AgentHandle
21
+
22
+ __all__ = [
23
+ "BaseExecutionAgent",
24
+ "AgentHandle",
25
+ "compact_args_repr",
26
+ "build_record_ui_state_event",
27
+ ]