
Un sandbox Python sicuro, scritto in Rust, per codice scritto dall'IA.
Sperimentale - Questo progetto è ancora in fase di sviluppo e non è pronto per l'uso in produzione.
Un interprete Python minimale e sicuro scritto in Rust, pensato per l'uso da parte di IA.
Monty evita i costi, la latenza, la complessità e il fastidio generale di usare una sandbox completa basata su container per eseguire codice generato da LLM.
Invece, ti permette di eseguire in sicurezza codice Python scritto da un LLM integrato nel tuo agente, con tempi di avvio misurati in microsecondi a una cifra, non in centinaia di millisecondi.
Cosa Monty può fare:
sys, os, typing, asyncio, re, datetime, json, dataclasses (presto)Cosa Monty non può fare:
In breve, Monty è estremamente limitato e progettato per un caso d'uso:
Eseguire codice scritto da agenti.
Per capire perché potresti volerlo fare, vedi:
In parole molto semplici, l'idea alla base di tutto ciò è che gli LLM possono lavorare più velocemente, a costi inferiori e in modo più affidabile se viene chiesto loro di scrivere codice Python (o JavaScript) invece di affidarsi alle tradizionali chiamate a strumenti. Monty rende tutto questo possibile senza la complessità di una sandbox o il rischio di eseguire codice direttamente sull'host.
Nota: Monty verrà (presto) utilizzato per implementare codemode in Pydantic AI
Monty può essere richiamato da Python, JavaScript/TypeScript o Rust.
Per installare:```bash uv add pydantic-monty
(Oppure `pip install pydantic-monty` per i boomer)
`pydantic-monty` è un metapackage che abbina `pydantic-monty-client` (il
modulo `pydantic_monty`) con `pydantic-monty-runtime` (il binario del
worker `monty`). Installa `pydantic-monty-client` da solo se il binario proviene già da
un'altra parte.
Uso:```python
from typing import Any
import pydantic_monty
code = """
async def agent(prompt: str, messages: Messages):
while True:
print(f'messages so far: {messages}')
output = await call_llm(prompt, messages)
if isinstance(output, str):
return output
messages.extend(output)
await agent(prompt, [])
"""
type_definitions = """
from typing import Any
Messages = list[dict[str, Any]]
async def call_llm(prompt: str, messages: Messages) -> str | Messages:
raise NotImplementedError()
prompt: str = ''
"""
Messages = list[dict[str, Any]]
async def call_llm(prompt: str, messages: Messages) -> str | Messages:
if len(messages) < 2:
return [{'role': 'system', 'content': 'example response'}]
else:
return f'example output, message count {len(messages)}'
async def main():
async with pydantic_monty.AsyncMonty() as pool:
async with pool.checkout(
script_name='agent.py',
type_check=True,
type_check_stubs=type_definitions,
) as session:
output = await session.feed_run(
code,
inputs={'prompt': 'testing'},
external_lookup={'call_llm': call_llm},
)
print(output)
#> example output, message count 2
if __name__ == '__main__':
import asyncio
asyncio.run(main())
L'esecuzione avviene in un pool di subprocessi worker monty, quindi anche un errore di
memoria innescato da codice avversario (stack overflow, abort dell'allocatore) non può
mai mandare in crash il tuo processo — il worker muore, solleva MontyCrashedError e
viene sostituito. C'è anche un'API completamente sincrona:```python
import pydantic_monty
with pydantic_monty.Monty() as pool: with pool.checkout() as session: # session state persists between feed_run calls session.feed_run('x = 21') print(session.feed_run('x * 2')) #> 42
### JavaScript / TypeScript
Per installare:```bash
npm install @pydantic/monty
The JS package is a native (napi) binding over the same Rust worker pool the
Python package uses — the binding and the monty worker binary ship via
platform-specific npm packages:```ts
import { Monty } from '@pydantic/monty'
await using pool = await Monty.create() await using session = await pool.checkout()
// session state persists between feedRun calls await session.feedRun('x = 21') console.log(await session.feedRun('x * 2')) // 42