jarvix-core 0.1.0__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.
- jarvix_core-0.1.0/.gitignore +30 -0
- jarvix_core-0.1.0/LICENSE +21 -0
- jarvix_core-0.1.0/Makefile +34 -0
- jarvix_core-0.1.0/PKG-INFO +23 -0
- jarvix_core-0.1.0/README.md +1 -0
- jarvix_core-0.1.0/pyproject.toml +33 -0
- jarvix_core-0.1.0/src/jarvix/core/__init__.py +2 -0
- jarvix_core-0.1.0/src/jarvix/core/graph/__init__.py +3 -0
- jarvix_core-0.1.0/src/jarvix/core/graph/base.py +175 -0
- jarvix_core-0.1.0/src/jarvix/core/graph/impl.py +402 -0
- jarvix_core-0.1.0/tests/conftest.py +50 -0
- jarvix_core-0.1.0/tests/core/graph/helpers.py +62 -0
- jarvix_core-0.1.0/tests/core/graph/test_branch.py +89 -0
- jarvix_core-0.1.0/tests/core/graph/test_combine.py +82 -0
- jarvix_core-0.1.0/tests/core/graph/test_conditional.py +200 -0
- jarvix_core-0.1.0/tests/core/graph/test_graph_cache.py +148 -0
- jarvix_core-0.1.0/tests/core/graph/test_graph_operands.py +160 -0
- jarvix_core-0.1.0/tests/core/graph/test_graph_showcase.py +55 -0
- jarvix_core-0.1.0/tests/core/graph/test_loops.py +46 -0
- jarvix_core-0.1.0/tests/core/graph/test_rshift.py +232 -0
- jarvix_core-0.1.0/tests/core/test_imports.py +19 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
*.egg
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.eggs/
|
|
9
|
+
|
|
10
|
+
# Virtual environments
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# Tooling caches
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Environment
|
|
23
|
+
.env
|
|
24
|
+
.env.*
|
|
25
|
+
!.env.example
|
|
26
|
+
|
|
27
|
+
# Editors / OS
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/
|
|
30
|
+
.DS_Store
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 loctvl842
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
APP_NAME := `sed -n 's/^ *name.*=.*"\([^"]*\)".*/\1/p' pyproject.toml`
|
|
2
|
+
APP_VERSION := `sed -n 's/^ *version.*=.*"\([^"]*\)".*/\1/p' pyproject.toml`
|
|
3
|
+
|
|
4
|
+
# Makefile help
|
|
5
|
+
|
|
6
|
+
.PHONY: header
|
|
7
|
+
header:
|
|
8
|
+
@printf "\033[34mEnvironment\033[0m"
|
|
9
|
+
@printf "\n"
|
|
10
|
+
@printf "\033[34m---------------------------------------------------------------\033[0m"
|
|
11
|
+
@printf "\n"
|
|
12
|
+
@printf "\033[33mAPP_NAME: \033[0m"
|
|
13
|
+
@printf "\033[35m$(APP_NAME)\033[0m"
|
|
14
|
+
@printf "\n"
|
|
15
|
+
@printf "\033[33mAPP_VERSION: \033[0m"
|
|
16
|
+
@printf "\033[35m$(APP_VERSION)\033[0m"
|
|
17
|
+
@printf "\n\n"
|
|
18
|
+
|
|
19
|
+
.PHONY: usage
|
|
20
|
+
usage:
|
|
21
|
+
@printf "\033[034mUsage\033[0m"
|
|
22
|
+
@printf "\n"
|
|
23
|
+
@printf "\033[34m---------------------------------------------------------------\033[0m"
|
|
24
|
+
@printf "\n"
|
|
25
|
+
@printf "\033[37mmake [options] \033[0m"
|
|
26
|
+
@printf "\n\n"
|
|
27
|
+
|
|
28
|
+
.PHONY: options
|
|
29
|
+
options:
|
|
30
|
+
@printf "\033[34mOptions\033[0m"
|
|
31
|
+
@printf "\n"
|
|
32
|
+
@printf "\033[34m---------------------------------------------------------------\033[0m"
|
|
33
|
+
@printf "\n"
|
|
34
|
+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-22s\033[0m %s\n", $$1, $$2}' | sort
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: jarvix-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Jarvix core: graph primitives
|
|
5
|
+
Project-URL: Homepage, https://github.com/loctvl842/jarvix
|
|
6
|
+
Project-URL: Repository, https://github.com/loctvl842/jarvix
|
|
7
|
+
Project-URL: Issues, https://github.com/loctvl842/jarvix/issues
|
|
8
|
+
Author-email: loctvl842 <loclepnvx@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,cli,multiplexer,tmux
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Jarvix Core
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Jarvix Core
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[tool.hatch.build.targets.wheel]
|
|
6
|
+
packages = ["src/jarvix"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "jarvix-core"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
description = "Jarvix core: graph primitives"
|
|
12
|
+
authors = [{ name = "loctvl842", email = "loclepnvx@gmail.com" }]
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
requires-python = ">=3.12"
|
|
15
|
+
license = "MIT"
|
|
16
|
+
license-files = ["LICENSE"]
|
|
17
|
+
keywords = ["ai", "agents", "tmux", "multiplexer", "cli"]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Operating System :: MacOS",
|
|
23
|
+
"Operating System :: POSIX :: Linux",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
]
|
|
28
|
+
dependencies = []
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/loctvl842/jarvix"
|
|
32
|
+
Repository = "https://github.com/loctvl842/jarvix"
|
|
33
|
+
Issues = "https://github.com/loctvl842/jarvix/issues"
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, overload
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class Condition:
|
|
11
|
+
"""Membership of an edge in one arm of a conditional: it is taken only when that arm is chosen."""
|
|
12
|
+
|
|
13
|
+
group: ConditionalBranch
|
|
14
|
+
arm: int
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class Edge:
|
|
19
|
+
"""A link to `target`. Solid (no conditions) when the target always runs.
|
|
20
|
+
|
|
21
|
+
Dashed (conditions, outermost first) when the target belongs to arms of
|
|
22
|
+
conditionals. Only the edges into a conditional are tagged; where the arms
|
|
23
|
+
join again is implied by the graph shape.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
target: Node
|
|
27
|
+
conditions: tuple[Condition, ...] = ()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Graph(abc.ABC):
|
|
31
|
+
@property
|
|
32
|
+
@abc.abstractmethod
|
|
33
|
+
def nodes(self) -> Mapping[str, Node]:
|
|
34
|
+
"""All nodes inside graph"""
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
@abc.abstractmethod
|
|
38
|
+
def sources(self) -> set[Node]:
|
|
39
|
+
"""Identify source nodes (nodes with no imcoming edges)"""
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
@abc.abstractmethod
|
|
43
|
+
def sinks(self) -> set[Node]:
|
|
44
|
+
"""Identify sink nodes (nodes with no outgoing edges)"""
|
|
45
|
+
|
|
46
|
+
@abc.abstractmethod
|
|
47
|
+
def compile(self) -> None:
|
|
48
|
+
"""Validate graph and prepare it to run"""
|
|
49
|
+
|
|
50
|
+
@abc.abstractmethod
|
|
51
|
+
async def arun(self, input: Any, *, max_steps: int = 100): ...
|
|
52
|
+
|
|
53
|
+
@abc.abstractmethod
|
|
54
|
+
def run(self, input: Any, *, max_steps: int = 100): ...
|
|
55
|
+
|
|
56
|
+
@overload
|
|
57
|
+
def __rshift__(self, other: Node) -> Graph: ...
|
|
58
|
+
|
|
59
|
+
@overload
|
|
60
|
+
def __rshift__(self, other: Graph) -> Graph: ...
|
|
61
|
+
|
|
62
|
+
@overload
|
|
63
|
+
def __rshift__(self, other: Branch) -> Graph: ...
|
|
64
|
+
|
|
65
|
+
@overload
|
|
66
|
+
def __rshift__(self, other: ConditionalBranch) -> Graph: ...
|
|
67
|
+
|
|
68
|
+
@abc.abstractmethod
|
|
69
|
+
def __rshift__(self, other: Node | Graph | Branch | ConditionalBranch) -> Graph: ...
|
|
70
|
+
|
|
71
|
+
@abc.abstractmethod
|
|
72
|
+
def __and__(self, other: Node | Graph | Branch | ConditionalBranch) -> Branch: ...
|
|
73
|
+
|
|
74
|
+
@abc.abstractmethod
|
|
75
|
+
def __or__(self, other: Node | Graph | Branch | ConditionalBranch) -> ConditionalBranch: ...
|
|
76
|
+
|
|
77
|
+
def __getattr__(self, node_name: str) -> Graph: ...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Node(abc.ABC):
|
|
81
|
+
alias: str
|
|
82
|
+
call: callable[..., Any]
|
|
83
|
+
edges: set[Edge]
|
|
84
|
+
|
|
85
|
+
def __init__(self, name: str):
|
|
86
|
+
self._name = name
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def name(self) -> str:
|
|
90
|
+
return self._name
|
|
91
|
+
|
|
92
|
+
def __eq__(self, other: object) -> bool:
|
|
93
|
+
if not isinstance(other, Node):
|
|
94
|
+
return NotImplemented
|
|
95
|
+
return self.name == other.name
|
|
96
|
+
|
|
97
|
+
def __hash__(self) -> int:
|
|
98
|
+
return hash(self.name)
|
|
99
|
+
|
|
100
|
+
def __repr__(self) -> str:
|
|
101
|
+
return f"{type(self).__name__}({self.name})"
|
|
102
|
+
|
|
103
|
+
@overload
|
|
104
|
+
def __rshift__(self, other: Node) -> Graph: ...
|
|
105
|
+
|
|
106
|
+
@overload
|
|
107
|
+
def __rshift__(self, other: Graph) -> Graph: ...
|
|
108
|
+
|
|
109
|
+
@overload
|
|
110
|
+
def __rshift__(self, other: Branch) -> Graph: ...
|
|
111
|
+
|
|
112
|
+
@overload
|
|
113
|
+
def __rshift__(self, other: ConditionalBranch) -> Graph: ...
|
|
114
|
+
|
|
115
|
+
@overload
|
|
116
|
+
def __and__(self, other: Node | Graph | Branch | ConditionalBranch) -> Branch: ...
|
|
117
|
+
|
|
118
|
+
@overload
|
|
119
|
+
def __or__(self, other: Node | Graph | Branch | ConditionalBranch) -> ConditionalBranch: ...
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class Branch(abc.ABC):
|
|
123
|
+
"""Members that all run. A member is a Node, a Graph or a ConditionalBranch, never a Branch."""
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
@abc.abstractmethod
|
|
127
|
+
def members(self) -> tuple[Node | Graph | ConditionalBranch, ...]:
|
|
128
|
+
"""Direct members of the branch, never what they point to"""
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
@abc.abstractmethod
|
|
132
|
+
def sources(self) -> frozenset[Node]:
|
|
133
|
+
"""Nodes a predecessor connects to"""
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
@abc.abstractmethod
|
|
137
|
+
def sinks(self) -> frozenset[Node]:
|
|
138
|
+
"""Nodes a successor connects from"""
|
|
139
|
+
|
|
140
|
+
@abc.abstractmethod
|
|
141
|
+
def __rshift__(self, other: Node | Graph | Branch | ConditionalBranch) -> Graph: ...
|
|
142
|
+
|
|
143
|
+
@abc.abstractmethod
|
|
144
|
+
def __and__(self, other: Node | Graph | Branch | ConditionalBranch) -> Branch: ...
|
|
145
|
+
|
|
146
|
+
@abc.abstractmethod
|
|
147
|
+
def __or__(self, other: Node | Graph | Branch | ConditionalBranch) -> ConditionalBranch: ...
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class ConditionalBranch(abc.ABC):
|
|
151
|
+
"""Alternatives of which exactly one runs. An arm is a Node, a Graph or a Branch, never a ConditionalBranch."""
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
@abc.abstractmethod
|
|
155
|
+
def arms(self) -> tuple[Node | Graph | Branch, ...]:
|
|
156
|
+
"""Direct arms of the conditional, never what they point to"""
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
@abc.abstractmethod
|
|
160
|
+
def sources(self) -> frozenset[Node]:
|
|
161
|
+
"""Nodes a predecessor connects to (the first nodes of every arm)"""
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
@abc.abstractmethod
|
|
165
|
+
def sinks(self) -> frozenset[Node]:
|
|
166
|
+
"""Nodes a successor connects from (the last nodes of every arm)"""
|
|
167
|
+
|
|
168
|
+
@abc.abstractmethod
|
|
169
|
+
def __rshift__(self, other: Node | Graph | Branch | ConditionalBranch) -> Graph: ...
|
|
170
|
+
|
|
171
|
+
@abc.abstractmethod
|
|
172
|
+
def __and__(self, other: Node | Graph | Branch | ConditionalBranch) -> Branch: ...
|
|
173
|
+
|
|
174
|
+
@abc.abstractmethod
|
|
175
|
+
def __or__(self, other: Node | Graph | Branch | ConditionalBranch) -> ConditionalBranch: ...
|