omnibioai-tool-runtime 0.1.0__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.
@@ -0,0 +1,371 @@
1
+ Metadata-Version: 2.4
2
+ Name: omnibioai-tool-runtime
3
+ Version: 0.1.0
4
+ Summary: Portable tool runtime for OmniBioAI TES (RESULT_URI uploader for s3:// and azureblob://)
5
+ Author: Manish Kumar
6
+ License: MIT
7
+ Keywords: omnibioai,tes,bioinformatics,batch,azure,aws
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: pydantic>=2.0
14
+ Provides-Extra: aws
15
+ Requires-Dist: boto3>=1.26; extra == "aws"
16
+ Provides-Extra: azure
17
+ Requires-Dist: azure-identity>=1.15; extra == "azure"
18
+ Requires-Dist: azure-storage-blob>=12.19; extra == "azure"
19
+
20
+ # Omni Tool Runtime
21
+
22
+ **Portable, cloud-agnostic execution runtime for OmniBioAI tools**
23
+
24
+ ---
25
+
26
+ ## Overview
27
+
28
+ `omnibioai-tool-runtime` is a **minimal, deterministic execution runtime** used by
29
+ OmniBioAI’s Tool Execution Service (TES) to run individual tools across **multiple execution backends**, including:
30
+
31
+ * Local Docker execution
32
+ * AWS Batch
33
+ * Azure Batch
34
+ * (future) Kubernetes Jobs
35
+ * (future) TES-compatible HPC schedulers
36
+
37
+ The runtime provides a **strict execution contract** so that:
38
+
39
+ * TES adapters stay thin and backend-specific
40
+ * Tool containers remain portable and backend-agnostic
41
+ * Results are uploaded consistently (S3 / Azure Blob / future backends)
42
+
43
+ This mirrors the design philosophy used throughout OmniBioAI:
44
+ **separate orchestration from execution, and execution from logic.**
45
+
46
+ ---
47
+
48
+ ## What This Runtime Is (and Is Not)
49
+
50
+ ### ✅ This runtime **is**
51
+
52
+ * A **containerized tool launcher**
53
+ * Responsible for:
54
+
55
+ * Reading tool inputs from environment variables
56
+ * Executing tool logic
57
+ * Writing `results.json`
58
+ * Uploading results to cloud storage
59
+ * Cloud-agnostic (AWS / Azure supported today)
60
+
61
+ ### ❌ This runtime is **not**
62
+
63
+ * A workflow engine
64
+ * A scheduler
65
+ * An LLM executor
66
+ * A UI layer
67
+
68
+ Those responsibilities live elsewhere in OmniBioAI.
69
+
70
+ ---
71
+
72
+ ## Execution Contract (Critical)
73
+
74
+ All tools executed via `omnibioai-tool-runtime` **must** follow this contract.
75
+
76
+ ### Environment Variables (Injected by TES Adapter)
77
+
78
+ | Variable | Description |
79
+ | ---------------- | -------------------------------------------------- |
80
+ | `TOOL_ID` | Tool identifier (`echo_test`, `blastn`, etc.) |
81
+ | `RUN_ID` | Unique run ID (generated by adapter) |
82
+ | `INPUTS_JSON` | JSON-encoded tool inputs |
83
+ | `RESOURCES_JSON` | JSON-encoded resource request |
84
+ | `S3_RESULT_URI` | (AWS Batch) S3 URI to upload results |
85
+ | `RESULT_URI` | (Azure Batch) `azureblob://` URI to upload results |
86
+
87
+ Only **one** of `S3_RESULT_URI` or `RESULT_URI` is expected per run.
88
+
89
+ ---
90
+
91
+ ## Repository Structure
92
+
93
+ ```text
94
+ omnibioai-tool-runtime/
95
+ ├── Dockerfile
96
+ ├── README.md
97
+ ├── pyproject.toml
98
+ ├── omni_tool_runtime/
99
+ │ ├── __init__.py
100
+ │ ├── result_uri.py # URI parsing & dispatch
101
+ │ ├── upload_result.py # Unified upload logic
102
+ │ └── uploaders/
103
+ │ ├── s3_uploader.py
104
+ │ └── azureblob_uploader.py
105
+ ├── tools/
106
+ │ └── echo_test/
107
+ │ ├── __init__.py
108
+ │ └── run.py
109
+ └── tests/
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Example Tool: `echo_test`
115
+
116
+ This is the **reference implementation** for all future tools.
117
+
118
+ ### Behavior
119
+
120
+ * Reads `INPUTS_JSON`
121
+ * Echoes a value
122
+ * Writes `results.json`
123
+ * Uploads results to configured storage backend
124
+
125
+ ### Minimal tool implementation
126
+
127
+ ```python
128
+ # tools/echo_test/run.py
129
+ import json
130
+ import os
131
+ from omni_tool_runtime.upload_result import upload_result
132
+
133
+ def main():
134
+ tool_id = os.environ["TOOL_ID"]
135
+ run_id = os.environ["RUN_ID"]
136
+ inputs = json.loads(os.environ.get("INPUTS_JSON", "{}"))
137
+
138
+ text = inputs.get("text", "")
139
+
140
+ result = {
141
+ "ok": True,
142
+ "tool_id": tool_id,
143
+ "run_id": run_id,
144
+ "results": {"echo": text},
145
+ }
146
+
147
+ upload_result(result)
148
+
149
+ if __name__ == "__main__":
150
+ main()
151
+ ```
152
+
153
+ ---
154
+
155
+ ## How Results Upload Works
156
+
157
+ `upload_result()` automatically detects the backend:
158
+
159
+ | Backend | URI Example |
160
+ | ------- | ------------------------------------------------- |
161
+ | AWS | `s3://bucket/prefix/run_id/results.json` |
162
+ | Azure | `azureblob://account/container/path/results.json` |
163
+
164
+ The runtime:
165
+
166
+ 1. Serializes result as JSON
167
+ 2. Uploads to correct backend
168
+ 3. Prints result to stdout (for debugging)
169
+
170
+ Adapters **never upload results themselves**.
171
+
172
+ ---
173
+
174
+ ## Building the Docker Image
175
+
176
+ From repository root:
177
+
178
+ ```bash
179
+ docker build -t man4ish/omnibioai-tool-runtime:latest .
180
+ ```
181
+
182
+ Verify:
183
+
184
+ ```bash
185
+ docker images | grep omnibioai-tool-runtime
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Running a Tool Locally (No Cloud)
191
+
192
+ ```bash
193
+ docker run --rm \
194
+ -e TOOL_ID=echo_test \
195
+ -e RUN_ID=local-test-1 \
196
+ -e INPUTS_JSON='{"text":"hello world"}' \
197
+ -e RESOURCES_JSON='{}' \
198
+ man4ish/omnibioai-tool-runtime:latest
199
+ ```
200
+
201
+ Expected:
202
+
203
+ * JSON output printed to stdout
204
+ * No upload attempted if no result URI is provided
205
+
206
+ ---
207
+
208
+ ## AWS Batch Usage
209
+
210
+ ### Job Definition
211
+
212
+ * Image: `man4ish/omnibioai-tool-runtime:latest`
213
+ * Command override:
214
+
215
+ ```json
216
+ ["python", "-m", "tools.echo_test.run"]
217
+ ```
218
+
219
+ ### Injected Environment
220
+
221
+ * `S3_RESULT_URI` provided by `AwsBatchAdapter`
222
+ * IAM Role handles S3 auth
223
+
224
+ ---
225
+
226
+ ## Azure Batch Usage
227
+
228
+ ### Task Settings
229
+
230
+ * Image: `man4ish/omnibioai-tool-runtime:latest`
231
+ * Command:
232
+
233
+ ```bash
234
+ python -m tools.echo_test.run
235
+ ```
236
+
237
+ ### Injected Environment
238
+
239
+ * `RESULT_URI=azureblob://...`
240
+ * Managed Identity handles Blob auth
241
+
242
+ ---
243
+
244
+ ## Pushing the Image
245
+
246
+ ### Docker Hub
247
+
248
+ ```bash
249
+ docker push man4ish/omnibioai-tool-runtime:latest
250
+ ```
251
+
252
+ ### Azure Container Registry
253
+
254
+ ```bash
255
+ az acr login --name YOUR_ACR
256
+ docker tag man4ish/omnibioai-tool-runtime:latest YOUR_ACR.azurecr.io/omnibioai-tool-runtime:latest
257
+ docker push YOUR_ACR.azurecr.io/omnibioai-tool-runtime:latest
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Adding a New Tool
263
+
264
+ ### Step 1: Create tool folder
265
+
266
+ ```bash
267
+ mkdir tools/my_new_tool
268
+ touch tools/my_new_tool/__init__.py
269
+ touch tools/my_new_tool/run.py
270
+ ```
271
+
272
+ ### Step 2: Implement `run.py`
273
+
274
+ Rules:
275
+
276
+ * Must read env vars
277
+ * Must write result via `upload_result()`
278
+ * Must be deterministic
279
+
280
+ ### Step 3: Register tool in adapter config
281
+
282
+ **AWS Batch**
283
+
284
+ ```yaml
285
+ job_definition_map:
286
+ my_new_tool: "omnibioai-my-new-tool:1"
287
+ ```
288
+
289
+ **Azure Batch**
290
+
291
+ ```yaml
292
+ tools:
293
+ my_new_tool:
294
+ image: "man4ish/omnibioai-tool-runtime:latest"
295
+ command: ["python", "-m", "tools.my_new_tool.run"]
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Current State
301
+
302
+ ### Implemented
303
+
304
+ * Unified runtime image
305
+ * AWS Batch support
306
+ * Azure Batch support
307
+ * S3 + Azure Blob uploads
308
+ * Deterministic execution contract
309
+ * Reference `echo_test` tool
310
+
311
+ ### Intentionally Missing (by design)
312
+
313
+ * No workflow orchestration
314
+ * No retry logic
315
+ * No state machine
316
+ * No scheduling policy
317
+
318
+ ---
319
+
320
+ ## Planned Future Enhancements
321
+
322
+ ### Short-term
323
+
324
+ * Tool generator CLI (`omnibioai tool new`)
325
+ * Structured logging
326
+ * Result size validation
327
+ * Runtime version pinning
328
+
329
+ ### Medium-term
330
+
331
+ * Kubernetes Job adapter support
332
+ * Streaming stdout to object storage
333
+ * Tool-level resource enforcement
334
+ * Tool metadata introspection
335
+
336
+ ### Long-term
337
+
338
+ * Signed result manifests
339
+ * Provenance hashing
340
+ * Deterministic replay support
341
+ * Cross-cloud artifact mirroring
342
+
343
+ ---
344
+
345
+ ## Design Philosophy (Important)
346
+
347
+ This runtime is intentionally **boring**.
348
+
349
+ That’s a feature.
350
+
351
+ * No magic
352
+ * No backend assumptions
353
+ * No hidden orchestration
354
+ * One job → one tool → one result
355
+
356
+ Everything complex belongs **above** this layer.
357
+
358
+ ---
359
+
360
+ ## Final Note
361
+
362
+ If this runtime feels similar to:
363
+
364
+ * CWL CommandLineTool
365
+ * TES task containers
366
+ * AWS Batch single-purpose images
367
+
368
+ That’s intentional.
369
+
370
+ You’re building the **correct abstraction boundary**.
371
+
@@ -0,0 +1,7 @@
1
+ tools/__init__.py,sha256=ozA2pps_Svtr0GVsYY_tflQTnVcboA5-_Km8dzyBSZY,55
2
+ tools/echo_test/__init__.py,sha256=51UHqGq6udvibHh8j1krZZYdZQH_cFWOfVeV0vBVVXM,65
3
+ tools/echo_test/run.py,sha256=neXirB_2UWmSTb-FWa-hPqFyZDa6CYN7no6C7w8JHEo,1440
4
+ omnibioai_tool_runtime-0.1.0.dist-info/METADATA,sha256=isMdFMHnord2osvyj-cdbrEg0K3RsBlT0-AUpqpNN0w,7800
5
+ omnibioai_tool_runtime-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ omnibioai_tool_runtime-0.1.0.dist-info/top_level.txt,sha256=Ib4ZA2MPBpiT0tC-0qt5RcP9g42gLddRbx9PiYGa-Fc,6
7
+ omnibioai_tool_runtime-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
tools/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # tools/__init__.py
2
+ from __future__ import annotations
@@ -0,0 +1,2 @@
1
+ # tools/echo_test/__init__.py
2
+ from __future__ import annotations
tools/echo_test/run.py ADDED
@@ -0,0 +1,56 @@
1
+ # tools/echo_test/run.py
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ import sys
7
+
8
+ from omni_tool_runtime.upload_result import upload_to_result_uri
9
+
10
+
11
+ def main() -> int:
12
+ tool_id = os.getenv("TOOL_ID", "")
13
+ run_id = os.getenv("RUN_ID", "")
14
+ result_uri = (os.getenv("RESULT_URI", "") or "").strip()
15
+
16
+ inputs_json = os.getenv("INPUTS_JSON", "{}")
17
+ try:
18
+ inputs = json.loads(inputs_json)
19
+ except Exception as e:
20
+ out = {"ok": False, "error": f"bad INPUTS_JSON: {e}", "tool_id": tool_id, "run_id": run_id}
21
+ print(json.dumps(out))
22
+ return 2
23
+
24
+ text = inputs.get("text") # keep strict contract (or: inputs.get("text") or inputs.get("msg"))
25
+ if text is None:
26
+ result_obj = {
27
+ "ok": False,
28
+ "error": "missing inputs.text",
29
+ "tool_id": tool_id,
30
+ "run_id": run_id,
31
+ "inputs": inputs,
32
+ }
33
+ else:
34
+ result_obj = {
35
+ "ok": True,
36
+ "tool_id": tool_id,
37
+ "run_id": run_id,
38
+ "results": {"echo": text},
39
+ }
40
+
41
+ body = json.dumps(result_obj, indent=2)
42
+
43
+ # Always print for logs/debug
44
+ print(body)
45
+
46
+ # If RESULT_URI not set -> local mode: succeed
47
+ if not result_uri:
48
+ return 0
49
+
50
+ # Cloud mode: upload
51
+ upload_to_result_uri(result_uri=result_uri, content=body.encode("utf-8"))
52
+ return 0
53
+
54
+
55
+ if __name__ == "__main__":
56
+ raise SystemExit(main())