trellis-pipelines 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.
- trellis_pipelines-0.1.0/LICENSE +21 -0
- trellis_pipelines-0.1.0/PKG-INFO +180 -0
- trellis_pipelines-0.1.0/README.md +109 -0
- trellis_pipelines-0.1.0/pyproject.toml +104 -0
- trellis_pipelines-0.1.0/scripts/benchmark.py +0 -0
- trellis_pipelines-0.1.0/setup.cfg +4 -0
- trellis_pipelines-0.1.0/trellis/__init__.py +0 -0
- trellis_pipelines-0.1.0/trellis/exceptions.py +102 -0
- trellis_pipelines-0.1.0/trellis/execution/__init__.py +0 -0
- trellis_pipelines-0.1.0/trellis/execution/blackboard.py +59 -0
- trellis_pipelines-0.1.0/trellis/execution/dag.py +610 -0
- trellis_pipelines-0.1.0/trellis/execution/orchestrator.py +318 -0
- trellis_pipelines-0.1.0/trellis/execution/prefect_adapter.py +39 -0
- trellis_pipelines-0.1.0/trellis/execution/run_queue.py +112 -0
- trellis_pipelines-0.1.0/trellis/execution/template.py +348 -0
- trellis_pipelines-0.1.0/trellis/models/__init__.py +6 -0
- trellis_pipelines-0.1.0/trellis/models/document.py +256 -0
- trellis_pipelines-0.1.0/trellis/models/handles.py +168 -0
- trellis_pipelines-0.1.0/trellis/models/pipeline.py +524 -0
- trellis_pipelines-0.1.0/trellis/models/plan.py +171 -0
- trellis_pipelines-0.1.0/trellis/registry/__init__.py +12 -0
- trellis_pipelines-0.1.0/trellis/registry/finance_functions.py +1126 -0
- trellis_pipelines-0.1.0/trellis/registry/functions.py +105 -0
- trellis_pipelines-0.1.0/trellis/registry/schema.py +54 -0
- trellis_pipelines-0.1.0/trellis/tools/__init__.py +12 -0
- trellis_pipelines-0.1.0/trellis/tools/base.py +129 -0
- trellis_pipelines-0.1.0/trellis/tools/decorators.py +203 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/__init__.py +33 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/compute.py +115 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/document.py +827 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/export.py +448 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/extract.py +522 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/extract_fields.py +393 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/fetch.py +344 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/llm.py +209 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/load_schema.py +318 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/mock.py +57 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/search.py +187 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/select.py +185 -0
- trellis_pipelines-0.1.0/trellis/tools/impls/store.py +36 -0
- trellis_pipelines-0.1.0/trellis/tools/registry.py +190 -0
- trellis_pipelines-0.1.0/trellis/validation/__init__.py +1 -0
- trellis_pipelines-0.1.0/trellis/validation/contract.py +304 -0
- trellis_pipelines-0.1.0/trellis/validation/graph.py +273 -0
- trellis_pipelines-0.1.0/trellis_api/__init__.py +7 -0
- trellis_pipelines-0.1.0/trellis_api/main.py +50 -0
- trellis_pipelines-0.1.0/trellis_api/routers/__init__.py +6 -0
- trellis_pipelines-0.1.0/trellis_api/routers/pipelines.py +224 -0
- trellis_pipelines-0.1.0/trellis_api/routers/plans.py +18 -0
- trellis_pipelines-0.1.0/trellis_api/schemas.py +88 -0
- trellis_pipelines-0.1.0/trellis_cli/__init__.py +5 -0
- trellis_pipelines-0.1.0/trellis_cli/main.py +549 -0
- trellis_pipelines-0.1.0/trellis_mcp/__init__.py +3 -0
- trellis_pipelines-0.1.0/trellis_mcp/server.py +0 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/PKG-INFO +180 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/SOURCES.txt +58 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/dependency_links.txt +1 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/entry_points.txt +2 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/requires.txt +25 -0
- trellis_pipelines-0.1.0/trellis_pipelines.egg-info/top_level.txt +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ciaran Davies
|
|
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,180 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trellis-pipelines
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Modular agentic pipeline system for document and data workflows
|
|
5
|
+
Author: Ciaran Davies
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ciaran Davies
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/your-org/trellis
|
|
29
|
+
Project-URL: Repository, https://github.com/your-org/trellis
|
|
30
|
+
Project-URL: Documentation, https://your-org.github.io/trellis
|
|
31
|
+
Project-URL: Bug Tracker, https://github.com/your-org/trellis/issues
|
|
32
|
+
Keywords: pipeline,agentic,dag,document,extraction,llm,pdf,sec,etl,workflow
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Intended Audience :: Science/Research
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Operating System :: OS Independent
|
|
38
|
+
Classifier: Programming Language :: Python :: 3
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
42
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
43
|
+
Classifier: Topic :: Office/Business
|
|
44
|
+
Classifier: Typing :: Typed
|
|
45
|
+
Requires-Python: >=3.12
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
License-File: LICENSE
|
|
48
|
+
Requires-Dist: pydantic>=2.0
|
|
49
|
+
Requires-Dist: pyyaml>=6.0
|
|
50
|
+
Requires-Dist: litellm>=1.0.0
|
|
51
|
+
Requires-Dist: PyMuPDF>=1.24.0
|
|
52
|
+
Requires-Dist: pypdf>=3.0.0
|
|
53
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
54
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
55
|
+
Requires-Dist: typer>=0.9
|
|
56
|
+
Provides-Extra: api
|
|
57
|
+
Requires-Dist: fastapi>=0.104; extra == "api"
|
|
58
|
+
Requires-Dist: uvicorn[standard]>=0.24; extra == "api"
|
|
59
|
+
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
61
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
62
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
63
|
+
Requires-Dist: httpx>=0.24; extra == "dev"
|
|
64
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
65
|
+
Requires-Dist: isort>=5.12; extra == "dev"
|
|
66
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
67
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
68
|
+
Provides-Extra: all
|
|
69
|
+
Requires-Dist: trellis-pipelines[api]; extra == "all"
|
|
70
|
+
Dynamic: license-file
|
|
71
|
+
|
|
72
|
+
# Trellis
|
|
73
|
+
|
|
74
|
+
An agentic solution for pipeline planning and execution within controlled environments.
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
### Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Usage
|
|
85
|
+
|
|
86
|
+
#### CLI
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Validate a pipeline
|
|
90
|
+
trellis validate pipelines/example.yaml
|
|
91
|
+
|
|
92
|
+
# Run a pipeline
|
|
93
|
+
trellis run pipelines/example.yaml
|
|
94
|
+
|
|
95
|
+
# Generate a plan from a goal
|
|
96
|
+
trellis plan "Extract and analyze market data"
|
|
97
|
+
|
|
98
|
+
# Generate a pipeline from a goal
|
|
99
|
+
trellis generate "Extract and analyze market data" -o output.yaml
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### API
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Start the API server
|
|
106
|
+
python -m trellis_api.main
|
|
107
|
+
|
|
108
|
+
# Create a pipeline
|
|
109
|
+
curl -X POST http://localhost:8000/pipelines \
|
|
110
|
+
-H "Content-Type: application/json" \
|
|
111
|
+
-d '{
|
|
112
|
+
"id": "example_pipeline",
|
|
113
|
+
"goal": "Process data",
|
|
114
|
+
"tasks": []
|
|
115
|
+
}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Python Library
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from trellis.models.pipeline import Pipeline
|
|
122
|
+
from trellis.execution.dag import DAGExecutor
|
|
123
|
+
|
|
124
|
+
pipeline = Pipeline(
|
|
125
|
+
id="my_pipeline",
|
|
126
|
+
goal="Extract and process data",
|
|
127
|
+
tasks=[]
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
executor = DAGExecutor()
|
|
131
|
+
results = executor.execute({})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Architecture
|
|
135
|
+
|
|
136
|
+
See [docs/architecture.md](docs/specifications/ARCHITECTURE.md) for detailed architecture documentation.
|
|
137
|
+
|
|
138
|
+
## Project Structure
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
trellis/
|
|
142
|
+
├── trellis/ # Core library (shared)
|
|
143
|
+
│ ├── models/ # Pydantic DSL models
|
|
144
|
+
│ ├── validation/ # DAG and contract validation
|
|
145
|
+
│ ├── execution/ # Execution engine
|
|
146
|
+
│ └── tools/ # Tool protocol and implementations
|
|
147
|
+
├── trelis_api/ # FastAPI server
|
|
148
|
+
├── trelis_mcp/ # MCP server
|
|
149
|
+
├── trelis_cli/ # CLI interface
|
|
150
|
+
├── data/ # Dataset generation
|
|
151
|
+
├── tests/ # Test suite
|
|
152
|
+
├── docs/ # Documentation
|
|
153
|
+
└── scripts/ # Utility scripts
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
### Testing
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pytest tests/ -v
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Linting
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
black .
|
|
168
|
+
isort .
|
|
169
|
+
mypy trellis/
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Building
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
python -m build
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
See LICENSE file for details.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Trellis
|
|
2
|
+
|
|
3
|
+
An agentic solution for pipeline planning and execution within controlled environments.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install -e .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Usage
|
|
14
|
+
|
|
15
|
+
#### CLI
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Validate a pipeline
|
|
19
|
+
trellis validate pipelines/example.yaml
|
|
20
|
+
|
|
21
|
+
# Run a pipeline
|
|
22
|
+
trellis run pipelines/example.yaml
|
|
23
|
+
|
|
24
|
+
# Generate a plan from a goal
|
|
25
|
+
trellis plan "Extract and analyze market data"
|
|
26
|
+
|
|
27
|
+
# Generate a pipeline from a goal
|
|
28
|
+
trellis generate "Extract and analyze market data" -o output.yaml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### API
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Start the API server
|
|
35
|
+
python -m trellis_api.main
|
|
36
|
+
|
|
37
|
+
# Create a pipeline
|
|
38
|
+
curl -X POST http://localhost:8000/pipelines \
|
|
39
|
+
-H "Content-Type: application/json" \
|
|
40
|
+
-d '{
|
|
41
|
+
"id": "example_pipeline",
|
|
42
|
+
"goal": "Process data",
|
|
43
|
+
"tasks": []
|
|
44
|
+
}'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### Python Library
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from trellis.models.pipeline import Pipeline
|
|
51
|
+
from trellis.execution.dag import DAGExecutor
|
|
52
|
+
|
|
53
|
+
pipeline = Pipeline(
|
|
54
|
+
id="my_pipeline",
|
|
55
|
+
goal="Extract and process data",
|
|
56
|
+
tasks=[]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
executor = DAGExecutor()
|
|
60
|
+
results = executor.execute({})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
See [docs/architecture.md](docs/specifications/ARCHITECTURE.md) for detailed architecture documentation.
|
|
66
|
+
|
|
67
|
+
## Project Structure
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
trellis/
|
|
71
|
+
├── trellis/ # Core library (shared)
|
|
72
|
+
│ ├── models/ # Pydantic DSL models
|
|
73
|
+
│ ├── validation/ # DAG and contract validation
|
|
74
|
+
│ ├── execution/ # Execution engine
|
|
75
|
+
│ └── tools/ # Tool protocol and implementations
|
|
76
|
+
├── trelis_api/ # FastAPI server
|
|
77
|
+
├── trelis_mcp/ # MCP server
|
|
78
|
+
├── trelis_cli/ # CLI interface
|
|
79
|
+
├── data/ # Dataset generation
|
|
80
|
+
├── tests/ # Test suite
|
|
81
|
+
├── docs/ # Documentation
|
|
82
|
+
└── scripts/ # Utility scripts
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Development
|
|
86
|
+
|
|
87
|
+
### Testing
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pytest tests/ -v
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Linting
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
black .
|
|
97
|
+
isort .
|
|
98
|
+
mypy trellis/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Building
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python -m build
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
See LICENSE file for details.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# NOTE: "trellis" is already registered on PyPI (Phillip J. Eby, v0.7a2).
|
|
7
|
+
# Replace the name below with your chosen PyPI name before publishing.
|
|
8
|
+
# The import name ("trellis", "trellis_api", etc.) is unaffected by this field.
|
|
9
|
+
name = "trellis-pipelines"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
description = "Modular agentic pipeline system for document and data workflows"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = {file = "LICENSE"}
|
|
14
|
+
authors = [
|
|
15
|
+
{name = "Ciaran Davies"},
|
|
16
|
+
]
|
|
17
|
+
requires-python = ">=3.12"
|
|
18
|
+
keywords = [
|
|
19
|
+
"pipeline", "agentic", "dag", "document", "extraction",
|
|
20
|
+
"llm", "pdf", "sec", "etl", "workflow",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 3 - Alpha",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
32
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
33
|
+
"Topic :: Office/Business",
|
|
34
|
+
"Typing :: Typed",
|
|
35
|
+
]
|
|
36
|
+
# ── Core dependencies ────────────────────────────────────────────────────────
|
|
37
|
+
# Installed for every user. FastAPI/uvicorn are optional (see [api] extra).
|
|
38
|
+
dependencies = [
|
|
39
|
+
"pydantic>=2.0",
|
|
40
|
+
"pyyaml>=6.0",
|
|
41
|
+
"litellm>=1.0.0",
|
|
42
|
+
"PyMuPDF>=1.24.0",
|
|
43
|
+
"pypdf>=3.0.0",
|
|
44
|
+
"python-dotenv>=1.0.0",
|
|
45
|
+
"beautifulsoup4>=4.12.0",
|
|
46
|
+
"typer>=0.9",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
Homepage = "https://github.com/your-org/trellis"
|
|
51
|
+
Repository = "https://github.com/your-org/trellis"
|
|
52
|
+
Documentation = "https://your-org.github.io/trellis"
|
|
53
|
+
"Bug Tracker" = "https://github.com/your-org/trellis/issues"
|
|
54
|
+
|
|
55
|
+
# ── Optional extras ──────────────────────────────────────────────────────────
|
|
56
|
+
[project.optional-dependencies]
|
|
57
|
+
api = [
|
|
58
|
+
"fastapi>=0.104",
|
|
59
|
+
"uvicorn[standard]>=0.24",
|
|
60
|
+
]
|
|
61
|
+
dev = [
|
|
62
|
+
"pytest>=7.0",
|
|
63
|
+
"pytest-cov>=4.0",
|
|
64
|
+
"pytest-asyncio>=0.21.0",
|
|
65
|
+
"httpx>=0.24",
|
|
66
|
+
"black>=23.0",
|
|
67
|
+
"isort>=5.12",
|
|
68
|
+
"mypy>=1.0",
|
|
69
|
+
"ruff>=0.1",
|
|
70
|
+
]
|
|
71
|
+
all = [
|
|
72
|
+
"trellis-pipelines[api]",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[project.scripts]
|
|
76
|
+
trellis = "trellis_cli.main:main"
|
|
77
|
+
|
|
78
|
+
# ── Package discovery ────────────────────────────────────────────────────────
|
|
79
|
+
# find: auto-discovers all packages (any directory with __init__.py).
|
|
80
|
+
# tests and build artefacts are excluded from the distribution.
|
|
81
|
+
[tool.setuptools.packages.find]
|
|
82
|
+
where = ["."]
|
|
83
|
+
include = ["trellis*", "trellis_api*", "trellis_cli*", "trellis_mcp*"]
|
|
84
|
+
|
|
85
|
+
# ── Tool configuration ───────────────────────────────────────────────────────
|
|
86
|
+
[tool.black]
|
|
87
|
+
line-length = 100
|
|
88
|
+
|
|
89
|
+
[tool.isort]
|
|
90
|
+
profile = "black"
|
|
91
|
+
line_length = 100
|
|
92
|
+
|
|
93
|
+
[tool.ruff]
|
|
94
|
+
line-length = 100
|
|
95
|
+
|
|
96
|
+
[tool.mypy]
|
|
97
|
+
python_version = "3.12"
|
|
98
|
+
warn_return_any = true
|
|
99
|
+
warn_unused_configs = true
|
|
100
|
+
ignore_missing_imports = true
|
|
101
|
+
|
|
102
|
+
[tool.pytest.ini_options]
|
|
103
|
+
testpaths = ["tests"]
|
|
104
|
+
asyncio_mode = "auto"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trellis.exceptions — Shared exception hierarchy for the Trellis runtime.
|
|
3
|
+
|
|
4
|
+
All public-facing errors inherit from TrellisError so callers can catch
|
|
5
|
+
broadly or narrowly as needed.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TrellisError(Exception):
|
|
12
|
+
"""Base class for all Trellis errors."""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
# Validation errors
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ValidationError(TrellisError):
|
|
21
|
+
"""Base class for all validation failures."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CycleError(ValidationError):
|
|
25
|
+
"""
|
|
26
|
+
Raised when a cycle is detected in a task DAG or a plan sub-pipeline DAG.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
cycle: The sequence of node IDs forming the cycle, if recoverable.
|
|
30
|
+
May be None if only the presence of a cycle is known.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, message: str, cycle: list[str] | None = None) -> None:
|
|
34
|
+
super().__init__(message)
|
|
35
|
+
self.cycle = cycle
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UnresolvedRefError(ValidationError):
|
|
39
|
+
"""
|
|
40
|
+
Raised when a template expression references a task or key that does
|
|
41
|
+
not exist in the current scope.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ContractError(ValidationError):
|
|
46
|
+
"""
|
|
47
|
+
Raised when a pipeline's store tasks do not match the sub-pipeline's
|
|
48
|
+
stores declaration in the plan, or when a session reference is made
|
|
49
|
+
to a key not listed in reads.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class UnknownToolError(ValidationError):
|
|
54
|
+
"""Raised when a task references a tool not present in the registry."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class PipelineParamError(ValidationError):
|
|
58
|
+
"""
|
|
59
|
+
Raised when pipeline parameter validation fails at invocation time —
|
|
60
|
+
e.g. a required param is missing or a value cannot be coerced to the
|
|
61
|
+
declared type.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Execution errors
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ExecutionError(TrellisError):
|
|
71
|
+
"""Base class for runtime execution failures."""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ResolutionError(ExecutionError):
|
|
75
|
+
"""
|
|
76
|
+
Raised when a template expression cannot be resolved against the current
|
|
77
|
+
execution context — e.g. a task output that does not exist yet, a
|
|
78
|
+
field path that does not match the output structure, or an unknown
|
|
79
|
+
namespace.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TaskFailedError(ExecutionError):
|
|
84
|
+
"""
|
|
85
|
+
Raised when a task fails after exhausting all retry attempts.
|
|
86
|
+
|
|
87
|
+
Attributes:
|
|
88
|
+
task_id: The id of the failing task.
|
|
89
|
+
cause: The underlying exception that caused the failure.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(self, task_id: str, cause: Exception) -> None:
|
|
93
|
+
super().__init__(f"Task {task_id!r} failed: {cause}")
|
|
94
|
+
self.task_id = task_id
|
|
95
|
+
self.cause = cause
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class BlackboardKeyError(ExecutionError):
|
|
99
|
+
"""
|
|
100
|
+
Raised when a session blackboard read is attempted for a key that does
|
|
101
|
+
not exist and no default is provided.
|
|
102
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple tenant-scoped blackboard for session persistence.
|
|
3
|
+
|
|
4
|
+
This module provides a minimal in-memory implementation suitable for local
|
|
5
|
+
runs and testing. The interface is intentionally tiny so it can be swapped for
|
|
6
|
+
Redis/Postgres/Prefect Blocks later without touching the executor.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Dict, Iterable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Blackboard:
|
|
15
|
+
"""Abstract tenant-scoped key/value store."""
|
|
16
|
+
|
|
17
|
+
def get_all(self, tenant_id: str) -> Dict[str, Any]: # pragma: no cover - interface
|
|
18
|
+
raise NotImplementedError
|
|
19
|
+
|
|
20
|
+
def read_many(self, tenant_id: str, keys: Iterable[str]) -> Dict[str, Any]: # pragma: no cover - interface
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
|
|
23
|
+
def write(self, tenant_id: str, key: str, value: Any, *, append: bool = False) -> None: # pragma: no cover - interface
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class InMemoryBlackboard(Blackboard):
|
|
29
|
+
"""Naive in-memory implementation.
|
|
30
|
+
|
|
31
|
+
Data layout: { tenant_id -> { key -> value } }
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
_data: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
|
35
|
+
|
|
36
|
+
def _tenant(self, tenant_id: str) -> Dict[str, Any]:
|
|
37
|
+
return self._data.setdefault(tenant_id, {})
|
|
38
|
+
|
|
39
|
+
def get_all(self, tenant_id: str) -> Dict[str, Any]:
|
|
40
|
+
return dict(self._tenant(tenant_id))
|
|
41
|
+
|
|
42
|
+
def read_many(self, tenant_id: str, keys: Iterable[str]) -> Dict[str, Any]:
|
|
43
|
+
t = self._tenant(tenant_id)
|
|
44
|
+
return {k: t[k] for k in keys if k in t}
|
|
45
|
+
|
|
46
|
+
def write(self, tenant_id: str, key: str, value: Any, *, append: bool = False) -> None:
|
|
47
|
+
t = self._tenant(tenant_id)
|
|
48
|
+
if append:
|
|
49
|
+
if key not in t:
|
|
50
|
+
t[key] = [value]
|
|
51
|
+
else:
|
|
52
|
+
existing = t[key]
|
|
53
|
+
if isinstance(existing, list):
|
|
54
|
+
existing.append(value)
|
|
55
|
+
else:
|
|
56
|
+
t[key] = [existing, value]
|
|
57
|
+
else:
|
|
58
|
+
t[key] = value
|
|
59
|
+
|