stabilize 0.9.2__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.
- stabilize/__init__.py +29 -0
- stabilize/cli.py +1193 -0
- stabilize/context/__init__.py +7 -0
- stabilize/context/stage_context.py +170 -0
- stabilize/dag/__init__.py +15 -0
- stabilize/dag/graph.py +215 -0
- stabilize/dag/topological.py +199 -0
- stabilize/examples/__init__.py +1 -0
- stabilize/examples/docker-example.py +759 -0
- stabilize/examples/golden-standard-expected-result.txt +1 -0
- stabilize/examples/golden-standard.py +488 -0
- stabilize/examples/http-example.py +606 -0
- stabilize/examples/llama-example.py +662 -0
- stabilize/examples/python-example.py +731 -0
- stabilize/examples/shell-example.py +399 -0
- stabilize/examples/ssh-example.py +603 -0
- stabilize/handlers/__init__.py +53 -0
- stabilize/handlers/base.py +226 -0
- stabilize/handlers/complete_stage.py +209 -0
- stabilize/handlers/complete_task.py +75 -0
- stabilize/handlers/complete_workflow.py +150 -0
- stabilize/handlers/run_task.py +369 -0
- stabilize/handlers/start_stage.py +262 -0
- stabilize/handlers/start_task.py +74 -0
- stabilize/handlers/start_workflow.py +136 -0
- stabilize/launcher.py +307 -0
- stabilize/migrations/01KDQ4N9QPJ6Q4MCV3V9GHWPV4_initial_schema.sql +97 -0
- stabilize/migrations/01KDRK3TXW4R2GERC1WBCQYJGG_rag_embeddings.sql +25 -0
- stabilize/migrations/__init__.py +1 -0
- stabilize/models/__init__.py +15 -0
- stabilize/models/stage.py +389 -0
- stabilize/models/status.py +146 -0
- stabilize/models/task.py +125 -0
- stabilize/models/workflow.py +317 -0
- stabilize/orchestrator.py +113 -0
- stabilize/persistence/__init__.py +28 -0
- stabilize/persistence/connection.py +185 -0
- stabilize/persistence/factory.py +136 -0
- stabilize/persistence/memory.py +214 -0
- stabilize/persistence/postgres.py +655 -0
- stabilize/persistence/sqlite.py +674 -0
- stabilize/persistence/store.py +235 -0
- stabilize/queue/__init__.py +59 -0
- stabilize/queue/messages.py +377 -0
- stabilize/queue/processor.py +312 -0
- stabilize/queue/queue.py +526 -0
- stabilize/queue/sqlite_queue.py +354 -0
- stabilize/rag/__init__.py +19 -0
- stabilize/rag/assistant.py +459 -0
- stabilize/rag/cache.py +294 -0
- stabilize/stages/__init__.py +11 -0
- stabilize/stages/builder.py +253 -0
- stabilize/tasks/__init__.py +19 -0
- stabilize/tasks/interface.py +335 -0
- stabilize/tasks/registry.py +255 -0
- stabilize/tasks/result.py +283 -0
- stabilize-0.9.2.dist-info/METADATA +301 -0
- stabilize-0.9.2.dist-info/RECORD +61 -0
- stabilize-0.9.2.dist-info/WHEEL +4 -0
- stabilize-0.9.2.dist-info/entry_points.txt +2 -0
- stabilize-0.9.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TaskResult - result of task execution.
|
|
3
|
+
|
|
4
|
+
This module defines the TaskResult class that encapsulates the result
|
|
5
|
+
of executing a task, including status, context updates, and outputs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from stabilize.models.status import WorkflowStatus
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class TaskResult:
|
|
18
|
+
"""
|
|
19
|
+
Result of a task execution.
|
|
20
|
+
|
|
21
|
+
Tasks return a TaskResult to indicate their status and provide
|
|
22
|
+
data to downstream stages.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
status: The execution status after the task runs
|
|
26
|
+
context: Data scoped to the current stage (merged into stage.context)
|
|
27
|
+
outputs: Data available to downstream stages (merged into stage.outputs)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
status: WorkflowStatus
|
|
31
|
+
context: dict[str, Any] = field(default_factory=dict)
|
|
32
|
+
outputs: dict[str, Any] = field(default_factory=dict)
|
|
33
|
+
|
|
34
|
+
# ========== Factory Methods ==========
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def success(
|
|
38
|
+
cls,
|
|
39
|
+
outputs: dict[str, Any] | None = None,
|
|
40
|
+
context: dict[str, Any] | None = None,
|
|
41
|
+
) -> TaskResult:
|
|
42
|
+
"""
|
|
43
|
+
Create a successful result.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
outputs: Values available to downstream stages
|
|
47
|
+
context: Values scoped to current stage
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
A TaskResult with SUCCEEDED status
|
|
51
|
+
"""
|
|
52
|
+
return cls(
|
|
53
|
+
status=WorkflowStatus.SUCCEEDED,
|
|
54
|
+
context=context or {},
|
|
55
|
+
outputs=outputs or {},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def running(
|
|
60
|
+
cls,
|
|
61
|
+
context: dict[str, Any] | None = None,
|
|
62
|
+
) -> TaskResult:
|
|
63
|
+
"""
|
|
64
|
+
Create a running result (task will be re-executed).
|
|
65
|
+
|
|
66
|
+
Use this when a task needs to poll/wait for something.
|
|
67
|
+
The task will be re-queued and executed again after a backoff period.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
context: Updated context values
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
A TaskResult with RUNNING status
|
|
74
|
+
"""
|
|
75
|
+
return cls(
|
|
76
|
+
status=WorkflowStatus.RUNNING,
|
|
77
|
+
context=context or {},
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def terminal(
|
|
82
|
+
cls,
|
|
83
|
+
error: str,
|
|
84
|
+
context: dict[str, Any] | None = None,
|
|
85
|
+
) -> TaskResult:
|
|
86
|
+
"""
|
|
87
|
+
Create a terminal failure result.
|
|
88
|
+
|
|
89
|
+
The stage and pipeline will fail.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
error: Error message
|
|
93
|
+
context: Additional context
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
A TaskResult with TERMINAL status
|
|
97
|
+
"""
|
|
98
|
+
ctx = context or {}
|
|
99
|
+
ctx["error"] = error
|
|
100
|
+
return cls(
|
|
101
|
+
status=WorkflowStatus.TERMINAL,
|
|
102
|
+
context=ctx,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def failed_continue(
|
|
107
|
+
cls,
|
|
108
|
+
error: str,
|
|
109
|
+
outputs: dict[str, Any] | None = None,
|
|
110
|
+
context: dict[str, Any] | None = None,
|
|
111
|
+
) -> TaskResult:
|
|
112
|
+
"""
|
|
113
|
+
Create a failed result that allows pipeline to continue.
|
|
114
|
+
|
|
115
|
+
The stage will be marked as failed but downstream stages will run.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
error: Error message
|
|
119
|
+
outputs: Values available to downstream stages
|
|
120
|
+
context: Additional context
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
A TaskResult with FAILED_CONTINUE status
|
|
124
|
+
"""
|
|
125
|
+
ctx = context or {}
|
|
126
|
+
ctx["error"] = error
|
|
127
|
+
return cls(
|
|
128
|
+
status=WorkflowStatus.FAILED_CONTINUE,
|
|
129
|
+
context=ctx,
|
|
130
|
+
outputs=outputs or {},
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def skipped(cls) -> TaskResult:
|
|
135
|
+
"""
|
|
136
|
+
Create a skipped result.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
A TaskResult with SKIPPED status
|
|
140
|
+
"""
|
|
141
|
+
return cls(status=WorkflowStatus.SKIPPED)
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def canceled(
|
|
145
|
+
cls,
|
|
146
|
+
outputs: dict[str, Any] | None = None,
|
|
147
|
+
) -> TaskResult:
|
|
148
|
+
"""
|
|
149
|
+
Create a canceled result.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
outputs: Final outputs to preserve
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
A TaskResult with CANCELED status
|
|
156
|
+
"""
|
|
157
|
+
return cls(
|
|
158
|
+
status=WorkflowStatus.CANCELED,
|
|
159
|
+
outputs=outputs or {},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def stopped(
|
|
164
|
+
cls,
|
|
165
|
+
outputs: dict[str, Any] | None = None,
|
|
166
|
+
) -> TaskResult:
|
|
167
|
+
"""
|
|
168
|
+
Create a stopped result.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
outputs: Final outputs to preserve
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
A TaskResult with STOPPED status
|
|
175
|
+
"""
|
|
176
|
+
return cls(
|
|
177
|
+
status=WorkflowStatus.STOPPED,
|
|
178
|
+
outputs=outputs or {},
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def redirect(
|
|
183
|
+
cls,
|
|
184
|
+
context: dict[str, Any] | None = None,
|
|
185
|
+
) -> TaskResult:
|
|
186
|
+
"""
|
|
187
|
+
Create a redirect result.
|
|
188
|
+
|
|
189
|
+
Indicates a decision branch should be followed.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
context: Context for the redirect
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
A TaskResult with REDIRECT status
|
|
196
|
+
"""
|
|
197
|
+
return cls(
|
|
198
|
+
status=WorkflowStatus.REDIRECT,
|
|
199
|
+
context=context or {},
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# ========== Builder Pattern ==========
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def builder(cls, status: WorkflowStatus) -> TaskResultBuilder:
|
|
206
|
+
"""
|
|
207
|
+
Create a builder for more complex results.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
status: The execution status
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
A TaskResultBuilder
|
|
214
|
+
"""
|
|
215
|
+
return TaskResultBuilder(status)
|
|
216
|
+
|
|
217
|
+
# ========== Utility Methods ==========
|
|
218
|
+
|
|
219
|
+
def merge_outputs(self, other: TaskResult | None) -> TaskResult:
|
|
220
|
+
"""
|
|
221
|
+
Merge outputs from another result.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
other: Result to merge outputs from
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
A new TaskResult with merged outputs
|
|
228
|
+
"""
|
|
229
|
+
if other is None:
|
|
230
|
+
return self
|
|
231
|
+
|
|
232
|
+
merged_context = dict(self.context)
|
|
233
|
+
merged_context.update(other.context)
|
|
234
|
+
|
|
235
|
+
merged_outputs = dict(self.outputs)
|
|
236
|
+
merged_outputs.update(other.outputs)
|
|
237
|
+
|
|
238
|
+
return TaskResult(
|
|
239
|
+
status=self.status,
|
|
240
|
+
context=merged_context,
|
|
241
|
+
outputs=merged_outputs,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class TaskResultBuilder:
|
|
246
|
+
"""
|
|
247
|
+
Builder for TaskResult objects.
|
|
248
|
+
|
|
249
|
+
Provides a fluent API for constructing complex task results.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
def __init__(self, status: WorkflowStatus) -> None:
|
|
253
|
+
self._status = status
|
|
254
|
+
self._context: dict[str, Any] = {}
|
|
255
|
+
self._outputs: dict[str, Any] = {}
|
|
256
|
+
|
|
257
|
+
def context(self, context: dict[str, Any]) -> TaskResultBuilder:
|
|
258
|
+
"""Set the context."""
|
|
259
|
+
self._context = context
|
|
260
|
+
return self
|
|
261
|
+
|
|
262
|
+
def outputs(self, outputs: dict[str, Any]) -> TaskResultBuilder:
|
|
263
|
+
"""Set the outputs."""
|
|
264
|
+
self._outputs = outputs
|
|
265
|
+
return self
|
|
266
|
+
|
|
267
|
+
def add_context(self, key: str, value: Any) -> TaskResultBuilder:
|
|
268
|
+
"""Add a context value."""
|
|
269
|
+
self._context[key] = value
|
|
270
|
+
return self
|
|
271
|
+
|
|
272
|
+
def add_output(self, key: str, value: Any) -> TaskResultBuilder:
|
|
273
|
+
"""Add an output value."""
|
|
274
|
+
self._outputs[key] = value
|
|
275
|
+
return self
|
|
276
|
+
|
|
277
|
+
def build(self) -> TaskResult:
|
|
278
|
+
"""Build the TaskResult."""
|
|
279
|
+
return TaskResult(
|
|
280
|
+
status=self._status,
|
|
281
|
+
context=self._context,
|
|
282
|
+
outputs=self._outputs,
|
|
283
|
+
)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stabilize
|
|
3
|
+
Version: 0.9.2
|
|
4
|
+
Summary: Highway Workflow Engine - Stabilize execution layer
|
|
5
|
+
Project-URL: Homepage, https://github.com/rodmena-limited/stabilize
|
|
6
|
+
Project-URL: Repository, https://github.com/rodmena-limited/stabilize
|
|
7
|
+
Project-URL: Issues, https://github.com/rodmena-limited/stabilize/issues
|
|
8
|
+
Author-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dag,orchestration,pipeline,task-runner,workflow
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Requires-Dist: ulid-py>=1.1
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: psycopg[binary,pool]>=3.0; extra == 'all'
|
|
25
|
+
Requires-Dist: ragit>=0.7.5; extra == 'all'
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
28
|
+
Requires-Dist: psycopg[binary,pool]>=3.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
32
|
+
Requires-Dist: testcontainers>=4.0; extra == 'dev'
|
|
33
|
+
Provides-Extra: postgres
|
|
34
|
+
Requires-Dist: psycopg[binary,pool]>=3.0; extra == 'postgres'
|
|
35
|
+
Provides-Extra: rag
|
|
36
|
+
Requires-Dist: ragit>=0.7.5; extra == 'rag'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# Stabilize
|
|
40
|
+
|
|
41
|
+
Highway Workflow Engine - Stabilize execution layer.
|
|
42
|
+
|
|
43
|
+
A lightweight Python workflow execution engine with DAG-based stage orchestration.
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Python 3.11+
|
|
48
|
+
- SQLite (included) or PostgreSQL 12+
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install stabilize # SQLite support only
|
|
54
|
+
pip install stabilize[postgres] # PostgreSQL support
|
|
55
|
+
pip install stabilize[rag] # RAG-powered pipeline generation
|
|
56
|
+
pip install stabilize[all] # All features
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- Message-driven DAG execution engine
|
|
62
|
+
- Parallel and sequential stage execution
|
|
63
|
+
- Synthetic stages (before/after/onFailure)
|
|
64
|
+
- PostgreSQL and SQLite persistence
|
|
65
|
+
- Pluggable task system
|
|
66
|
+
- Retry and timeout support
|
|
67
|
+
- RAG-powered pipeline generation from natural language
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from stabilize import Workflow, StageExecution, TaskExecution, WorkflowStatus
|
|
73
|
+
from stabilize.persistence.sqlite import SqliteWorkflowStore
|
|
74
|
+
from stabilize.queue.sqlite_queue import SqliteQueue
|
|
75
|
+
from stabilize.queue.processor import QueueProcessor
|
|
76
|
+
from stabilize.orchestrator import Orchestrator
|
|
77
|
+
from stabilize.tasks.interface import Task
|
|
78
|
+
from stabilize.tasks.result import TaskResult
|
|
79
|
+
from stabilize.tasks.registry import TaskRegistry
|
|
80
|
+
|
|
81
|
+
# Define a custom task
|
|
82
|
+
class HelloTask(Task):
|
|
83
|
+
def execute(self, stage: StageExecution) -> TaskResult:
|
|
84
|
+
name = stage.context.get("name", "World")
|
|
85
|
+
return TaskResult.success(outputs={"greeting": f"Hello, {name}!"})
|
|
86
|
+
|
|
87
|
+
# Create a workflow
|
|
88
|
+
workflow = Workflow.create(
|
|
89
|
+
application="my-app",
|
|
90
|
+
name="Hello Workflow",
|
|
91
|
+
stages=[
|
|
92
|
+
StageExecution(
|
|
93
|
+
ref_id="1",
|
|
94
|
+
type="hello",
|
|
95
|
+
name="Say Hello",
|
|
96
|
+
tasks=[
|
|
97
|
+
TaskExecution.create(
|
|
98
|
+
name="Hello Task",
|
|
99
|
+
implementing_class="hello",
|
|
100
|
+
stage_start=True,
|
|
101
|
+
stage_end=True,
|
|
102
|
+
),
|
|
103
|
+
],
|
|
104
|
+
context={"name": "Stabilize"},
|
|
105
|
+
),
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Setup persistence and queue
|
|
110
|
+
store = SqliteWorkflowStore(":memory:")
|
|
111
|
+
queue = SqliteQueue(":memory:")
|
|
112
|
+
|
|
113
|
+
# Register tasks
|
|
114
|
+
registry = TaskRegistry()
|
|
115
|
+
registry.register("hello", HelloTask)
|
|
116
|
+
|
|
117
|
+
# Create processor and orchestrator
|
|
118
|
+
processor = QueueProcessor.create(queue, store, registry)
|
|
119
|
+
orchestrator = Orchestrator(queue)
|
|
120
|
+
|
|
121
|
+
# Run workflow
|
|
122
|
+
store.store(workflow)
|
|
123
|
+
orchestrator.start(workflow)
|
|
124
|
+
processor.process_all(timeout=10.0)
|
|
125
|
+
|
|
126
|
+
# Check result
|
|
127
|
+
result = store.retrieve(workflow.id)
|
|
128
|
+
print(f"Status: {result.status}") # WorkflowStatus.SUCCEEDED
|
|
129
|
+
print(f"Output: {result.stages[0].outputs}") # {'greeting': 'Hello, Stabilize!'}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Parallel Stages
|
|
133
|
+
|
|
134
|
+
Stages with shared dependencies run in parallel:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# Setup
|
|
138
|
+
# / \
|
|
139
|
+
# Test Lint
|
|
140
|
+
# \ /
|
|
141
|
+
# Deploy
|
|
142
|
+
|
|
143
|
+
workflow = Workflow.create(
|
|
144
|
+
application="my-app",
|
|
145
|
+
name="CI/CD Pipeline",
|
|
146
|
+
stages=[
|
|
147
|
+
StageExecution(ref_id="setup", type="setup", name="Setup", ...),
|
|
148
|
+
StageExecution(ref_id="test", type="test", name="Test",
|
|
149
|
+
requisite_stage_ref_ids={"setup"}, ...),
|
|
150
|
+
StageExecution(ref_id="lint", type="lint", name="Lint",
|
|
151
|
+
requisite_stage_ref_ids={"setup"}, ...),
|
|
152
|
+
StageExecution(ref_id="deploy", type="deploy", name="Deploy",
|
|
153
|
+
requisite_stage_ref_ids={"test", "lint"}, ...),
|
|
154
|
+
],
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Database Setup
|
|
159
|
+
|
|
160
|
+
### SQLite
|
|
161
|
+
|
|
162
|
+
No setup required. Schema is created automatically.
|
|
163
|
+
|
|
164
|
+
### PostgreSQL
|
|
165
|
+
|
|
166
|
+
Apply migrations using the CLI:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Using mg.yaml in current directory
|
|
170
|
+
stabilize mg-up
|
|
171
|
+
|
|
172
|
+
# Using database URL
|
|
173
|
+
stabilize mg-up --db-url postgres://user:pass@host:5432/dbname
|
|
174
|
+
|
|
175
|
+
# Using environment variable
|
|
176
|
+
MG_DATABASE_URL=postgres://user:pass@host:5432/dbname stabilize mg-up
|
|
177
|
+
|
|
178
|
+
# Check migration status
|
|
179
|
+
stabilize mg-status
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Example mg.yaml:
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
database:
|
|
186
|
+
host: localhost
|
|
187
|
+
port: 5432
|
|
188
|
+
user: postgres
|
|
189
|
+
password: postgres
|
|
190
|
+
dbname: stabilize
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## RAG-Powered Pipeline Generation
|
|
194
|
+
|
|
195
|
+
Stabilize includes an AI-powered assistant that generates pipeline code from natural language descriptions using RAG (Retrieval-Augmented Generation).
|
|
196
|
+
|
|
197
|
+
### Requirements
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pip install stabilize[rag] # Installs ragit dependency
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
You also need:
|
|
204
|
+
- **Local Ollama** (required for embeddings - ollama.com doesn't support embeddings API):
|
|
205
|
+
```bash
|
|
206
|
+
# Install from https://ollama.com/download, then:
|
|
207
|
+
ollama serve # Start the server
|
|
208
|
+
ollama pull nomic-embed-text # Download embedding model
|
|
209
|
+
```
|
|
210
|
+
- **Ollama API key** for LLM generation (uses ollama.com cloud)
|
|
211
|
+
|
|
212
|
+
### Setup
|
|
213
|
+
|
|
214
|
+
Create a `.env` file with your API key:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
OLLAMA_API_KEY=your_api_key_here
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Initialize the embedding cache:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Initialize with default context (Stabilize docs + examples)
|
|
224
|
+
stabilize rag init
|
|
225
|
+
|
|
226
|
+
# Include your own code as additional training context
|
|
227
|
+
stabilize rag init --additional-context /path/to/your/code/
|
|
228
|
+
|
|
229
|
+
# Force regenerate embeddings
|
|
230
|
+
stabilize rag init --force
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Generate Pipelines
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Generate a pipeline from natural language
|
|
237
|
+
stabilize rag generate "create a pipeline that processes CSV files in parallel"
|
|
238
|
+
|
|
239
|
+
# Save to file
|
|
240
|
+
stabilize rag generate "build a CI/CD pipeline with test and deploy stages" > my_pipeline.py
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Clear Cache
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
stabilize rag clear
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Configuration
|
|
250
|
+
|
|
251
|
+
Environment variables:
|
|
252
|
+
|
|
253
|
+
| Variable | Default | Description |
|
|
254
|
+
|----------|---------|-------------|
|
|
255
|
+
| `OLLAMA_API_KEY` | (required) | API key for ollama.com |
|
|
256
|
+
| `OLLAMA_BASE_URL` | `https://ollama.com` | LLM endpoint URL |
|
|
257
|
+
| `OLLAMA_EMBEDDING_URL` | `http://localhost:11434` | Local Ollama for embeddings |
|
|
258
|
+
|
|
259
|
+
### Example
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
$ stabilize rag generate "create a hello world pipeline"
|
|
263
|
+
|
|
264
|
+
from stabilize import Workflow, StageExecution, TaskExecution
|
|
265
|
+
from stabilize.tasks.interface import Task
|
|
266
|
+
from stabilize.tasks.result import TaskResult
|
|
267
|
+
...
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## CLI Reference
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
stabilize mg-up [--db-url URL] Apply pending PostgreSQL migrations
|
|
274
|
+
stabilize mg-status [--db-url URL] Show migration status
|
|
275
|
+
stabilize rag init [--force] [--additional-context PATH] Initialize RAG embeddings
|
|
276
|
+
stabilize rag generate "prompt" Generate pipeline from natural language
|
|
277
|
+
stabilize rag clear Clear embedding cache
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Naming Alignment with highway_dsl
|
|
281
|
+
|
|
282
|
+
| highway_dsl | stabilize |
|
|
283
|
+
|-------------|-----------|
|
|
284
|
+
| Workflow | Workflow |
|
|
285
|
+
| TaskOperator | Task interface |
|
|
286
|
+
| RetryPolicy | RetryableTask |
|
|
287
|
+
| TimeoutPolicy | OverridableTimeoutRetryableTask |
|
|
288
|
+
|
|
289
|
+
## Running Tests
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# All tests (requires Docker for PostgreSQL)
|
|
293
|
+
pytest tests/ -v
|
|
294
|
+
|
|
295
|
+
# SQLite tests only (no Docker)
|
|
296
|
+
pytest tests/ -v -k sqlite
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
Apache 2.0
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
stabilize/__init__.py,sha256=uCpkXVvxBFFoVkifBcU8dIkzEPgtO2TpclYg-AgOLAs,784
|
|
2
|
+
stabilize/cli.py,sha256=to-MY7GUZBAh_TcHhhPGh2LhuLOqR3ccJA78DTBksxM,41708
|
|
3
|
+
stabilize/launcher.py,sha256=5POhM4ia1HMNoTFxfcQPB2QKbWVxlsOLadBTBteK5d4,8337
|
|
4
|
+
stabilize/orchestrator.py,sha256=shpOToe4fXwjkSBjDu-k5hHlYIKNYRlwmCHsyn9gBdM,2716
|
|
5
|
+
stabilize/context/__init__.py,sha256=nVL-uhufF8EPPGybnJ-Rxi0Nbm0leJjlQcWvb-IfGBo,140
|
|
6
|
+
stabilize/context/stage_context.py,sha256=YsBFrzBLQwr5ymz8wszvestTi0nxPU0lVbd6ywlZolA,4900
|
|
7
|
+
stabilize/dag/__init__.py,sha256=ooRWzJo4oz9P25MrQ-a-EoGKhTAxDy-tStCPYdB-WQA,352
|
|
8
|
+
stabilize/dag/graph.py,sha256=n-ZQTxvOi_-XkoVoKJC6KhUFx78yYpmi4wjiG7Q4ENE,6373
|
|
9
|
+
stabilize/dag/topological.py,sha256=VVhgW5JLaMM52dIpAzv7DRcLuqCCvuo97G-USRSSTX4,6069
|
|
10
|
+
stabilize/handlers/__init__.py,sha256=N4D2u1FLgbEcF6A8PR1Klbv8mcE4O38Mx91im18VQbw,1651
|
|
11
|
+
stabilize/handlers/base.py,sha256=KWXeK053y8g8_ktGk3DTsTRHPFKGN8mjvs1r1ElFs8Q,6726
|
|
12
|
+
stabilize/handlers/complete_stage.py,sha256=UbNCIVjWfx7G4sFWgZ_WobpOV-Trq32ATLwoxuY-A40,7970
|
|
13
|
+
stabilize/handlers/complete_task.py,sha256=Ps-M_8FmHrTSQexDjec0JmdP-sQq_6Gl3MCxUXUzOls,2193
|
|
14
|
+
stabilize/handlers/complete_workflow.py,sha256=y_n21xEYOt20tDxKkICboOX5DXiZ_HoSyCtw2soPSjA,5293
|
|
15
|
+
stabilize/handlers/run_task.py,sha256=xqBpQi_yhcB8DJBMApatkrPE5PuCkMnIFVKbVHQ1cm0,12166
|
|
16
|
+
stabilize/handlers/start_stage.py,sha256=Kjfs0Anjh3nUdCU_aHwVEZChztcooR1Mlztufsa9ffM,8638
|
|
17
|
+
stabilize/handlers/start_task.py,sha256=gOZaO4dg9QAfiT66nhBX-DkeK7J_JcHkVFRwNIdxfK0,2025
|
|
18
|
+
stabilize/handlers/start_workflow.py,sha256=Yd-kn1K41VVHbCh0YJQRAiDMdBnGRdrQE-VUVYqI5G8,4506
|
|
19
|
+
stabilize/migrations/__init__.py,sha256=oHEHbvHO3OeV4l3ggstDBz5olXHFiozcIKOZtjAf6vo,52
|
|
20
|
+
stabilize/models/__init__.py,sha256=MB-4rQd7VCdoXPyb1uYsKe1eMgp3M_ibdlfGfyNmIdo,422
|
|
21
|
+
stabilize/models/stage.py,sha256=9gxfZL4yCeH5zBaxCRpYflS7noCxdZZ_7nrn_zPJ2VQ,13579
|
|
22
|
+
stabilize/models/status.py,sha256=DAdvzuQi_AjD37Y2SOFC5H_V5jUDKjxRj-OE3OwmOgA,4150
|
|
23
|
+
stabilize/models/task.py,sha256=hOSm4l7EadfuZzINXc9GAitkyzJku1KkK_noEztble0,3812
|
|
24
|
+
stabilize/models/workflow.py,sha256=qL4t-8D7kkmOyJaCPnOQDSFkv7LkgFOkLFsgIhl_MnE,9883
|
|
25
|
+
stabilize/persistence/__init__.py,sha256=fArCMlwW9f00C0iU1Ew7Fwu1K3M9auOGm5kmPzKHH8Q,723
|
|
26
|
+
stabilize/persistence/connection.py,sha256=j5qqHN2u0_egswU6FMXAM9HxSuvaOOCBvXQKiYPIklI,6484
|
|
27
|
+
stabilize/persistence/factory.py,sha256=MVJVZuiawygKOZnNrVJcmQKlcjTWJK2V4YXmF2nhIUY,3816
|
|
28
|
+
stabilize/persistence/memory.py,sha256=F_aOr5rYY0suYmfDsp__lbeW4rWkpE2erm6GyCZ1YME,7351
|
|
29
|
+
stabilize/persistence/postgres.py,sha256=NzuywAb9Cw5KK1hy2Hik-83Ygmqed30XysQSBki_JdA,25775
|
|
30
|
+
stabilize/persistence/sqlite.py,sha256=vrkXHQmS_XTFU08-djgA1XbkjZkn1pPCWbkGpF8lhfQ,24289
|
|
31
|
+
stabilize/persistence/store.py,sha256=JhpvfYSOgR_SkAZps5yp22So2Gd4n1NUtTpWExiRfCE,5267
|
|
32
|
+
stabilize/queue/__init__.py,sha256=4AlZ9ywOHhlEoGErF8F1I1HACsFRnU1KxnpPo3KIvpM,1187
|
|
33
|
+
stabilize/queue/messages.py,sha256=eSQp5lK0oeLlUenwIJQiLTWRYT5JfvjLyZ-MWKqI3w0,8333
|
|
34
|
+
stabilize/queue/processor.py,sha256=qPqxQlwpsC4J6mrXpeoIz1eM397696I2mNdR1V_EJmU,9073
|
|
35
|
+
stabilize/queue/queue.py,sha256=-L32SLnk403ZV_qeQfFDJ1G6svX5G3IZdwrX2-RmPs0,16436
|
|
36
|
+
stabilize/queue/sqlite_queue.py,sha256=7hxeI7Q317pY2JpP4GIGdYJZbDKM2LgiuCLTj3GBH5U,11538
|
|
37
|
+
stabilize/rag/__init__.py,sha256=ID5zjgtzMY2zAx-VTJ1ESRqFjnA73WR-gPBsBU90xdE,378
|
|
38
|
+
stabilize/rag/assistant.py,sha256=jmElT5ZgFQu3it81lvBPc81bUB0jLGIvUMdywRKn3Eg,17273
|
|
39
|
+
stabilize/rag/cache.py,sha256=oXCYnX6dJRvKHtBHe3Zr5YPivumHh73Cg_4EQOOX_zo,9697
|
|
40
|
+
stabilize/stages/__init__.py,sha256=cQJkyv8bkQ5Je-DNIo5oVl4YoFxHSNydC402TQk5zkg,243
|
|
41
|
+
stabilize/stages/builder.py,sha256=zUu9IznW_DhYrBXiMCCX2owOgxxlBvuJ8iAaDWJuGwg,7133
|
|
42
|
+
stabilize/tasks/__init__.py,sha256=Mgz08g1DYgpKy8MhmopwupNTeSL6cCbYJEvcb4F4fVo,374
|
|
43
|
+
stabilize/tasks/interface.py,sha256=8cocNsfHWNHzOf9XtMTRd2ctdyJvp2AOgb4G_SXvgDM,8990
|
|
44
|
+
stabilize/tasks/registry.py,sha256=wMi7IFkBGn5iweXp2QRs7a33RJjhqGd_e7yP4qHUXkc,7006
|
|
45
|
+
stabilize/tasks/result.py,sha256=7U5p-pZguNvX8M1lyDkbWKTbn9-2T7qzGS7rshRz3Bc,7096
|
|
46
|
+
stabilize/examples/__init__.py,sha256=8zCTqVKrDmMPslObBLBaX7TO1_yHThnvbZfyMbSR_Fk,51
|
|
47
|
+
stabilize/examples/docker-example.py,sha256=s9-OKEQIaNQJvJVZ_NCoQuxBmEyDJTCJmBmZ8kpOrig,25358
|
|
48
|
+
stabilize/examples/golden-standard-expected-result.txt,sha256=igeb_4YtZkO20wh91PELrDwk-BcVG4L9BZS4kp3KUj8,183
|
|
49
|
+
stabilize/examples/golden-standard.py,sha256=hVq2Y0CTuNYNhJPikAjMWBQQVL5QfnrxLuW90SyRqW4,16716
|
|
50
|
+
stabilize/examples/http-example.py,sha256=oUg__SrWXITzt9i11csXIgvQMUoXC_V2eb4pexh_hCc,20792
|
|
51
|
+
stabilize/examples/llama-example.py,sha256=TG2PfWeDf8dtL1HzevGZTbv6vD8eI79_wG8WZ9mp8Uo,23743
|
|
52
|
+
stabilize/examples/python-example.py,sha256=rIeLRntA_xoivWMf1CmwZh1-zFKd9bJFUwUkOp-317s,23061
|
|
53
|
+
stabilize/examples/shell-example.py,sha256=OeHa9ZyGdbcdeCullRqFbnuChmX1V9f2NiJYTEUSvk0,13851
|
|
54
|
+
stabilize/examples/ssh-example.py,sha256=m0TLyZgmcjA1i8fG-O29VY6k3DcPGHA8sT-iLyA-teU,20329
|
|
55
|
+
stabilize/migrations/01KDQ4N9QPJ6Q4MCV3V9GHWPV4_initial_schema.sql,sha256=HQxEBsQ7HQZf1cSSsrHZuRaHKOuDNGHrYF71OC29ot0,3244
|
|
56
|
+
stabilize/migrations/01KDRK3TXW4R2GERC1WBCQYJGG_rag_embeddings.sql,sha256=GlS7EFDb0HZ_R5aD1Uv38_zyquP-iBdaA3kDqDUbh64,720
|
|
57
|
+
stabilize-0.9.2.dist-info/METADATA,sha256=fjPI_LLf6na5ZdnKk9e_5eoK09bbg52xaTSpJAxgZBY,8167
|
|
58
|
+
stabilize-0.9.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
59
|
+
stabilize-0.9.2.dist-info/entry_points.txt,sha256=m2JqUEJIa-jJF1mljmS470__o4UnuVt__IlhhrclS8U,49
|
|
60
|
+
stabilize-0.9.2.dist-info/licenses/LICENSE,sha256=2KBcAK1QM2XEtDBVt3osZV0xnwYlS_F8iFeKLtYSbM0,11345
|
|
61
|
+
stabilize-0.9.2.dist-info/RECORD,,
|