OpenJarvis 1.0.4.dev1012__py3-none-any.whl → 1.0.4.dev1014__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.
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections import deque
6
- from typing import TYPE_CHECKING, Dict, List, Set
6
+ from typing import TYPE_CHECKING, Dict, List, Optional, Set
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from openjarvis.skills.types import SkillManifest
@@ -12,6 +12,13 @@ if TYPE_CHECKING:
12
12
  class DependencyCycleError(Exception):
13
13
  """Raised when a cycle is detected in the skill dependency graph."""
14
14
 
15
+ def __init__(self, message: str, skills: Optional[Set[str]] = None) -> None:
16
+ super().__init__(message)
17
+ # The skills involved in (or downstream of) the cycle, so callers
18
+ # can prune exactly those rather than parsing the message string
19
+ # or discarding the whole graph (#781).
20
+ self.skills: Set[str] = skills if skills is not None else set()
21
+
15
22
 
16
23
  class DepthExceededError(Exception):
17
24
  """Raised when the dependency depth exceeds the configured maximum."""
@@ -101,9 +108,11 @@ def validate_dependencies(
101
108
  queue.append(dependent)
102
109
 
103
110
  if len(order) != len(graph):
111
+ cyclic = set(graph) - set(order)
104
112
  raise DependencyCycleError(
105
113
  "Cycle detected in skill dependency graph. "
106
- f"Skills involved: {set(graph) - set(order)}"
114
+ f"Skills involved: {cyclic}",
115
+ skills=cyclic,
107
116
  )
108
117
 
109
118
  # --- Depth enforcement via DFS ---
@@ -3,18 +3,21 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import html
6
+ import logging
6
7
  from pathlib import Path
7
8
  from typing import Any, Dict, List, Optional
8
9
 
9
10
  from openjarvis.core.events import EventBus
10
11
  from openjarvis.core.paths import get_config_dir
11
- from openjarvis.skills.dependency import validate_dependencies
12
+ from openjarvis.skills.dependency import DependencyCycleError, validate_dependencies
12
13
  from openjarvis.skills.executor import SkillExecutor, SkillResult
13
14
  from openjarvis.skills.loader import discover_skills
14
15
  from openjarvis.skills.tool_adapter import SkillTool
15
16
  from openjarvis.skills.types import SkillManifest
16
17
  from openjarvis.tools._stubs import BaseTool, ToolExecutor
17
18
 
19
+ logger = logging.getLogger(__name__)
20
+
18
21
 
19
22
  class SkillManager:
20
23
  """Coordinate skill discovery, resolution, catalog generation, and execution.
@@ -86,13 +89,41 @@ class SkillManager:
86
89
 
87
90
  # Validate the dependency graph after loading skills
88
91
  if self._skills:
89
- validate_dependencies(self._skills)
92
+ self._prune_dependency_cycles()
90
93
 
91
94
  # Load optimization overlays (Plan 2A) — always runs, even when no
92
95
  # paths are provided, so callers can apply overlays to skills loaded
93
96
  # via other means.
94
97
  self._load_overlays()
95
98
 
99
+ def _prune_dependency_cycles(self) -> None:
100
+ """Validate the dependency graph, iteratively dropping any skills
101
+ involved in a cycle so the rest of discovery still succeeds (#781).
102
+
103
+ Previously ``validate_dependencies`` was called unguarded: a single
104
+ cyclic pair raised ``DependencyCycleError`` straight out of
105
+ ``discover()``, which crashed CLI callers outright and, in
106
+ ``SystemBuilder``, was caught by a broad exception handler that
107
+ silently discarded every discovered skill — not just the cyclic
108
+ ones. Each pass removes exactly the skills the error identifies as
109
+ cyclic and re-validates, since removing them can resolve skills
110
+ that only *looked* stuck because of an edge into the cycle.
111
+ """
112
+ while self._skills:
113
+ try:
114
+ validate_dependencies(self._skills)
115
+ return
116
+ except DependencyCycleError as exc:
117
+ if not exc.skills:
118
+ # No indication of which skills to drop; bail out
119
+ # rather than looping forever.
120
+ return
121
+ for name in sorted(exc.skills):
122
+ logger.warning(
123
+ "Skill '%s' removed: part of a dependency cycle", name
124
+ )
125
+ self._skills.pop(name, None)
126
+
96
127
  def _load_overlays(self) -> None:
97
128
  """Apply optimization overlays to discovered skills.
98
129
 
@@ -20,8 +20,32 @@ _MAX_TIMEOUT = 300
20
20
  # Default timeout (seconds)
21
21
  _DEFAULT_TIMEOUT = 30
22
22
 
23
- # Environment variables always passed through
24
- _BASE_ENV_KEYS = ("PATH", "HOME", "USER", "LANG", "TERM")
23
+ # Environment variables always passed through on every platform.
24
+ _PORTABLE_ENV_KEYS = (
25
+ "PATH",
26
+ "HOME",
27
+ "USER",
28
+ "LANG",
29
+ "TERM",
30
+ )
31
+
32
+ # Windows needs these to bootstrap ordinary child processes: missing
33
+ # SystemRoot breaks Winsock/DNS initialization, while missing LOCALAPPDATA
34
+ # can make the Store Python launcher provision a fresh interpreter in cwd.
35
+ # Keep them conditional so a POSIX host that happens to define similarly
36
+ # named variables does not expand the tool's minimal environment.
37
+ _WINDOWS_ENV_KEYS = (
38
+ "SystemRoot",
39
+ "SystemDrive",
40
+ "COMSPEC",
41
+ "PATHEXT",
42
+ "TEMP",
43
+ "TMP",
44
+ "USERPROFILE",
45
+ "LOCALAPPDATA",
46
+ "APPDATA",
47
+ )
48
+ _BASE_ENV_KEYS = _PORTABLE_ENV_KEYS + (_WINDOWS_ENV_KEYS if os.name == "nt" else ())
25
49
 
26
50
 
27
51
  @ToolRegistry.register("shell_exec")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: OpenJarvis
3
- Version: 1.0.4.dev1012
3
+ Version: 1.0.4.dev1014
4
4
  Summary: OpenJarvis — modular AI assistant backend with composable intelligence primitives
5
5
  Project-URL: Homepage, https://github.com/open-jarvis/OpenJarvis
6
6
  Project-URL: Documentation, https://open-jarvis.github.io/OpenJarvis/
@@ -768,12 +768,12 @@ openjarvis/sessions/__init__.py,sha256=kv78IvoPDvXK4X7TeIZxiMlpXWQrQmtnqEePdzDCf
768
768
  openjarvis/sessions/compression.py,sha256=KB0VoCVXa1j-_4RJafMTLAscCjIO9fpSEEch4v6nrx0,3677
769
769
  openjarvis/sessions/session.py,sha256=mXlftYDluF2TX0M9-IwGSKg0X-D_VFjwQp6y85w7wYI,12202
770
770
  openjarvis/skills/__init__.py,sha256=Ho43L58RscRL4P8yJx4b_T6GCLgkYDXoISVlDhsfMOs,1310
771
- openjarvis/skills/dependency.py,sha256=-dqUUXiG0sWazVOo3QfhPew5Ug3XPid1_PQuVsfgzQ0,5939
771
+ openjarvis/skills/dependency.py,sha256=zYKIacRqbexUfpBbF27Z4bhXZiwJO08MofsSohFRyBA,6384
772
772
  openjarvis/skills/executor.py,sha256=EyTTbOPn0rEfsTvJKq5okRCbzjUdT8OUyxQaYD9NGyI,7599
773
773
  openjarvis/skills/importer.py,sha256=-3htZU64yWbXbKbqoX2wBOpQ32ne_clulAs3vs4-f0o,9335
774
774
  openjarvis/skills/index.py,sha256=UpypJzu6EkBWdgzHcZqX-wmxBYbpE3NMFiroQSxVkVQ,3123
775
775
  openjarvis/skills/loader.py,sha256=Sa-FZCQtZwo7me03aCPKhECtxFh4AsSsR8lII9Y2yB0,10929
776
- openjarvis/skills/manager.py,sha256=vWcuNQrfwzYs4t9GCm_JehxLxy0Hcw4qPnYL3KWYhNg,16597
776
+ openjarvis/skills/manager.py,sha256=OcEjilLQSMAfr9w75O2qptg-gTp3vY8KLlDc_7qb3K0,18037
777
777
  openjarvis/skills/overlay.py,sha256=rcZNbaWRNWN5MoPkZjfEpzmivogkSOAcI_bco_Ywun8,4832
778
778
  openjarvis/skills/parser.py,sha256=M72s4twtAvG8fv5iGtXr3iwQzyXL3oiMl-qfL0pAZ-4,8811
779
779
  openjarvis/skills/security.py,sha256=on53PIvVPo-f3voKrA2-3L-skbJdfjUFyXEirGNexZw,1797
@@ -891,7 +891,7 @@ openjarvis/tools/proactive_tools.py,sha256=Ej89KDO5kucq4X9WYbjIxgJ2ERvC2jTg6BtO_
891
891
  openjarvis/tools/repl.py,sha256=5UYWDYD2VYErNhBr9Qibg87nZ6BvfitVcjithL1Iphk,10289
892
892
  openjarvis/tools/retrieval.py,sha256=rx7_8eI0RjzGxQmeS6dNcNKskjcRX3fkbqyk8L0Yf08,2847
893
893
  openjarvis/tools/scan_chunks.py,sha256=AV3OrPQAJTARGf4QqxLmTHtW98tPiEqd03Sh4pko43c,6699
894
- openjarvis/tools/shell_exec.py,sha256=bx9rfjQz3HZWl2B5p4XIwb2xEs1x4p_bKdfxI85IeGo,7143
894
+ openjarvis/tools/shell_exec.py,sha256=HqlfLsBj29ujJyMJgVIL4jFVLOlBmvc7WFreHS_Y-Gg,7801
895
895
  openjarvis/tools/skill_manage.py,sha256=ld6tmulz_LCuug5BVl9aBpGCY5spUjQ0r7ocapqLnvU,5378
896
896
  openjarvis/tools/storage_tools.py,sha256=TWdPQszrlzJJ78La_iOXVqSHHLMmuvq_U1VXhA1gMT0,10274
897
897
  openjarvis/tools/text_to_speech.py,sha256=L4OL0ZKnNvI1DZEnRKK6UvxuDA6uTm9dD0pDxuqDjAs,3577
@@ -949,8 +949,8 @@ _node_modules/whatsapp_baileys_bridge/package-lock.json,sha256=MPMyCqNAzQGB16-hm
949
949
  _node_modules/whatsapp_baileys_bridge/package.json,sha256=iIdmM7Pg2uas-RBOtA2PlYHas_Fc8YCKvPGOJHS2YTg,410
950
950
  _node_modules/whatsapp_baileys_bridge/tsconfig.json,sha256=CZwRjhfDvWEr6IBdM_5_2Mgtam53nUHS8kNCHXyfLhY,258
951
951
  _node_modules/whatsapp_baileys_bridge/src/bridge.ts,sha256=QFrrqy2sSR01qvw6xYB0opuF4fh3ytZe5X2086Jyxs8,4418
952
- openjarvis-1.0.4.dev1012.dist-info/METADATA,sha256=R_u0rSwpy41Vq9EJN1pk0eTL0EBQTvI8BHXP9v6gQiY,17250
953
- openjarvis-1.0.4.dev1012.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
954
- openjarvis-1.0.4.dev1012.dist-info/entry_points.txt,sha256=_KQ__IsIkCPIMrokIXk0U5Fl8QijcJGncFuX3ZxP4TY,91
955
- openjarvis-1.0.4.dev1012.dist-info/licenses/LICENSE,sha256=rGF-zdt__rJ6I5xsnIFFISMGuqkOI-5pSEm_PO-xB0M,10773
956
- openjarvis-1.0.4.dev1012.dist-info/RECORD,,
952
+ openjarvis-1.0.4.dev1014.dist-info/METADATA,sha256=sB8AfCq9Ck5rN-9a27WbKiXTfutt-WUUaBcnAD63Zf0,17250
953
+ openjarvis-1.0.4.dev1014.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
954
+ openjarvis-1.0.4.dev1014.dist-info/entry_points.txt,sha256=_KQ__IsIkCPIMrokIXk0U5Fl8QijcJGncFuX3ZxP4TY,91
955
+ openjarvis-1.0.4.dev1014.dist-info/licenses/LICENSE,sha256=rGF-zdt__rJ6I5xsnIFFISMGuqkOI-5pSEm_PO-xB0M,10773
956
+ openjarvis-1.0.4.dev1014.dist-info/RECORD,,