matrx-runtime 0.0.1__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.
- matrx_runtime-0.0.1/.gitignore +271 -0
- matrx_runtime-0.0.1/CLAUDE.md +114 -0
- matrx_runtime-0.0.1/PKG-INFO +48 -0
- matrx_runtime-0.0.1/README.md +27 -0
- matrx_runtime-0.0.1/matrx_runtime/__init__.py +146 -0
- matrx_runtime-0.0.1/matrx_runtime/_config.py +52 -0
- matrx_runtime-0.0.1/matrx_runtime/db/__init__.py +217 -0
- matrx_runtime-0.0.1/matrx_runtime/db/bootstrap/000_substrate.sql +82 -0
- matrx_runtime-0.0.1/matrx_runtime/db/bootstrap/010_identity.sql +84 -0
- matrx_runtime-0.0.1/matrx_runtime/db/bootstrap/020_runtime.sql +206 -0
- matrx_runtime-0.0.1/matrx_runtime/db/models_runtime.py +143 -0
- matrx_runtime-0.0.1/matrx_runtime/engine.py +865 -0
- matrx_runtime-0.0.1/matrx_runtime/lifecycle.py +142 -0
- matrx_runtime-0.0.1/matrx_runtime/models.py +353 -0
- matrx_runtime-0.0.1/matrx_runtime/origins.py +79 -0
- matrx_runtime-0.0.1/matrx_runtime/orm_store.py +388 -0
- matrx_runtime-0.0.1/matrx_runtime/store.py +364 -0
- matrx_runtime-0.0.1/pyproject.toml +54 -0
- matrx_runtime-0.0.1/tests/__init__.py +0 -0
- matrx_runtime-0.0.1/tests/test_bootstrap_schema.py +121 -0
- matrx_runtime-0.0.1/tests/test_engine.py +223 -0
- matrx_runtime-0.0.1/tests/test_idempotency.py +35 -0
- matrx_runtime-0.0.1/tests/test_lease_reaper.py +271 -0
- matrx_runtime-0.0.1/tests/test_lifecycle.py +76 -0
- matrx_runtime-0.0.1/tests/test_meter_and_context.py +73 -0
- matrx_runtime-0.0.1/tests/test_origins.py +53 -0
- matrx_runtime-0.0.1/tests/test_orm_store.py +206 -0
- matrx_runtime-0.0.1/tests/test_payload_blind.py +99 -0
- matrx_runtime-0.0.1/tests/test_proof.py +127 -0
- matrx_runtime-0.0.1/tests/test_scope.py +190 -0
- matrx_runtime-0.0.1/tests/test_tree_read.py +134 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
secrets/
|
|
3
|
+
ignore/
|
|
4
|
+
temp/
|
|
5
|
+
logs/
|
|
6
|
+
# The broad `logs/` rule above is for RUNTIME log output, but it also matched
|
|
7
|
+
# the dashboard's SOURCE directory and silently swallowed an entire feature's
|
|
8
|
+
# files (only the pre-existing index.tsx stayed tracked), breaking the prod
|
|
9
|
+
# Docker build with "Could not resolve ./structured-tab". Re-include the source.
|
|
10
|
+
!apps/dashboard/src/features/logs/
|
|
11
|
+
!apps/dashboard/src/features/logs/**
|
|
12
|
+
todo
|
|
13
|
+
text_notes/
|
|
14
|
+
aidream/secrets/2.env
|
|
15
|
+
automation_matrix/matrix_processing/temp/*
|
|
16
|
+
cd
|
|
17
|
+
# Byte-compiled / optimized / DLL files
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[cod]
|
|
20
|
+
*$py.class
|
|
21
|
+
|
|
22
|
+
# C extensions
|
|
23
|
+
*.so
|
|
24
|
+
.venv/
|
|
25
|
+
|
|
26
|
+
# Distribution / packaging
|
|
27
|
+
.Python
|
|
28
|
+
build/
|
|
29
|
+
develop-eggs/
|
|
30
|
+
dist/
|
|
31
|
+
downloads/
|
|
32
|
+
eggs/
|
|
33
|
+
.eggs/
|
|
34
|
+
lib/
|
|
35
|
+
lib64/
|
|
36
|
+
# The blanket lib/ rule above is from the standard Python .gitignore template
|
|
37
|
+
# and was silently swallowing TS source under the SPA `src/lib/` folders.
|
|
38
|
+
# Re-allow them explicitly so frontend builds don't ship without their lib layer.
|
|
39
|
+
!apps/dashboard/src/lib/
|
|
40
|
+
!apps/dashboard/src/lib/**
|
|
41
|
+
!apps/workflow-studio/src/lib/
|
|
42
|
+
!apps/workflow-studio/src/lib/**
|
|
43
|
+
parts/
|
|
44
|
+
sdist/
|
|
45
|
+
var/
|
|
46
|
+
wheels/
|
|
47
|
+
share/python-wheels/
|
|
48
|
+
*.egg-info/
|
|
49
|
+
.installed.cfg
|
|
50
|
+
*.egg
|
|
51
|
+
MANIFEST
|
|
52
|
+
|
|
53
|
+
# PyInstaller
|
|
54
|
+
# Usually these files are written by a python script from a template
|
|
55
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
56
|
+
*.manifest
|
|
57
|
+
*.spec
|
|
58
|
+
|
|
59
|
+
# Installer logs
|
|
60
|
+
pip-log.txt
|
|
61
|
+
pip-delete-this-directory.txt
|
|
62
|
+
|
|
63
|
+
# Unit test / coverage reports
|
|
64
|
+
ai/tests/clean_response.json
|
|
65
|
+
ai/tests/cx_storage_response.json
|
|
66
|
+
ai/tests/execution_test.py
|
|
67
|
+
ai/tests/final_response.json
|
|
68
|
+
htmlcov/
|
|
69
|
+
.tox/
|
|
70
|
+
.nox/
|
|
71
|
+
.coverage
|
|
72
|
+
.coverage.*
|
|
73
|
+
.cache
|
|
74
|
+
nosetests.xml
|
|
75
|
+
coverage.xml
|
|
76
|
+
*.cover
|
|
77
|
+
*.py,cover
|
|
78
|
+
.hypothesis/
|
|
79
|
+
.pytest_cache/
|
|
80
|
+
cover/
|
|
81
|
+
|
|
82
|
+
# Translations
|
|
83
|
+
*.mo
|
|
84
|
+
*.pot
|
|
85
|
+
|
|
86
|
+
# Django stuff:
|
|
87
|
+
*.log
|
|
88
|
+
local_settings.py
|
|
89
|
+
db.sqlite3
|
|
90
|
+
db.sqlite3-journal
|
|
91
|
+
|
|
92
|
+
# Flask stuff:
|
|
93
|
+
instance/
|
|
94
|
+
.webassets-cache
|
|
95
|
+
|
|
96
|
+
# Scrapy stuff:
|
|
97
|
+
.scrapy
|
|
98
|
+
|
|
99
|
+
# Sphinx documentation
|
|
100
|
+
docs/_build/
|
|
101
|
+
|
|
102
|
+
# PyBuilder
|
|
103
|
+
.pybuilder/
|
|
104
|
+
target/
|
|
105
|
+
|
|
106
|
+
# Jupyter Notebook
|
|
107
|
+
.ipynb_checkpoints
|
|
108
|
+
|
|
109
|
+
# IPython
|
|
110
|
+
profile_default/
|
|
111
|
+
ipython_config.py
|
|
112
|
+
|
|
113
|
+
# pyenv
|
|
114
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
115
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
116
|
+
# .python-version
|
|
117
|
+
|
|
118
|
+
# pipenv
|
|
119
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
120
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
121
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
122
|
+
# install all needed dependencies.
|
|
123
|
+
#Pipfile.lock
|
|
124
|
+
|
|
125
|
+
# poetry
|
|
126
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
127
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
128
|
+
# commonly ignored for libraries.
|
|
129
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
130
|
+
|
|
131
|
+
# pdm
|
|
132
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
133
|
+
#pdm.lock
|
|
134
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
135
|
+
# in version control.
|
|
136
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
137
|
+
.pdm.toml
|
|
138
|
+
|
|
139
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
140
|
+
__pypackages__/
|
|
141
|
+
|
|
142
|
+
# Celery stuff
|
|
143
|
+
celerybeat-schedule
|
|
144
|
+
celerybeat.pid
|
|
145
|
+
|
|
146
|
+
# SageMath parsed files
|
|
147
|
+
*.sage.py
|
|
148
|
+
|
|
149
|
+
# Environments
|
|
150
|
+
.env
|
|
151
|
+
.env_remote
|
|
152
|
+
.venv
|
|
153
|
+
env/
|
|
154
|
+
venv/
|
|
155
|
+
ENV/
|
|
156
|
+
env.bak/
|
|
157
|
+
venv.bak/
|
|
158
|
+
.env.armanonly
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# random armani files
|
|
179
|
+
/armani_dev/secrets/
|
|
180
|
+
/armani/
|
|
181
|
+
/_armani/
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# pytype static type analyzer
|
|
186
|
+
.pytype/
|
|
187
|
+
|
|
188
|
+
# Cython debug symbols
|
|
189
|
+
cython_debug/
|
|
190
|
+
|
|
191
|
+
.idea/
|
|
192
|
+
.vscode/
|
|
193
|
+
/node_modules/
|
|
194
|
+
|
|
195
|
+
# Frontend pnpm workspace (apps/) — node_modules at the workspace root and any
|
|
196
|
+
# member, plus Vite caches and build output. The unified lockfile (apps/pnpm-lock.yaml)
|
|
197
|
+
# IS committed; everything below is regenerated.
|
|
198
|
+
node_modules/
|
|
199
|
+
apps/**/.vite/
|
|
200
|
+
apps/**/dist/
|
|
201
|
+
.vite/
|
|
202
|
+
|
|
203
|
+
dump.rdb
|
|
204
|
+
|
|
205
|
+
frontend/
|
|
206
|
+
|
|
207
|
+
# AME Temp Files and directory structure
|
|
208
|
+
# Ignore all files in the temp directory and its subdirectories
|
|
209
|
+
/temp/**/*
|
|
210
|
+
/tmp/**/*
|
|
211
|
+
|
|
212
|
+
# Allow .gitkeep files to retain directory structure
|
|
213
|
+
!/temp/**/.gitkeep
|
|
214
|
+
!/tmp/**/.gitkeep
|
|
215
|
+
|
|
216
|
+
# Armani
|
|
217
|
+
.history*
|
|
218
|
+
.history/
|
|
219
|
+
local_data/
|
|
220
|
+
local_reports_data/
|
|
221
|
+
webscraper/quick_scrapes/temp/
|
|
222
|
+
automation_matrix/ai_apis/fireworks/_dev/*
|
|
223
|
+
automation_matrix/ai_apis/fireworks/_dev/fireworks_sample.py
|
|
224
|
+
*.pdf
|
|
225
|
+
*.flac
|
|
226
|
+
*.mp3
|
|
227
|
+
*.wav
|
|
228
|
+
miniconda.sh
|
|
229
|
+
/database/python_sql/temp_data/
|
|
230
|
+
.history*
|
|
231
|
+
.history/
|
|
232
|
+
.history/
|
|
233
|
+
|
|
234
|
+
_dev/
|
|
235
|
+
/_dev/
|
|
236
|
+
requirements_filtered.txt
|
|
237
|
+
|
|
238
|
+
# matrx-dev-tools backups
|
|
239
|
+
.env-backups/
|
|
240
|
+
# Matrx Ship config (contains API key)
|
|
241
|
+
.matrx-ship.json
|
|
242
|
+
|
|
243
|
+
# Matrx config (contains API keys)
|
|
244
|
+
.matrx.json
|
|
245
|
+
.matrx-tools.conf
|
|
246
|
+
|
|
247
|
+
# Claude Code local worktrees and per-user settings
|
|
248
|
+
.claude/worktrees/
|
|
249
|
+
.claude/settings.local.json
|
|
250
|
+
|
|
251
|
+
# Append-only snapshots from matrx_utils.update_history (unbounded; do not commit)
|
|
252
|
+
common/utils/data_in_code/data_history.json
|
|
253
|
+
packages/matrx-utils/matrx_utils/data_in_code/data_history.json
|
|
254
|
+
|
|
255
|
+
# Tool-dispatch debug logs — one file per server start, never committed
|
|
256
|
+
.matrx-debug/
|
|
257
|
+
|
|
258
|
+
# macOS Finder metadata
|
|
259
|
+
.DS_Store
|
|
260
|
+
**/.DS_Store
|
|
261
|
+
|
|
262
|
+
# Environment files
|
|
263
|
+
.env
|
|
264
|
+
.env.*
|
|
265
|
+
*.env
|
|
266
|
+
*.env.*
|
|
267
|
+
|
|
268
|
+
# Keep safe templates trackable
|
|
269
|
+
!.env.example
|
|
270
|
+
!.env.sample
|
|
271
|
+
!.env.template
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# CLAUDE.md — matrx-runtime
|
|
2
|
+
|
|
3
|
+
> **Operating Principle: Build the platform, not the artifact.** Full doctrine: [/PRINCIPLES.md](../../PRINCIPLES.md).
|
|
4
|
+
|
|
5
|
+
**Package:** `matrx-runtime` — the **Request Management Layer** — Python 3.13+ — pre-alpha (v0.0.1).
|
|
6
|
+
**Role in the graph:** the generic request/execution substrate. Sits **below** every consumer (`matrx-ai`, `matrx-graph`, `matrx-scraper`, aidream) and **above** `matrx-utils` / `matrx-connect` / `matrx-orm`.
|
|
7
|
+
|
|
8
|
+
Canonical design: **[docs/runtime/REQUEST_MANAGEMENT_LAYER.md](../../docs/runtime/REQUEST_MANAGEMENT_LAYER.md)** (read it first).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What this package IS
|
|
13
|
+
|
|
14
|
+
> You hand us a request; we own its entire life and its whole nested tree —
|
|
15
|
+
> identity, nesting, status, every failure and success, accumulated cost and any
|
|
16
|
+
> metered limit, context propagation, cancellation, and resume — **without knowing
|
|
17
|
+
> or caring what the work is.**
|
|
18
|
+
|
|
19
|
+
## The ONE invariant — payload-blind
|
|
20
|
+
|
|
21
|
+
matrx-runtime **must never** know the words **chat, agent, conversation, provider,
|
|
22
|
+
token, message, tool**. It deals only in generic `global_execution`s with an
|
|
23
|
+
**opaque `type`** label (a "registered_action": `utility`/`conversation`/`workflow`/…
|
|
24
|
+
— the host's strings, never enumerated here). Feature data lives in the consumer's
|
|
25
|
+
OWN tables, reached only via the opaque `link_kind`/`link_id` pointer. The interiors
|
|
26
|
+
of `MeterEvent` and `ExecutionContext` are opaque too — we sum numerics and
|
|
27
|
+
propagate context without interpreting them.
|
|
28
|
+
|
|
29
|
+
A test (`test_proof.py`) proves it: one engine drives `utility` + `conversation` +
|
|
30
|
+
`workflow` + every nesting case identically. Run `uv run pytest packages/matrx-runtime/tests/test_proof.py -s`.
|
|
31
|
+
|
|
32
|
+
## The surface
|
|
33
|
+
|
|
34
|
+
- **`ExecutionEngine`** (`engine.py`) — the one typed service. `create_root` /
|
|
35
|
+
`spawn_child` (with a `ContextMode`: inherit|scope|replace) / lifecycle
|
|
36
|
+
transitions / `record(MeterEvent)` / tree rollups / `ensure_can_proceed` (budget
|
|
37
|
+
+ per-quantity limit + cancel + deadline) / checkpoints. Status changes ONLY via
|
|
38
|
+
the lifecycle (`transition`), CAS so a terminal is written exactly once.
|
|
39
|
+
- **`ExecutionScope`** (`engine.execution(...)` / `scope.child(...)`) — the ONE
|
|
40
|
+
uniform lifecycle wrapper every consumer runs work inside: enter creates+starts,
|
|
41
|
+
clean exit auto-completes with accrued cost, an exception auto-fails (structured
|
|
42
|
+
error) or cancels and re-raises; `record` / `ensure_can_proceed` / `checkpoint` /
|
|
43
|
+
`request_input` / `renew_lease` / `note` (opaque observability annotation on THIS
|
|
44
|
+
execution — the scope-level door to `record_note`) for the body; explicit
|
|
45
|
+
`complete/fail/cancel` for return-based consumers. No consumer hand-rolls lifecycle — utility/conversation/
|
|
46
|
+
workflow differ only in the body.
|
|
47
|
+
- **Crash recovery — lease + reaper (layer 1, ACTS) + `find_stuck` (layer 2, ALARMS).**
|
|
48
|
+
`start(holder=, lease_seconds=)` leases a running execution (opt-in; unleased = never
|
|
49
|
+
reaped), `renew_lease(...)` heartbeats, **`reap_expired(now=)`** sweeps dead-worker
|
|
50
|
+
executions → FAILED `matrx_execution_abandoned` (cost preserved, CAS-safe). Because
|
|
51
|
+
unleased actives are structurally invisible to the reaper, **`find_stuck(now=, older_than=)`**
|
|
52
|
+
is the independent second layer: it RETURNS (never mutates) the reaper-blind stuck rows
|
|
53
|
+
(unleased/ never-started actives past a deadline) so the host watchdog screams — no work is
|
|
54
|
+
ever silently lost. Both host-scheduled.
|
|
55
|
+
- **`MeterEvent`** (`models.py`) — the metering primitive. A consumer subclasses it
|
|
56
|
+
with numeric fields; EVERY numeric is a tracked quantity summed per execution +
|
|
57
|
+
tree; `money_field` feeds the budgeted `cost`. Covers money, tokens, rate-limits,
|
|
58
|
+
rows — one mechanism, runtime knows none of their meanings.
|
|
59
|
+
- **`ExecutionContext`** + `ContextMode` — the typed context carrier. Runtime owns
|
|
60
|
+
PROPAGATION + per-execution SNAPSHOT across the tree (where the nested-handoff bug
|
|
61
|
+
class lived); the interior is opaque; creation stays Matrx Connect.
|
|
62
|
+
- **Origin registry** (`origins.py`) — `sync_origins` (config-driven, drift-checked,
|
|
63
|
+
soft-deleted) + `is_caller_allowed` (host admission policy). CORS/transport stays
|
|
64
|
+
Connect; runtime owns only the guest list + policy.
|
|
65
|
+
- **`ExecutionStore`** port + `InMemoryExecutionStore` (tests) + matrx-orm
|
|
66
|
+
`OrmExecutionStore` (the 7 `runtime.*` tables).
|
|
67
|
+
|
|
68
|
+
## What this package is NOT
|
|
69
|
+
|
|
70
|
+
- **NOT an executor.** The conversation loop is `matrx-ai`'s; the workflow superstep
|
|
71
|
+
is `matrx-graph`'s; utilities are the consumer's. They drive the engine; their
|
|
72
|
+
complexity never leaks in here.
|
|
73
|
+
- **NOT transport** (CORS/auth/streaming = Matrx Connect), **NOT the work**, **NOT a
|
|
74
|
+
general logger**, **NOT feature tables.**
|
|
75
|
+
|
|
76
|
+
## DB models
|
|
77
|
+
|
|
78
|
+
`db/models_runtime.py` is GENERATED (the `runtime` entry in aidream's
|
|
79
|
+
`db/matrx_orm.yaml`) — change the live schema, then `python db/generate.py`; never
|
|
80
|
+
hand-edit beyond keeping it in sync. The 7 tables: `global_origin`,
|
|
81
|
+
`global_request`, `global_execution`, `global_execution_control`,
|
|
82
|
+
`global_execution_event`, `global_execution_checkpoint`, `global_meter_entry`.
|
|
83
|
+
|
|
84
|
+
## Standalone substrate (the package DEFINES its own schema)
|
|
85
|
+
|
|
86
|
+
matrx-runtime is a **standalone, opinionated** package: it ships the canonical
|
|
87
|
+
substrate it needs and CREATES it on a bare DB. `db/bootstrap/*.sql` (applied in
|
|
88
|
+
`NNN_*` order by **`apply_schema()`**) creates the schemas (`platform`/`iam`/`runtime`),
|
|
89
|
+
the `visibility`/`permission_level` enums, the portable `_touch_row`/`_stamp_actor`
|
|
90
|
+
trigger functions (GUC actor, NOT `auth.uid()`), a minimal `organizations` + registries
|
|
91
|
+
+ fail-closed `iam.has_access`, and the 7 `runtime.*` tables + indexes + triggers + RLS.
|
|
92
|
+
- **Standalone:** `bootstrap_db()` (pool) → `await apply_schema()` (DDL). Fresh DB → working spine.
|
|
93
|
+
- **Hosted (aidream):** the real substrate exists; aidream does NOT call `apply_schema()`.
|
|
94
|
+
- **THE INVARIANT — non-destructive:** every statement is `IF NOT EXISTS` /
|
|
95
|
+
create-if-absent / `ON CONFLICT DO NOTHING`. Running it against aidream changes
|
|
96
|
+
NOTHING; it never overwrites a richer host object. `test_bootstrap_schema.py` enforces
|
|
97
|
+
this. Full design + the pattern for other packages: [docs/runtime/STANDALONE_SUBSTRATE.md](../../docs/runtime/STANDALONE_SUBSTRATE.md).
|
|
98
|
+
|
|
99
|
+
## Dependency rules (mechanically enforced)
|
|
100
|
+
|
|
101
|
+
- Declare ONLY what you import (`pydantic`, `matrx-orm`). The boundary gate fails
|
|
102
|
+
the build on an undeclared sibling or any `aidream`/repo-root import.
|
|
103
|
+
- ❌ Never import an executor (`matrx-ai`, `matrx-graph`) — the dependency points the other way.
|
|
104
|
+
- ❌ Never name a chat/agent/provider concept in this package.
|
|
105
|
+
|
|
106
|
+
## Testing
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run pytest packages/matrx-runtime/tests
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The whole behavioral core is tested against `InMemoryExecutionStore`, **no
|
|
113
|
+
database**. `OrmExecutionStore` is unit-tested with mocked matrx-orm Models
|
|
114
|
+
(`test_orm_store.py`) — call-shape only, never a live DB.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: matrx-runtime
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: The durable-execution substrate: one global_execution spine, one lifecycle state machine, one cost ledger, that every matrx-* executor (agent loop, workflow superstep, utilities) plugs into.
|
|
5
|
+
Author-email: Matrx <admin@aimatrx.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: durable,execution,matrx,orchestration,runtime
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Python: >=3.13
|
|
15
|
+
Requires-Dist: matrx-orm>=3.1
|
|
16
|
+
Requires-Dist: pydantic>=2.12
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# matrx-runtime
|
|
23
|
+
|
|
24
|
+
The durable-execution substrate for the Matrx platform.
|
|
25
|
+
|
|
26
|
+
Every unit of work — a utility call, a workflow run, an agent session — is one
|
|
27
|
+
row on a single `global_execution` spine that can nest inside any other. The
|
|
28
|
+
substrate owns the concerns all three flavors share, so they compose freely and
|
|
29
|
+
share **one lifecycle, one nesting tree, one cost ledger, and one enforced state
|
|
30
|
+
machine**:
|
|
31
|
+
|
|
32
|
+
- run identity + lineage (`parent_execution_id`, denormalized `root_execution_id`)
|
|
33
|
+
- the lifecycle state machine (`transition()` — the only legal way to change status)
|
|
34
|
+
- the cost ledger + tree-wide budget *(forthcoming)*
|
|
35
|
+
- cancellation signal + down-tree propagation *(forthcoming)*
|
|
36
|
+
- generalized checkpoint + lifecycle-event primitives *(forthcoming)*
|
|
37
|
+
- the hardened write coordinator *(moving in from matrx-ai)*
|
|
38
|
+
- the typed runtime context *(forthcoming)*
|
|
39
|
+
|
|
40
|
+
Executors plug in as strategies and are NOT owned here: the agent loop
|
|
41
|
+
(`matrx-ai`), the superstep DAG (`matrx-graph`), utility implementations
|
|
42
|
+
(`matrx-scraper`).
|
|
43
|
+
|
|
44
|
+
Status: **pre-alpha.** The pure decision core (lifecycle + spine models) is in
|
|
45
|
+
place; the persistence/coordinator/context drops follow. Built behind a `/v2`
|
|
46
|
+
route; the legacy `cx_*` / `wf_*` paths are untouched until cutover.
|
|
47
|
+
|
|
48
|
+
Design + phased plan: [`docs/runtime/EXECUTION_SPINE.md`](../../docs/runtime/EXECUTION_SPINE.md).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# matrx-runtime
|
|
2
|
+
|
|
3
|
+
The durable-execution substrate for the Matrx platform.
|
|
4
|
+
|
|
5
|
+
Every unit of work — a utility call, a workflow run, an agent session — is one
|
|
6
|
+
row on a single `global_execution` spine that can nest inside any other. The
|
|
7
|
+
substrate owns the concerns all three flavors share, so they compose freely and
|
|
8
|
+
share **one lifecycle, one nesting tree, one cost ledger, and one enforced state
|
|
9
|
+
machine**:
|
|
10
|
+
|
|
11
|
+
- run identity + lineage (`parent_execution_id`, denormalized `root_execution_id`)
|
|
12
|
+
- the lifecycle state machine (`transition()` — the only legal way to change status)
|
|
13
|
+
- the cost ledger + tree-wide budget *(forthcoming)*
|
|
14
|
+
- cancellation signal + down-tree propagation *(forthcoming)*
|
|
15
|
+
- generalized checkpoint + lifecycle-event primitives *(forthcoming)*
|
|
16
|
+
- the hardened write coordinator *(moving in from matrx-ai)*
|
|
17
|
+
- the typed runtime context *(forthcoming)*
|
|
18
|
+
|
|
19
|
+
Executors plug in as strategies and are NOT owned here: the agent loop
|
|
20
|
+
(`matrx-ai`), the superstep DAG (`matrx-graph`), utility implementations
|
|
21
|
+
(`matrx-scraper`).
|
|
22
|
+
|
|
23
|
+
Status: **pre-alpha.** The pure decision core (lifecycle + spine models) is in
|
|
24
|
+
place; the persistence/coordinator/context drops follow. Built behind a `/v2`
|
|
25
|
+
route; the legacy `cx_*` / `wf_*` paths are untouched until cutover.
|
|
26
|
+
|
|
27
|
+
Design + phased plan: [`docs/runtime/EXECUTION_SPINE.md`](../../docs/runtime/EXECUTION_SPINE.md).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""matrx-runtime — the Request Management Layer.
|
|
2
|
+
|
|
3
|
+
You hand us a request; we own its entire life and its whole nested tree —
|
|
4
|
+
identity, nesting, status, every failure and success, accumulated cost and any
|
|
5
|
+
metered limit, context propagation, cancellation, and resume — WITHOUT knowing or
|
|
6
|
+
caring what the work is. Payload-blind: never chat, agents, providers, tokens, or
|
|
7
|
+
messages. Feature data stays in the consumer's tables, reached via an opaque
|
|
8
|
+
`link_kind`/`link_id`.
|
|
9
|
+
|
|
10
|
+
Design: docs/runtime/REQUEST_MANAGEMENT_LAYER.md. Public API = exactly __all__.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from matrx_runtime.lifecycle import (
|
|
16
|
+
ALLOWED_TRANSITIONS,
|
|
17
|
+
InvalidExecutionTransition,
|
|
18
|
+
TransitionResult,
|
|
19
|
+
can_transition,
|
|
20
|
+
event_for_transition,
|
|
21
|
+
is_terminal,
|
|
22
|
+
transition,
|
|
23
|
+
)
|
|
24
|
+
from matrx_runtime.engine import (
|
|
25
|
+
DEFAULT_LEASE_SECONDS,
|
|
26
|
+
BudgetExceeded,
|
|
27
|
+
ConcurrentTransition,
|
|
28
|
+
DeadlineExceeded,
|
|
29
|
+
ExecutionCancelled,
|
|
30
|
+
ExecutionEngine,
|
|
31
|
+
ExecutionNotFound,
|
|
32
|
+
ExecutionScope,
|
|
33
|
+
InvalidLeaseState,
|
|
34
|
+
LimitExceeded,
|
|
35
|
+
)
|
|
36
|
+
from matrx_runtime.models import (
|
|
37
|
+
TERMINAL_STATUSES,
|
|
38
|
+
ContextMode,
|
|
39
|
+
ExecutionCheckpoint,
|
|
40
|
+
ExecutionContext,
|
|
41
|
+
ExecutionControl,
|
|
42
|
+
ExecutionError,
|
|
43
|
+
ExecutionEvent,
|
|
44
|
+
ExecutionEventKind,
|
|
45
|
+
ExecutionOutcome,
|
|
46
|
+
ExecutionStatus,
|
|
47
|
+
ExecutionTree,
|
|
48
|
+
ExecutionTreeNode,
|
|
49
|
+
GlobalExecution,
|
|
50
|
+
MeterEntry,
|
|
51
|
+
MeterEvent,
|
|
52
|
+
Origin,
|
|
53
|
+
Request,
|
|
54
|
+
)
|
|
55
|
+
from matrx_runtime.store import ExecutionStore, InMemoryExecutionStore
|
|
56
|
+
from matrx_runtime.orm_store import OrmExecutionStore
|
|
57
|
+
from matrx_runtime.origins import (
|
|
58
|
+
OriginSpec,
|
|
59
|
+
OriginSyncResult,
|
|
60
|
+
is_caller_allowed,
|
|
61
|
+
sync_origins,
|
|
62
|
+
)
|
|
63
|
+
from matrx_runtime.db import PACKAGE_DB_NAME, apply_schema, bind_to_host, bootstrap_db
|
|
64
|
+
|
|
65
|
+
__version__ = "0.0.1"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def configure(*, db_config_name: str | None = None) -> None:
|
|
69
|
+
"""Host-injection entry point (called once at startup; mirrors matrx-rag).
|
|
70
|
+
`db_config_name` is the matrx-orm pool the host already registered — we alias
|
|
71
|
+
the package's `"matrx_runtime"` name onto it and register the `runtime.*`
|
|
72
|
+
Models the `OrmExecutionStore` needs. Standalone installs call `bootstrap_db()`."""
|
|
73
|
+
from matrx_runtime import _config
|
|
74
|
+
|
|
75
|
+
if db_config_name is not None:
|
|
76
|
+
_config.set_db_config_name(db_config_name)
|
|
77
|
+
from matrx_orm import is_database_registered
|
|
78
|
+
|
|
79
|
+
from matrx_runtime.db import bind_to_host as _bind
|
|
80
|
+
|
|
81
|
+
if is_database_registered(db_config_name):
|
|
82
|
+
_bind(db_config_name)
|
|
83
|
+
_config.mark_configured()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def is_configured() -> bool:
|
|
87
|
+
from matrx_runtime import _config
|
|
88
|
+
|
|
89
|
+
return _config.is_configured()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
__all__ = [
|
|
93
|
+
# lifecycle
|
|
94
|
+
"transition",
|
|
95
|
+
"can_transition",
|
|
96
|
+
"is_terminal",
|
|
97
|
+
"event_for_transition",
|
|
98
|
+
"TransitionResult",
|
|
99
|
+
"InvalidExecutionTransition",
|
|
100
|
+
"ALLOWED_TRANSITIONS",
|
|
101
|
+
# engine
|
|
102
|
+
"ExecutionEngine",
|
|
103
|
+
"ExecutionScope",
|
|
104
|
+
"ExecutionNotFound",
|
|
105
|
+
"ConcurrentTransition",
|
|
106
|
+
"BudgetExceeded",
|
|
107
|
+
"LimitExceeded",
|
|
108
|
+
"DeadlineExceeded",
|
|
109
|
+
"ExecutionCancelled",
|
|
110
|
+
"InvalidLeaseState",
|
|
111
|
+
"DEFAULT_LEASE_SECONDS",
|
|
112
|
+
# store
|
|
113
|
+
"ExecutionStore",
|
|
114
|
+
"InMemoryExecutionStore",
|
|
115
|
+
"OrmExecutionStore",
|
|
116
|
+
# origin registry
|
|
117
|
+
"OriginSpec",
|
|
118
|
+
"OriginSyncResult",
|
|
119
|
+
"sync_origins",
|
|
120
|
+
"is_caller_allowed",
|
|
121
|
+
# host wiring / db binding
|
|
122
|
+
"configure",
|
|
123
|
+
"is_configured",
|
|
124
|
+
"bind_to_host",
|
|
125
|
+
"bootstrap_db",
|
|
126
|
+
"apply_schema",
|
|
127
|
+
"PACKAGE_DB_NAME",
|
|
128
|
+
# models / enums
|
|
129
|
+
"GlobalExecution",
|
|
130
|
+
"ExecutionStatus",
|
|
131
|
+
"ExecutionEventKind",
|
|
132
|
+
"ContextMode",
|
|
133
|
+
"ExecutionContext",
|
|
134
|
+
"ExecutionError",
|
|
135
|
+
"ExecutionOutcome",
|
|
136
|
+
"ExecutionControl",
|
|
137
|
+
"ExecutionEvent",
|
|
138
|
+
"ExecutionCheckpoint",
|
|
139
|
+
"ExecutionTree",
|
|
140
|
+
"ExecutionTreeNode",
|
|
141
|
+
"MeterEvent",
|
|
142
|
+
"MeterEntry",
|
|
143
|
+
"Origin",
|
|
144
|
+
"Request",
|
|
145
|
+
"TERMINAL_STATUSES",
|
|
146
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Host-injection registry — the seam between matrx-runtime and its host.
|
|
2
|
+
|
|
3
|
+
The host calls :func:`matrx_runtime.configure` once at startup; the package reads
|
|
4
|
+
back what it needs here. Kept tiny and dependency-free (the boundary gate stays
|
|
5
|
+
green). Today the only seam is the matrx-orm pool name the spine persists to; the
|
|
6
|
+
Coordinator/context drops will add their seams here the same way.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
_registry: dict[str, object] = {
|
|
14
|
+
# matrx-orm pool identifier the host registered via
|
|
15
|
+
# register_database_from_env. matrx_runtime.configure(db_config_name=...)
|
|
16
|
+
# aliases PACKAGE_DB_NAME onto it.
|
|
17
|
+
"db_config_name": None,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_configured = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def set_db_config_name(name: str) -> None:
|
|
24
|
+
_registry["db_config_name"] = name
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_configured() -> bool:
|
|
28
|
+
return _configured
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def mark_configured() -> None:
|
|
32
|
+
global _configured
|
|
33
|
+
_configured = True
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_db_config_name() -> str:
|
|
37
|
+
"""Resolve the host's matrx-orm pool name.
|
|
38
|
+
|
|
39
|
+
Order: the name injected via ``configure(db_config_name=...)`` → the
|
|
40
|
+
``MATRX_RUNTIME_DB_NAME`` env var (name of an already-registered config).
|
|
41
|
+
Raises if neither is set — running the ORM-bound store with no configured
|
|
42
|
+
pool is a wiring bug, surfaced loudly rather than silently no-op'd.
|
|
43
|
+
"""
|
|
44
|
+
name = _registry.get("db_config_name") or os.environ.get("MATRX_RUNTIME_DB_NAME")
|
|
45
|
+
if not name:
|
|
46
|
+
raise RuntimeError(
|
|
47
|
+
"matrx-runtime: no database configured. Call "
|
|
48
|
+
"matrx_runtime.configure(db_config_name=<registered matrx-orm pool>) "
|
|
49
|
+
"at host startup, set MATRX_RUNTIME_DB_NAME, or use "
|
|
50
|
+
"matrx_runtime.bootstrap_db() for a standalone pool."
|
|
51
|
+
)
|
|
52
|
+
return str(name)
|