koru 0.1.331__py3-none-any.whl → 0.1.332__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.
- koru/agent_backend_runtime.py +83 -38
- koru/integrations/imgl_client.py +2 -1
- koru/integrations/vdisplay_client.py +24 -15
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/METADATA +5 -5
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/RECORD +9 -9
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/WHEEL +0 -0
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/entry_points.txt +0 -0
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/licenses/LICENSE +0 -0
- {koru-0.1.331.dist-info → koru-0.1.332.dist-info}/top_level.txt +0 -0
koru/agent_backend_runtime.py
CHANGED
|
@@ -281,6 +281,77 @@ class Nlp2UriDesktopBackend:
|
|
|
281
281
|
return _nlp2uri_desktop_send(prompt, ide=ide, submit=submit, dry_run=self.dry_run)
|
|
282
282
|
|
|
283
283
|
|
|
284
|
+
def _build_plugin_socket_backend(client: IDEControlClient | None) -> AgentBackend:
|
|
285
|
+
if client is None:
|
|
286
|
+
raise ValueError("plugin_socket backend requires an IDEControlClient")
|
|
287
|
+
return PluginSocketBackend(client=client)
|
|
288
|
+
|
|
289
|
+
def _build_mcp_tool_backend(mcp_server: str | None) -> AgentBackend:
|
|
290
|
+
return McpToolBackend(mcp_server=mcp_server)
|
|
291
|
+
|
|
292
|
+
def _build_vendor_agent_cli_backend(shell_client_id: str | None) -> AgentBackend:
|
|
293
|
+
return TillmShellBackend(
|
|
294
|
+
client_id=shell_client_id or os.environ.get("KORU_TILLM_CLIENT", "aider"),
|
|
295
|
+
execute=os.environ.get("KORU_TILLM_DRY_RUN", "").strip().lower()
|
|
296
|
+
not in {"1", "true", "yes", "on"},
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def _build_gillm_gui_backend() -> AgentBackend:
|
|
300
|
+
return GillmGuiBackend(client=build_gillm_ide_client())
|
|
301
|
+
|
|
302
|
+
def _build_os_injector_backend() -> AgentBackend:
|
|
303
|
+
profile = os.environ.get("KORU_OS_INJECTOR_PROFILE", "").strip()
|
|
304
|
+
if not profile:
|
|
305
|
+
raise ValueError("os_injector backend requires KORU_OS_INJECTOR_PROFILE")
|
|
306
|
+
raw_cfg = os.environ.get("KORU_OS_INJECTOR_CONFIG", "").strip()
|
|
307
|
+
cfg = Path(raw_cfg).expanduser().resolve() if raw_cfg else None
|
|
308
|
+
return OsInjectorBackend(profile_id=profile, config_path=cfg)
|
|
309
|
+
|
|
310
|
+
def _build_nlp2uri_desktop_backend() -> AgentBackend:
|
|
311
|
+
dry = os.environ.get("KORU_NLP2URI_DRY_RUN", "").strip().lower() in {
|
|
312
|
+
"1", "true", "yes", "on",
|
|
313
|
+
}
|
|
314
|
+
return Nlp2UriDesktopBackend(dry_run=dry)
|
|
315
|
+
|
|
316
|
+
def _build_imgl_desktop_backend() -> AgentBackend:
|
|
317
|
+
dry = os.environ.get("KORU_IMGL_DRY_RUN", "").strip().lower() in {
|
|
318
|
+
"1", "true", "yes", "on",
|
|
319
|
+
}
|
|
320
|
+
return ImglDesktopBackend(dry_run=dry)
|
|
321
|
+
|
|
322
|
+
def _build_vdisplay_control_backend() -> AgentBackend:
|
|
323
|
+
dry = os.environ.get("KORU_VDISPLAY_DRY_RUN", "").strip().lower() in {
|
|
324
|
+
"1", "true", "yes", "on",
|
|
325
|
+
}
|
|
326
|
+
return VdisplayControlBackend(dry_run=dry)
|
|
327
|
+
|
|
328
|
+
def _build_noop_backend(noop_reason: str) -> AgentBackend:
|
|
329
|
+
return NoopBackend(reason=noop_reason)
|
|
330
|
+
|
|
331
|
+
_BACKEND_BUILDERS = {
|
|
332
|
+
"plugin_socket": _build_plugin_socket_backend,
|
|
333
|
+
"vscode_family_plugin_socket": _build_plugin_socket_backend,
|
|
334
|
+
"mcp_tool": _build_mcp_tool_backend,
|
|
335
|
+
"mcp_stdio_server": _build_mcp_tool_backend,
|
|
336
|
+
"vendor_agent_cli": _build_vendor_agent_cli_backend,
|
|
337
|
+
"gillm_gui": _build_gillm_gui_backend,
|
|
338
|
+
"gillm_gui_driver": _build_gillm_gui_backend,
|
|
339
|
+
"os_injector": _build_os_injector_backend,
|
|
340
|
+
"os_keyboard_injector": _build_os_injector_backend,
|
|
341
|
+
"nlp2uri_desktop": _build_nlp2uri_desktop_backend,
|
|
342
|
+
"nlp2uri_desktop_window": _build_nlp2uri_desktop_backend,
|
|
343
|
+
"imgl": _build_imgl_desktop_backend,
|
|
344
|
+
"imgl_vision": _build_imgl_desktop_backend,
|
|
345
|
+
"imgl_desktop": _build_imgl_desktop_backend,
|
|
346
|
+
"imgl_vision_driver": _build_imgl_desktop_backend,
|
|
347
|
+
"vdisplay": _build_vdisplay_control_backend,
|
|
348
|
+
"vdisplay_control": _build_vdisplay_control_backend,
|
|
349
|
+
"vdisplay_semantic_control": _build_vdisplay_control_backend,
|
|
350
|
+
"none": _build_noop_backend,
|
|
351
|
+
"noop": _build_noop_backend,
|
|
352
|
+
"": _build_noop_backend,
|
|
353
|
+
}
|
|
354
|
+
|
|
284
355
|
def build_agent_backend(
|
|
285
356
|
*,
|
|
286
357
|
backend_id: str,
|
|
@@ -296,44 +367,18 @@ def build_agent_backend(
|
|
|
296
367
|
"""
|
|
297
368
|
bid = (backend_id or "").strip().lower().replace("-", "_")
|
|
298
369
|
normalized = normalize_agent_backend_id(backend_id or "")
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if bid == "gillm_gui" or normalized == "gillm_gui_driver":
|
|
312
|
-
return GillmGuiBackend(client=build_gillm_ide_client())
|
|
313
|
-
if bid == "os_injector" or normalized == "os_keyboard_injector":
|
|
314
|
-
profile = os.environ.get("KORU_OS_INJECTOR_PROFILE", "").strip()
|
|
315
|
-
if not profile:
|
|
316
|
-
raise ValueError("os_injector backend requires KORU_OS_INJECTOR_PROFILE")
|
|
317
|
-
raw_cfg = os.environ.get("KORU_OS_INJECTOR_CONFIG", "").strip()
|
|
318
|
-
cfg = Path(raw_cfg).expanduser().resolve() if raw_cfg else None
|
|
319
|
-
return OsInjectorBackend(profile_id=profile, config_path=cfg)
|
|
320
|
-
if bid == "nlp2uri_desktop" or normalized == "nlp2uri_desktop_window":
|
|
321
|
-
dry = os.environ.get("KORU_NLP2URI_DRY_RUN", "").strip().lower() in {
|
|
322
|
-
"1", "true", "yes", "on",
|
|
323
|
-
}
|
|
324
|
-
return Nlp2UriDesktopBackend(dry_run=dry)
|
|
325
|
-
if bid in ("imgl", "imgl_vision", "imgl_desktop") or normalized == "imgl_vision_driver":
|
|
326
|
-
dry = os.environ.get("KORU_IMGL_DRY_RUN", "").strip().lower() in {
|
|
327
|
-
"1", "true", "yes", "on",
|
|
328
|
-
}
|
|
329
|
-
return ImglDesktopBackend(dry_run=dry)
|
|
330
|
-
if bid in ("vdisplay", "vdisplay_control") or normalized == "vdisplay_semantic_control":
|
|
331
|
-
dry = os.environ.get("KORU_VDISPLAY_DRY_RUN", "").strip().lower() in {
|
|
332
|
-
"1", "true", "yes", "on",
|
|
333
|
-
}
|
|
334
|
-
return VdisplayControlBackend(dry_run=dry)
|
|
335
|
-
if bid in ("none", "noop", ""):
|
|
336
|
-
return NoopBackend(reason=noop_reason)
|
|
370
|
+
builder = _BACKEND_BUILDERS.get(bid) or _BACKEND_BUILDERS.get(normalized)
|
|
371
|
+
if builder:
|
|
372
|
+
if "client" in builder.__code__.co_varnames and client is not None:
|
|
373
|
+
return builder(client=client)
|
|
374
|
+
elif "mcp_server" in builder.__code__.co_varnames and mcp_server is not None:
|
|
375
|
+
return builder(mcp_server=mcp_server)
|
|
376
|
+
elif "shell_client_id" in builder.__code__.co_varnames and shell_client_id is not None:
|
|
377
|
+
return builder(shell_client_id=shell_client_id)
|
|
378
|
+
elif "noop_reason" in builder.__code__.co_varnames:
|
|
379
|
+
return builder(noop_reason=noop_reason)
|
|
380
|
+
else:
|
|
381
|
+
return builder()
|
|
337
382
|
raise ValueError(f"unknown agent backend id: {backend_id!r}")
|
|
338
383
|
|
|
339
384
|
|
koru/integrations/imgl_client.py
CHANGED
|
@@ -87,7 +87,8 @@ def imgl_desktop_transport_enabled() -> bool:
|
|
|
87
87
|
|
|
88
88
|
def default_image_path() -> Path:
|
|
89
89
|
if _IMGL_DIRECT:
|
|
90
|
-
|
|
90
|
+
p = _default_image_path()
|
|
91
|
+
return Path(p) if isinstance(p, (str, bytes, os.PathLike)) else p
|
|
91
92
|
raw = os.environ.get("KORU_IMGL_IMAGE", "/tmp/koru-imgl-screen.png").strip()
|
|
92
93
|
return Path(raw).expanduser()
|
|
93
94
|
|
|
@@ -619,6 +619,28 @@ def send_chat(
|
|
|
619
619
|
"fallback_from": "plugin",
|
|
620
620
|
}
|
|
621
621
|
|
|
622
|
+
|
|
623
|
+
def _resolve_vql_chat_target(ide: str, hints: dict) -> dict | None:
|
|
624
|
+
"""Resolve chat target using VQL metadata for precise mouse nav on second monitor (DP-1).
|
|
625
|
+
Used in autonomous PyCharm/JetBrains control via vdisplay + VQL centers (e.g. 1024,640).
|
|
626
|
+
"""
|
|
627
|
+
vql_target = get_vql_target(ide, role="input", name_contains="chat") or get_vql_target(ide, role="input") or get_vql_target(ide, label="chat")
|
|
628
|
+
if not vql_target and ide in ("pycharm", "jetbrains"):
|
|
629
|
+
vql_target = {"click_center": {"x": 1024, "y": 640, "note": "PyCharm/JetBrains editor area on DP-1 second monitor from VQL"}}
|
|
630
|
+
if vql_target:
|
|
631
|
+
return {
|
|
632
|
+
"ok": True,
|
|
633
|
+
"count": 1,
|
|
634
|
+
"selected": {
|
|
635
|
+
"id": vql_target.get("id", "vql-chat"),
|
|
636
|
+
"backend": "vql",
|
|
637
|
+
"role": vql_target.get("role"),
|
|
638
|
+
"click_point": vql_target.get("click_center"),
|
|
639
|
+
"note": f"VQL target from {vql_target.get('source', 'VQL analysis for second monitor')}"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return None
|
|
643
|
+
|
|
622
644
|
canon = _canonical_ide(ide)
|
|
623
645
|
if canon in {"jetbrains", "pycharm"}:
|
|
624
646
|
try:
|
|
@@ -668,22 +690,9 @@ def send_chat(
|
|
|
668
690
|
|
|
669
691
|
selector, found = _find_first_selector(ide=ide, selectors=_chat_selectors_for(ide))
|
|
670
692
|
if selector is None:
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if vql_target:
|
|
674
|
-
# Inject synthetic selector with VQL center for downstream set/click
|
|
693
|
+
found = _resolve_vql_chat_target(ide, hints)
|
|
694
|
+
if found:
|
|
675
695
|
selector = {"role": "input", "name_contains": "Chat"}
|
|
676
|
-
found = {
|
|
677
|
-
"ok": True,
|
|
678
|
-
"count": 1,
|
|
679
|
-
"selected": {
|
|
680
|
-
"id": vql_target.get("id", "vql-chat"),
|
|
681
|
-
"backend": "vql",
|
|
682
|
-
"role": vql_target.get("role"),
|
|
683
|
-
"click_point": vql_target.get("click_center"),
|
|
684
|
-
"note": f"VQL target from {vql_target.get('source')}"
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
696
|
else:
|
|
688
697
|
return {
|
|
689
698
|
"ok": False,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: koru
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.332
|
|
4
4
|
Summary: Closed-loop automation across semcod/* repositories.
|
|
5
5
|
Author: Semcod
|
|
6
6
|
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
@@ -156,11 +156,11 @@ Dynamic: license-file
|
|
|
156
156
|
|
|
157
157
|
## AI Cost Tracking
|
|
158
158
|
|
|
159
|
-
    
|
|
160
|
+
  
|
|
161
161
|
|
|
162
|
-
- 🤖 **LLM usage:** $
|
|
163
|
-
- 👤 **Human dev:** ~$
|
|
162
|
+
- 🤖 **LLM usage:** $27.5767 (438 commits)
|
|
163
|
+
- 👤 **Human dev:** ~$15021 (150.2h @ $100/h, 30min dedup)
|
|
164
164
|
|
|
165
165
|
Generated on 2026-06-11 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
|
|
166
166
|
|
|
@@ -43,7 +43,7 @@ imgl/freshness.py,sha256=DbqXzE8lN1Y8OB7nsdVcHHe1T35GxU0awB5ur2rQQx0,1652
|
|
|
43
43
|
koru/__init__.py,sha256=Vm4rFKBrKGHWUOLhtLm2CNlqBlSmdFNWLAoz711QMqI,3535
|
|
44
44
|
koru/__main__.py,sha256=UOpoyf0hO4es2XGbuRJlM7BOUxoNMA8SjLItKY7Auzc,307
|
|
45
45
|
koru/activity_log.py,sha256=nZuGppo15AsE8l5hI2-z64tGFMxgV59i5FwF2c8NokY,10400
|
|
46
|
-
koru/agent_backend_runtime.py,sha256
|
|
46
|
+
koru/agent_backend_runtime.py,sha256=Kflm3K0LdeLNUkOOr-t5vfyqTWjc2ov9zlhsr-PDr4E,15389
|
|
47
47
|
koru/agent_backends.py,sha256=-QNmG7Ss_fsr8Vm2hURms_2QmrIHojKXyjfjLgLs22s,9338
|
|
48
48
|
koru/agent_cli_helpers.py,sha256=EZe_qTofG84ggZgbakrFhNxsYMELKWlMf4WwbJGVBYs,2689
|
|
49
49
|
koru/agents.py,sha256=fVSy0L_-PQ36FftTk3jhcjiZxz70nSKZMUHAp1ii7ig,12150
|
|
@@ -393,8 +393,8 @@ koru/ide_adapters/shared.py,sha256=duOfFoimxF8OZVcDXOKg3zW190vseEJeolkKVW2acVc,1
|
|
|
393
393
|
koru/ide_adapters/vscode_family.py,sha256=2c6ylhiPI8-1xJHS2kJvlMmmdmpJ-b4khGkSsiJ--jI,5415
|
|
394
394
|
koru/integrations/__init__.py,sha256=cddoUSXZl_lhBs1zhwht5bDwnijj7YF3WY7u1bGz4n4,406
|
|
395
395
|
koru/integrations/imgl_autodiag.py,sha256=Ri2vPgzCJ6jjeyHjL3_RHnJ2F99tuCPfi5ooot4S0YE,355
|
|
396
|
-
koru/integrations/imgl_client.py,sha256=
|
|
397
|
-
koru/integrations/vdisplay_client.py,sha256=
|
|
396
|
+
koru/integrations/imgl_client.py,sha256=Nnoay8KFQcqi7u9r2JWar5fou_CtnM0wWCEYEod3Dy8,10360
|
|
397
|
+
koru/integrations/vdisplay_client.py,sha256=SIKvv0UX8C-6VK4dnhpsyDzENaBi4gbsnJYIpsA4JsY,33173
|
|
398
398
|
koru/queue/__init__.py,sha256=KZlgdUocyznnhtcSsK7yXDJjXPyPZIELLLI7CMWDc_o,985
|
|
399
399
|
koru/queue/human.py,sha256=quuN8RC4DHXwOQMNPC3m8_PWNZDd6hZN--ZlBmY-3Bw,960
|
|
400
400
|
koru/queue/koru_queue_argv.py,sha256=lH78lu7Iqzhx_DNW_llCua74AYkvc43JeEVhFPlJYtk,1235
|
|
@@ -436,7 +436,7 @@ koru/wizard/templates/library.json,sha256=6Eap1pgVjYPT8fNUIsL_dHNc9SYOCKFW3W6vxu
|
|
|
436
436
|
koru/wizard/templates/ml-research.json,sha256=rONHc5XxKrn28qvkG8uTjwHMmA9dVIsqHEoRW9-lOtw,3484
|
|
437
437
|
koru/wizard/templates/registry.json,sha256=9aiJhcO5Uq8WQT5XeUnmQTqv7GS8hYhteUS2FZSrleM,1469
|
|
438
438
|
koru/wizard/templates/web-app.json,sha256=2BjQ5l4BRqcHUzAAK9_D-cT-nCfb8EqeR-l5kF7GIjg,7174
|
|
439
|
-
koru-0.1.
|
|
439
|
+
koru-0.1.332.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
440
440
|
koruapi/__init__.py,sha256=9yJrfnlKhndkf5osgjhsIsvbv4kGM5w8ONgQQcOvznk,747
|
|
441
441
|
koruapi/calibration_validator.py,sha256=4CWwN95cuPn7BdvIUGABjGZoJ81g2dZxcL7TfCmQufk,11733
|
|
442
442
|
koruapi/cli.py,sha256=gy8GGnR9XCSv5PRGpm5J1OCjCvR-V8SY26BmE733Bok,4997
|
|
@@ -591,8 +591,8 @@ koruvision/providers/registry.py,sha256=0GPl4wjK4bP0hET2SpDJ3gkxTjLauVVBokIQXpKL
|
|
|
591
591
|
koruvision/providers/screencast_session.py,sha256=Q8Q06Kso3jJGv3ZieG9ego1c2XwD_LjwjQ2xTI4MZMg,2087
|
|
592
592
|
nlp2imgl/__init__.py,sha256=0vZk1E9F8ViPi9nK_de85HrnzoOpuQ-gzmNqrQDBVpE,95
|
|
593
593
|
nlp2imgl/control.py,sha256=3QXdx8QG_HHIO2PCslTzbd-pAIjIFuWiNh36Wj4r-QY,1646
|
|
594
|
-
koru-0.1.
|
|
595
|
-
koru-0.1.
|
|
596
|
-
koru-0.1.
|
|
597
|
-
koru-0.1.
|
|
598
|
-
koru-0.1.
|
|
594
|
+
koru-0.1.332.dist-info/METADATA,sha256=2mQkMS1LaXrtoacYPZULLcNHnvrFw5AHG2j9OpCHMuU,72766
|
|
595
|
+
koru-0.1.332.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
596
|
+
koru-0.1.332.dist-info/entry_points.txt,sha256=nLNoiTotankEuZhByzdP0y7phHExiKc0YmLU-hQvieY,162
|
|
597
|
+
koru-0.1.332.dist-info/top_level.txt,sha256=99eWAyPWuPiwn9sKJjELlg4J5XXUDCpKvuWe33nbrSk,103
|
|
598
|
+
koru-0.1.332.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|