mitos-run 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.
- mitos_run-0.1.0/.gitignore +12 -0
- mitos_run-0.1.0/PKG-INFO +465 -0
- mitos_run-0.1.0/README.md +433 -0
- mitos_run-0.1.0/examples/direct.py +44 -0
- mitos_run-0.1.0/mitos/__init__.py +52 -0
- mitos_run-0.1.0/mitos/_envelope.py +118 -0
- mitos_run-0.1.0/mitos/_k8s.py +69 -0
- mitos_run-0.1.0/mitos/aio.py +741 -0
- mitos_run-0.1.0/mitos/client.py +382 -0
- mitos_run-0.1.0/mitos/direct.py +639 -0
- mitos_run-0.1.0/mitos/e2b.py +361 -0
- mitos_run-0.1.0/mitos/errors.py +127 -0
- mitos_run-0.1.0/mitos/guest.py +189 -0
- mitos_run-0.1.0/mitos/integrations/__init__.py +43 -0
- mitos_run-0.1.0/mitos/integrations/_mapping.py +178 -0
- mitos_run-0.1.0/mitos/integrations/claude_agent.py +329 -0
- mitos_run-0.1.0/mitos/integrations/langchain.py +226 -0
- mitos_run-0.1.0/mitos/integrations/openai_agents.py +308 -0
- mitos_run-0.1.0/mitos/integrations/vibekit.py +222 -0
- mitos_run-0.1.0/mitos/integrations/zenml.py +244 -0
- mitos_run-0.1.0/mitos/pty.py +173 -0
- mitos_run-0.1.0/mitos/sandbox.py +839 -0
- mitos_run-0.1.0/mitos/template.py +130 -0
- mitos_run-0.1.0/mitos/types.py +225 -0
- mitos_run-0.1.0/mitos/workspace.py +149 -0
- mitos_run-0.1.0/pyproject.toml +65 -0
- mitos_run-0.1.0/tests/__init__.py +0 -0
- mitos_run-0.1.0/tests/test_async.py +114 -0
- mitos_run-0.1.0/tests/test_auth_resolution.py +75 -0
- mitos_run-0.1.0/tests/test_claude_agent_integration.py +243 -0
- mitos_run-0.1.0/tests/test_conformance.py +142 -0
- mitos_run-0.1.0/tests/test_default_pool.py +135 -0
- mitos_run-0.1.0/tests/test_direct.py +158 -0
- mitos_run-0.1.0/tests/test_e2b_compat.py +306 -0
- mitos_run-0.1.0/tests/test_errors.py +63 -0
- mitos_run-0.1.0/tests/test_flat_create.py +633 -0
- mitos_run-0.1.0/tests/test_from_name.py +31 -0
- mitos_run-0.1.0/tests/test_guest.py +145 -0
- mitos_run-0.1.0/tests/test_langchain_integration.py +308 -0
- mitos_run-0.1.0/tests/test_openai_agents_integration.py +254 -0
- mitos_run-0.1.0/tests/test_preview.py +100 -0
- mitos_run-0.1.0/tests/test_pty.py +119 -0
- mitos_run-0.1.0/tests/test_quickstart_snippet.py +91 -0
- mitos_run-0.1.0/tests/test_run_code.py +143 -0
- mitos_run-0.1.0/tests/test_sandbox.py +354 -0
- mitos_run-0.1.0/tests/test_stream.py +225 -0
- mitos_run-0.1.0/tests/test_template_builder.py +73 -0
- mitos_run-0.1.0/tests/test_typed_errors.py +105 -0
- mitos_run-0.1.0/tests/test_types.py +52 -0
- mitos_run-0.1.0/tests/test_vibekit_integration.py +188 -0
- mitos_run-0.1.0/tests/test_wait_ready.py +45 -0
- mitos_run-0.1.0/tests/test_workspace.py +77 -0
- mitos_run-0.1.0/tests/test_zenml_integration.py +165 -0
mitos_run-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mitos-run
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for mitos: sub-millisecond sandbox forking on Kubernetes
|
|
5
|
+
Project-URL: Homepage, https://mitos.run
|
|
6
|
+
Project-URL: Documentation, https://mitos.run/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/mitos-run/mitos
|
|
8
|
+
Project-URL: Issues, https://github.com/mitos-run/mitos/issues
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Keywords: ai-agents,code-interpreter,firecracker,kubernetes,microvm,mitos,sandbox
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
Requires-Dist: websocket-client>=1.7.0
|
|
14
|
+
Provides-Extra: claude-agent
|
|
15
|
+
Requires-Dist: claude-agent-sdk>=0.1; extra == 'claude-agent'
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: kubernetes>=31.0.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: websockets>=12.0; extra == 'dev'
|
|
21
|
+
Provides-Extra: k8s
|
|
22
|
+
Requires-Dist: kubernetes>=31.0.0; extra == 'k8s'
|
|
23
|
+
Provides-Extra: langchain
|
|
24
|
+
Requires-Dist: langchain>=0.3; extra == 'langchain'
|
|
25
|
+
Provides-Extra: openai-agents
|
|
26
|
+
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
|
|
27
|
+
Provides-Extra: vibekit
|
|
28
|
+
Requires-Dist: vibekit>=0.1; extra == 'vibekit'
|
|
29
|
+
Provides-Extra: zenml
|
|
30
|
+
Requires-Dist: zenml>=0.60; extra == 'zenml'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# mitos Python SDK
|
|
34
|
+
|
|
35
|
+
Python client for [mitos-run/mitos](https://github.com/mitos-run/mitos):
|
|
36
|
+
snapshot-fork sandboxes for AI agents on Kubernetes.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install mitos-run
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The PyPI distribution is named `mitos-run` (the bare `mitos` name is taken by an
|
|
43
|
+
unrelated project), but the import package stays `mitos`: you `pip install
|
|
44
|
+
mitos-run` and `import mitos`. Optional extras keep the same import name, for
|
|
45
|
+
example `pip install "mitos-run[k8s]"` for cluster mode.
|
|
46
|
+
|
|
47
|
+
Two modes:
|
|
48
|
+
|
|
49
|
+
- `mitos.create` (flat one-liner): API key plus base URL, returns a Ready
|
|
50
|
+
sandbox handle against the hosted control plane or a standalone
|
|
51
|
+
`sandbox-server`. No Kubernetes required. The canonical entry point.
|
|
52
|
+
- `mitos.AgentRun` / `Sandbox`: drives the Kubernetes CRDs
|
|
53
|
+
(`SandboxClaim`, `SandboxFork`, `SandboxPool`, `SandboxTemplate`) and execs
|
|
54
|
+
through the forkd sandbox API. For operators who run the mitos cluster.
|
|
55
|
+
|
|
56
|
+
## The flat one-liner
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import mitos
|
|
60
|
+
|
|
61
|
+
# MITOS_API_KEY and MITOS_BASE_URL from the environment (explicit args override).
|
|
62
|
+
sb = mitos.create("python")
|
|
63
|
+
print(sb.exec("echo hello").stdout) # hello
|
|
64
|
+
sb.terminate()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`mitos.create(image, api_key=..., base_url=...)` resolves the API key (argument,
|
|
68
|
+
else `MITOS_API_KEY`, else the CLI login credential file written by
|
|
69
|
+
`mitos auth login`, so one login authenticates the SDK too) and base URL
|
|
70
|
+
(argument, else `MITOS_BASE_URL`) and returns a `DirectSandbox` exposing `exec`,
|
|
71
|
+
`run_code`, `files`, `pty`, `fork`, and `terminate`. `Sandbox.create(...)` is an
|
|
72
|
+
alias for the same call.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import mitos
|
|
76
|
+
|
|
77
|
+
sb = mitos.create("python", api_key="sk-...", base_url="http://localhost:8080")
|
|
78
|
+
|
|
79
|
+
sb.files.write("/workspace/plan.txt", "draft")
|
|
80
|
+
print(sb.files.read("/workspace/plan.txt")) # draft
|
|
81
|
+
|
|
82
|
+
ex = sb.run_code("import math; math.sqrt(144)")
|
|
83
|
+
print(ex.text) # 12.0
|
|
84
|
+
|
|
85
|
+
fork_a, fork_b = sb.fork(2) # independent sibling sandboxes
|
|
86
|
+
fork_a.exec("echo a > /workspace/a.txt")
|
|
87
|
+
fork_b.exec("echo b > /workspace/b.txt")
|
|
88
|
+
|
|
89
|
+
sb.terminate()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Auth: the API key rides on `Authorization: Bearer <key>` on every request. The
|
|
93
|
+
standalone `sandbox-server` runs tokenless and ignores it; the hosted control
|
|
94
|
+
plane verifies the same header server-side ([#210], not yet built) without an SDK
|
|
95
|
+
change. The key value is never logged and never placed in an error message. A
|
|
96
|
+
missing base URL raises a typed `AgentRunError(code="missing_base_url")` whose
|
|
97
|
+
remediation names the argument and the env var but no key value.
|
|
98
|
+
|
|
99
|
+
[#210]: https://github.com/mitos-run/mitos/issues/210
|
|
100
|
+
|
|
101
|
+
### Async flat path
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import asyncio
|
|
105
|
+
import mitos.aio
|
|
106
|
+
|
|
107
|
+
async def main():
|
|
108
|
+
sb = await mitos.aio.create("python") # AsyncDirectSandbox
|
|
109
|
+
print((await sb.exec("echo hi")).stdout)
|
|
110
|
+
await sb.files.write("/workspace/a.txt", "x")
|
|
111
|
+
print(await sb.files.read("/workspace/a.txt"))
|
|
112
|
+
ex = await sb.run_code("1 + 1")
|
|
113
|
+
print(ex.text)
|
|
114
|
+
children = await sb.fork(2)
|
|
115
|
+
for c in children:
|
|
116
|
+
await c.terminate()
|
|
117
|
+
await sb.terminate()
|
|
118
|
+
|
|
119
|
+
asyncio.run(main())
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Cluster mode: the one-liner
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from mitos import AgentRun
|
|
126
|
+
|
|
127
|
+
c = AgentRun() # kubeconfig or in-cluster; autodetected
|
|
128
|
+
|
|
129
|
+
sb = c.sandbox("python", ready=True) # lazy default pool, waits Ready
|
|
130
|
+
print(sb.exec("python -c 'print(2 + 2)'").stdout) # 4
|
|
131
|
+
sb.files.write("/workspace/notes.md", "# findings")
|
|
132
|
+
print(sb.files.read("/workspace/notes.md")) # "# findings"
|
|
133
|
+
sb.terminate()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`c.sandbox("python")` ensures a deterministic default pool
|
|
137
|
+
`mitos-default-python` (a `SandboxTemplate` carrying the image plus a
|
|
138
|
+
`SandboxPool` that references it), creating both if absent. It is
|
|
139
|
+
admin-disableable with `AgentRun(allow_default_pool=False)`, which makes the
|
|
140
|
+
image path raise instead of creating anything.
|
|
141
|
+
|
|
142
|
+
### Explicit pool (never creates anything)
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
sb = c.sandbox(pool="python-agent-pool")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Fork a running sandbox
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
forks = sb.fork(3) # 3 copies of the warmed state
|
|
152
|
+
for f in forks:
|
|
153
|
+
print(f.exec("echo from-fork").stdout)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Reconnect by name (durable handle across processes)
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
sb = c.sandbox("python", name="agent-session-1", ready=True)
|
|
160
|
+
# ... later, in a different process:
|
|
161
|
+
sb = c.from_name("agent-session-1")
|
|
162
|
+
print(sb.exec("cat /workspace/notes.md").stdout)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Readiness
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
sb = c.sandbox("python").wait_until_ready() # chainable; raises on Failed/timeout
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Streaming exec
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# Callbacks fire per chunk (bytes) as output arrives; the returned ExecResult
|
|
175
|
+
# still carries the full aggregate.
|
|
176
|
+
sb.exec("pytest -x", on_stdout=lambda b: print(b.decode(), end=""))
|
|
177
|
+
|
|
178
|
+
# A long-running background command with a handle.
|
|
179
|
+
bg = sb.exec_background("npm run dev")
|
|
180
|
+
# ... do other work ...
|
|
181
|
+
bg.kill()
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Structured errors
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from mitos import AgentRunError
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
sb.exec("false")
|
|
191
|
+
sb.files.read("/does/not/exist")
|
|
192
|
+
except AgentRunError as e:
|
|
193
|
+
print(e.code) # e.g. file_failed, not_found
|
|
194
|
+
print(e.remediation) # an actionable next step
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
`AgentRunError` is parsed from the server envelope
|
|
198
|
+
`{error:{code, message, cause, remediation}}`. Any bearer token a misconfigured
|
|
199
|
+
server reflects into a body is redacted before it becomes the error cause.
|
|
200
|
+
|
|
201
|
+
### Async client (hot paths)
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
import asyncio
|
|
205
|
+
from mitos import AsyncAgentRun
|
|
206
|
+
|
|
207
|
+
async def main():
|
|
208
|
+
c = AsyncAgentRun()
|
|
209
|
+
sb = await c.sandbox("python", ready=True)
|
|
210
|
+
print((await sb.exec("echo async-hello")).stdout)
|
|
211
|
+
await sb.files.write("/workspace/a.txt", "x")
|
|
212
|
+
print(await sb.files.read("/workspace/a.txt"))
|
|
213
|
+
forks = await sb.fork(2)
|
|
214
|
+
for f in forks:
|
|
215
|
+
await f.terminate()
|
|
216
|
+
await sb.terminate()
|
|
217
|
+
|
|
218
|
+
asyncio.run(main())
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`AsyncAgentRun` / `AsyncSandbox` cover the hot paths (exec blocking and
|
|
222
|
+
streaming, files, fork, terminate, wait_until_ready, from_name,
|
|
223
|
+
sandbox(image)). Pool and workspace administration are sync-only. If your build
|
|
224
|
+
includes the code interpreter (#102), `sb.run_code(...)` returns an `Execution`;
|
|
225
|
+
the async client does not yet wrap `run_code`.
|
|
226
|
+
|
|
227
|
+
## Direct mode (no Kubernetes)
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from mitos.direct import SandboxServer
|
|
231
|
+
|
|
232
|
+
server = SandboxServer("http://localhost:8080")
|
|
233
|
+
server.create_template("python")
|
|
234
|
+
sandbox = server.fork("python")
|
|
235
|
+
print(sandbox.exec("print(1 + 1)").stdout)
|
|
236
|
+
sandbox.terminate()
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Templates as code
|
|
240
|
+
|
|
241
|
+
Author a custom environment from code with the fluent `Template` builder, in the
|
|
242
|
+
shape E2B and Daytona use. It emits a `SandboxTemplate` spec; no server or KVM is
|
|
243
|
+
needed to build the spec.
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from mitos import Template
|
|
247
|
+
|
|
248
|
+
spec = (
|
|
249
|
+
Template()
|
|
250
|
+
.from_image("python:3.12")
|
|
251
|
+
.copy("app/", "/app")
|
|
252
|
+
.run("pip install -r requirements.txt")
|
|
253
|
+
.set_start("python app.py")
|
|
254
|
+
.to_spec()
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Or wrap it as a full object to apply to a cluster:
|
|
258
|
+
obj = Template().from_image("node:24").run("npm ci").to_template("web")
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The ordered steps (copy / run / env / workdir) map onto the CRD
|
|
262
|
+
`spec.buildSteps` and feed a content-addressed, chained build cache so unchanged
|
|
263
|
+
steps are reused. See docs/templates.md for the CLI (`mitos template build` /
|
|
264
|
+
`push`) and the cache semantics.
|
|
265
|
+
|
|
266
|
+
## Integrations
|
|
267
|
+
|
|
268
|
+
Framework adapters live under `mitos.integrations`. Each maps a framework's
|
|
269
|
+
sandbox-backend interface onto the native SDK ops (exec, files, run_code, fork),
|
|
270
|
+
so you change the backend and keep your agent code. The framework is an OPTIONAL
|
|
271
|
+
dependency: the adapter modules import mitos always and the framework lazily, so
|
|
272
|
+
the base SDK installs and tests without it.
|
|
273
|
+
|
|
274
|
+
### LangChain / deepagents quickstart
|
|
275
|
+
|
|
276
|
+
LangChain and deepagents let you pick a pluggable sandbox backend (they ship
|
|
277
|
+
`E2BSandbox` and `DaytonaSandbox`). `MitosSandbox` is the mitos backend: change
|
|
278
|
+
the backend, keep your agent code.
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
from mitos.integrations.langchain import MitosSandbox
|
|
282
|
+
|
|
283
|
+
# Standalone sandbox-server / hosted control plane, no Kubernetes:
|
|
284
|
+
sb = MitosSandbox.create("python", base_url="http://localhost:8080")
|
|
285
|
+
|
|
286
|
+
# Shell command -> normalized result dict (stdout, stderr, exit_code).
|
|
287
|
+
out = sb.execute("echo hi") # alias: sb.run("echo hi")
|
|
288
|
+
|
|
289
|
+
# Filesystem ops.
|
|
290
|
+
sb.write_file("/workspace/a.txt", "hello")
|
|
291
|
+
print(sb.read_file("/workspace/a.txt"))
|
|
292
|
+
print(sb.list_files("/workspace"))
|
|
293
|
+
|
|
294
|
+
# Code execution with rich MIME results (image/png, text/html, ...).
|
|
295
|
+
ex = sb.run_code("import math; math.sqrt(144)")
|
|
296
|
+
print(ex.text, ex.results)
|
|
297
|
+
|
|
298
|
+
sb.close() # alias: sb.stop(); lifecycle close
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Install the optional extra only if you use the integration:
|
|
302
|
+
`pip install "mitos-run[langchain]"`. `MitosSandbox` does not subclass any langchain
|
|
303
|
+
type and is fully usable without langchain installed.
|
|
304
|
+
|
|
305
|
+
Fork is a mitos superpower the LangChain sandbox-backend interface does not
|
|
306
|
+
expose, so it is NOT forced onto that interface. Reach branching / parallel runs
|
|
307
|
+
through the adapter's native `fork`, which returns sibling `MitosSandbox`
|
|
308
|
+
backends:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
children = sb.fork(2) # two independent forked sandboxes
|
|
312
|
+
for c in children:
|
|
313
|
+
print(c.execute("echo from-fork")["stdout"])
|
|
314
|
+
c.close()
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The wire-op mapping is factored into `mitos.integrations._mapping` so the other
|
|
318
|
+
adapters (OpenAI / Claude, the E2B-compat shim) reuse one translation layer.
|
|
319
|
+
|
|
320
|
+
### OpenAI Agents SDK quickstart
|
|
321
|
+
|
|
322
|
+
The OpenAI Agents SDK exposes tools as function tools. `MitosSandboxTools` binds
|
|
323
|
+
`run_command` / `read_file` / `write_file` / `run_code` to a mitos sandbox: give
|
|
324
|
+
the tools to your agent and its tool calls run inside the sandbox.
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from mitos.integrations.openai_agents import MitosSandboxTools
|
|
328
|
+
|
|
329
|
+
# Standalone sandbox-server / hosted control plane, no Kubernetes:
|
|
330
|
+
tools = MitosSandboxTools.create("python", base_url="http://localhost:8080")
|
|
331
|
+
|
|
332
|
+
# Use the thin wrappers directly:
|
|
333
|
+
print(tools.run_command("echo hi")["stdout"])
|
|
334
|
+
tools.write_file("/workspace/a.txt", "hello")
|
|
335
|
+
print(tools.read_file("/workspace/a.txt"))
|
|
336
|
+
print(tools.run_code("import math; math.sqrt(144)")["text"])
|
|
337
|
+
|
|
338
|
+
# Or hand real function tools to an Agent (needs the SDK installed):
|
|
339
|
+
from agents import Agent
|
|
340
|
+
agent = Agent(name="coder", tools=tools.as_function_tools())
|
|
341
|
+
|
|
342
|
+
tools.close()
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Install the optional extra only if you use the integration:
|
|
346
|
+
`pip install "mitos-run[openai-agents]"`. The adapter is fully usable and testable
|
|
347
|
+
without `openai-agents`; only `as_function_tools()` needs it and it raises a
|
|
348
|
+
clear error naming the extra when absent.
|
|
349
|
+
|
|
350
|
+
### Claude Agent SDK quickstart
|
|
351
|
+
|
|
352
|
+
The Claude Agent SDK takes custom tools as an in-process MCP server.
|
|
353
|
+
`MitosSandboxTools` binds the same four tools to a mitos sandbox and wraps them
|
|
354
|
+
as an MCP server you pass to the agent.
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from mitos.integrations.claude_agent import MitosSandboxTools
|
|
358
|
+
|
|
359
|
+
# Standalone sandbox-server / hosted control plane, no Kubernetes:
|
|
360
|
+
tools = MitosSandboxTools.create("python", base_url="http://localhost:8080")
|
|
361
|
+
|
|
362
|
+
# The handlers return MCP tool results (a content list of text blocks):
|
|
363
|
+
res = tools.run_command({"command": "echo hi"})
|
|
364
|
+
print(res["content"][0]["text"])
|
|
365
|
+
tools.write_file({"path": "/workspace/a.txt", "content": "hello"})
|
|
366
|
+
print(tools.read_file({"path": "/workspace/a.txt"})["content"][0]["text"])
|
|
367
|
+
|
|
368
|
+
# Or build a real in-process MCP server (needs the SDK installed):
|
|
369
|
+
server = tools.as_mcp_server(name="mitos-sandbox") # pass via mcp_servers
|
|
370
|
+
|
|
371
|
+
tools.close()
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Install the optional extra only if you use the integration:
|
|
375
|
+
`pip install "mitos-run[claude-agent]"`. The adapter is fully usable and testable
|
|
376
|
+
without `claude-agent-sdk`; only `as_mcp_server()` needs it and it raises a clear
|
|
377
|
+
error naming the extra when absent.
|
|
378
|
+
|
|
379
|
+
### Use mitos via VibeKit
|
|
380
|
+
|
|
381
|
+
VibeKit is a provider aggregator over sandbox backends ("E2B today; Daytona,
|
|
382
|
+
Modal, Fly.io coming soon"). `MitosVibeKitProvider` is the mitos provider against
|
|
383
|
+
VibeKit's provider shape: a named provider that creates sandboxes exposing
|
|
384
|
+
command execution, a filesystem, and a lifecycle.
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from mitos.integrations.vibekit import MitosVibeKitProvider
|
|
388
|
+
|
|
389
|
+
provider = MitosVibeKitProvider(base_url="http://localhost:8080") # name == "mitos"
|
|
390
|
+
sandbox = provider.create("python")
|
|
391
|
+
|
|
392
|
+
out = sandbox.run_command("echo hi") # {stdout, stderr, exit_code, exec_time_ms}
|
|
393
|
+
sandbox.write_file("/workspace/a.txt", "hello")
|
|
394
|
+
print(sandbox.read_file("/workspace/a.txt"))
|
|
395
|
+
ex = sandbox.run_code("1 + 1") # rich Execution with MIME results
|
|
396
|
+
sandbox.kill() # alias: sandbox.close()
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Install the optional extra only if you use the integration:
|
|
400
|
+
`pip install "mitos-run[vibekit]"`. The provider does not subclass any VibeKit type
|
|
401
|
+
and is fully usable and testable without VibeKit installed. Fork stays reachable
|
|
402
|
+
as a mitos-native op via `sandbox.fork(n)`, which VibeKit's provider interface
|
|
403
|
+
does not expose.
|
|
404
|
+
|
|
405
|
+
### Use mitos via ZenML
|
|
406
|
+
|
|
407
|
+
ZenML treats a sandbox as a pluggable stack component selected by a flavor.
|
|
408
|
+
`MitosSandboxComponent` is the framework-neutral mitos backend (config, flavor
|
|
409
|
+
name, and the provision / run_command / files / run_code / deprovision logic the
|
|
410
|
+
flavor wraps).
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
from mitos.integrations.zenml import MitosSandboxComponent, MitosSandboxConfig
|
|
414
|
+
|
|
415
|
+
comp = MitosSandboxComponent(
|
|
416
|
+
MitosSandboxConfig(template="python", base_url="http://localhost:8080")
|
|
417
|
+
) # FLAVOR == "mitos"
|
|
418
|
+
comp.provision()
|
|
419
|
+
out = comp.run_command("echo hi") # {stdout, stderr, exit_code, exec_time_ms}
|
|
420
|
+
comp.write_file("/workspace/a.txt", "hello")
|
|
421
|
+
ex = comp.run_code("1 + 1") # rich Execution; comp.run_code_dict(...) for JSON
|
|
422
|
+
comp.deprovision()
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Install the optional extra only if you use the integration:
|
|
426
|
+
`pip install "mitos-run[zenml]"`. The component backend is fully usable and testable
|
|
427
|
+
without ZenML; only `MitosSandboxComponent.flavor()` needs it and raises a clear
|
|
428
|
+
error naming the extra when absent.
|
|
429
|
+
|
|
430
|
+
### Registering mitos with VibeKit / ZenML (maintainer step)
|
|
431
|
+
|
|
432
|
+
The adapters above implement the mitos backend each aggregator expects, but
|
|
433
|
+
LISTING mitos as a selectable option inside VibeKit or ZenML is a contribution to
|
|
434
|
+
THOSE projects' own repositories and is NOT done by installing this SDK. It is a
|
|
435
|
+
maintainer step:
|
|
436
|
+
|
|
437
|
+
- **VibeKit:** open a PR to VibeKit adding a provider entry that constructs
|
|
438
|
+
`MitosVibeKitProvider` and wires its create / command / filesystem methods to
|
|
439
|
+
VibeKit's provider interface, following VibeKit's contribution process.
|
|
440
|
+
- **ZenML:** open a PR (or ship a plugin) that subclasses ZenML's sandbox
|
|
441
|
+
stack-component base with `MitosSandboxConfig` and `FLAVOR = "mitos"`, delegates
|
|
442
|
+
its hooks to `MitosSandboxComponent`, and registers the flavor through ZenML's
|
|
443
|
+
flavor API, following ZenML's integration contribution process.
|
|
444
|
+
|
|
445
|
+
Until those external PRs merge, mitos is usable through the adapters directly (as
|
|
446
|
+
shown above); it is not yet selectable by name inside VibeKit's or ZenML's own
|
|
447
|
+
provider lists. See the module docstrings in `mitos/integrations/vibekit.py` and
|
|
448
|
+
`mitos/integrations/zenml.py` for the targeted contract each PR conforms to.
|
|
449
|
+
|
|
450
|
+
## What is proven where
|
|
451
|
+
|
|
452
|
+
The cluster examples (lazy default-pool creation, fork, from_name reconnect,
|
|
453
|
+
readiness, async hot paths) run against the real Firecracker engine in the KVM
|
|
454
|
+
CI job. The structured-error parsing and the wire shapes are unit-tested with
|
|
455
|
+
no cluster. No latency or throughput number is claimed in this README.
|
|
456
|
+
|
|
457
|
+
## Development
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
pip install -e ".[dev]"
|
|
461
|
+
pytest tests/ -v
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
See the [repository README](https://github.com/mitos-run/mitos#readme)
|
|
465
|
+
for project status; this SDK is pre-alpha and its API may change.
|