Volver a actualizaciones
Nuevo releaseAug 9, 2026

monty v0.0.20

Un intérprete de Python minimalista y seguro escrito en Rust para uso por IA

Compartir

Monty

Un intérprete de Python mínimo y seguro escrito en Rust para uso por parte de la IA.

CI Codspeed Coverage PyPI versions license Join Slack

Experimental - Este proyecto aún está en desarrollo y no está listo para producción.

Un intérprete de Python mínimo y seguro escrito en Rust para uso por parte de la IA.

Monty evita el costo, la latencia, la complejidad y la molestia general de usar un sandbox basado en contenedores completos para ejecutar código generado por LLM.

En cambio, te permite ejecutar de forma segura código Python escrito por un LLM integrado en tu agente, con tiempos de inicio medidos en microsegundos de un solo dígito, no en cientos de milisegundos.

Lo que Monty puede hacer:

  • Ejecutar un subconjunto razonable de código Python, suficiente para que tu agente exprese lo que quiere hacer
  • Bloquear por completo el acceso al entorno host: el sistema de archivos, las variables de entorno y el acceso a la red se implementan mediante llamadas a funciones externas que el desarrollador puede controlar
  • Llamar funciones en el host, solo las funciones a las que le des acceso
  • Ejecutar verificación de tipos: Monty admite los type hints modernos de Python y viene con ty incluido en un solo binario para ejecutar la verificación de tipos
  • Ser capturado como una instantánea de bytes en las llamadas a funciones externas, lo que significa que puedes almacenar el estado del intérprete en un archivo o base de datos, y reanudarlo más tarde
  • Iniciar extremadamente rápido (<1μs desde el código hasta el resultado de la ejecución), y tiene un rendimiento en tiempo de ejecución similar a CPython (generalmente entre 5 veces más rápido y 5 veces más lento)
  • Poder ser llamado desde Rust, Python o Javascript: como Monty no tiene dependencias de cpython, puedes usarlo en cualquier lugar donde puedas ejecutar Rust
  • Controlar el uso de recursos: Monty puede rastrear el uso de memoria, la profundidad de la pila y el tiempo de ejecución, y cancelar la ejecución si supera los límites preestablecidos
  • Recopilar stdout y stderr y devolverlos al llamador
  • Ejecutar código asíncrono o síncrono en el host mediante código asíncrono o síncrono en el host
  • Usar un pequeño subconjunto de la biblioteca estándar: sys, os, typing, asyncio, re, datetime, json, dataclasses (pronto)

Lo que Monty no puede hacer:

  • Usar el resto de la biblioteca estándar
  • Usar bibliotecas de terceros (como Pydantic); el soporte para bibliotecas externas de Python no es un objetivo
  • definir clases (el soporte debería llegar pronto)
  • usar sentencias match (de nuevo, el soporte debería llegar pronto)

En resumen, Monty es extremadamente limitado y está diseñado para un caso de uso:

Ejecutar código escrito por agentes.

Para motivación sobre por qué podrías querer hacer esto, consulta:

En términos muy simples, la idea de todo lo anterior es que los LLM pueden trabajar más rápido, de forma más económica y más fiable si se les pide que escriban código Python (o Javascript), en lugar de depender de las llamadas a herramientas tradicionales. Monty hace eso posible sin la complejidad de un sandbox ni el riesgo de ejecutar código directamente en el host.

Nota: Monty se usará (pronto) para implementar codemode en Pydantic AI

Uso

Se puede llamar a Monty desde Python, JavaScript/TypeScript o Rust.

Python

Para instalarlo:```bash uv add pydantic-monty

(O `pip install pydantic-monty` para los boomers)

`pydantic-monty` es un metapaquete que combina `pydantic-monty-client` (el módulo `pydantic_monty`) con `pydantic-monty-runtime` (el binario del worker `monty`). Instala `pydantic-monty-client` por sí solo si el binario ya viene de otro lugar.

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())

La ejecución se realiza en un grupo de subprocesos worker monty, por lo que incluso un error de memoria provocado por código adversarial (desbordamiento de pila, aborto del asignador) nunca puede hacer fallar tu proceso — el worker muere, lanza MontyCrashedError, y es reemplazado. También hay una API totalmente síncrona:```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

Para instalar:```bash
npm install @pydantic/monty

El paquete JS es un binding nativo (napi) sobre el mismo pool de workers Rust que usa el paquete Python — el binding y el binario worker monty se distribuyen mediante paquetes npm específicos de cada plataforma:```ts import { Monty } from '@pydantic/monty'

await using pool = await Monty.create() await using session = await pool.checkout()

Categorías