
Um interpretador Python mínimo e seguro escrito em Rust para uso por IA.
Experimental - Este projeto ainda está em desenvolvimento e não está pronto para uso em produção.
Um interpretador Python mínimo e seguro escrito em Rust para uso por IA.
O Monty evita o custo, a latência, a complexidade e o incômodo geral de usar um sandbox baseado em contêiner completo para executar código gerado por LLM.
Em vez disso, ele permite que você execute com segurança código Python escrito por um LLM incorporado ao seu agente, com tempos de inicialização medidos em dígitos únicos de microssegundos, não em centenas de milissegundos.
O que o Monty consegue fazer:
sys, os, typing, asyncio, re, datetime, json, dataclasses (em breve)O que o Monty não pode fazer:
Em resumo, o Monty é extremamente limitado e projetado para um caso de uso:
Executar código escrito por agentes.
Para entender a motivação de por que você pode querer fazer isso, veja:
Em termos muito simples, a ideia de tudo isso é que LLMs podem trabalhar mais rápido, de forma mais barata e mais confiável se forem solicitados a escrever código Python (ou Javascript), em vez de depender do chamamento tradicional de ferramentas. O Monty torna isso possível sem a complexidade de um sandbox ou o risco de executar código diretamente no host.
Nota: o Monty será (em breve) usado para implementar o codemode no Pydantic AI
O Monty pode ser chamado a partir de Python, JavaScript/TypeScript ou Rust.
Para instalar:```bash uv add pydantic-monty
(Ou `pip install pydantic-monty` para os boomers)
`pydantic-monty` é um metapacote que combina `pydantic-monty-client` (o
módulo `pydantic_monty`) com `pydantic-monty-runtime` (o binário do worker
`monty`). Instale apenas `pydantic-monty-client` se o binário já vier de
outro 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())
A execução acontece em um pool de subprocessos workers monty, então até mesmo um erro de memória acionado por código adversarial (estouro de pilha, abort do alocador) nunca pode derrubar seu processo — o worker morre, levanta MontyCrashedError, e é substituído. Também existe uma 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
O pacote JS é um binding nativo (napi) sobre o mesmo pool de workers Rust que o
pacote Python usa — o binding e o binário do worker monty são distribuídos via
pacotes npm específicos de plataforma:```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