代码模式执行器

一个允许LLM生成并执行JavaScript代码以调用Python工具的高效执行器,适用于开发效率提升。

  • by imfing
  • Python
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 imfing/codemode

使用说明

编码模式

与其一次调用一个工具,不如让LLM编写代码,在一次更有效的令牌传递中编排Python工具。

Codemode通过以下方式在进程内V8隔离中运行该代码 jsrun。隔离在5ms内启动,运行时性能与Node.js相同,默认情况下没有网络或文件系统访问权限,除非通过您明确提供的函数,否则无法访问主机。

实验性:这个项目处于早期开发阶段

安装

pip install py-codemode[mcp]
# or
uv add py-codemode[mcp]

对于没有MCP的核心执行器: pip install py-codemode

快速开始

创建具有内置功能和自定义工具的MCP服务器:

from codemode import EnvCapability, FsCapability, HttpCapability
from codemode.mcp import CodeModeServer

server = CodeModeServer(
    name="example",
    capabilities=[
        EnvCapability(allowed_keys=["USER"]),
        FsCapability(allowed_paths=["./examples"]),
        HttpCapability(allowed_hosts=["httpbin.org"]),
    ],
    enable_search=True,
)


@server.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b


if __name__ == "__main__":
    server.mcp.run(transport="streamable-http")

奔跑 uv run python examples/mcp_server.py 并连接任何MCP客户端。

这 codemode[mcp] extra将执行器包装为MCP服务器,公开:

  • execute --运行调用Python函数的JavaScript。TypeScript声明是根据你的类型提示自动生成的,并嵌入在工具描述中,这样LLM就知道什么是可调用的。
  • search (可选,通过 enable_search=True)--按名称或描述搜索已注册的功能和工具。

运作原理

┌─────────────────────┐         ┌──────────────────────┐
│  V8 isolate (jsrun) │         │  Python host         │
│                     │         │                      │
│  LLM-generated JS   │         │  Executor            │
│  runs in async IIFE │         │                      │
│                     │  bridge │                      │
│  codemode.fn({...}) ├────────►│  _dispatch()         │
│                     │◄────────┤  -> your_fn(**kwargs)│
│                     │  result │                      │
└─────────────────────┘         └──────────────────────┘

执行器将代码封装在一个线束中,该线束捕获控制台输出并设置 codemode 代理对象。代理拦截每个 codemode.*() 调用,将其序列化为JSON,并桥接回Python,其中 _dispatch() 将其路由到匹配的主机函数。MCP服务器使用 Executor 引擎盖下。

主机功能

宿主函数仅使用带有类型提示的关键字参数:

async def read(*, path: str) -> str:
    return open(path).read()

从JavaScript调用为 await codemode.read({ path: "/tmp/f" })类型提示用于生成TypeScript存根(str 成为 string, int/float 成为 number, list[T] 成为 T[]等等)。

内置功能

功能是具有基于满列表安全性的命名空间主机函数。默认情况下,沙盒没有文件系统、网络或环境访问权限。

能力 命名空间 描述
FsCapability(allowed_paths=[...]) codemode.fs 在允许的路径内进行沙盒读/写
EnvCapability(allowed_keys=[...]) codemode.env 从满列表中读取环境变量
HttpCapability(allowed_hosts=[...]) codemode.http 仅向允许的主机发送HTTP请求

局限性

  • V8运行时,不是Node,所以没有Node内置模块。仅限JavaScript。
  • 没有顶级 import 或 require 沙盒代码

高级

要逐步控制主机调用,请直接使用会话API:

import asyncio
from codemode import Executor, HostCallRequest, RunCompleted, RunFailed

async def main():
    executor = Executor(timeout_s=5)
    session = await executor.start("""
        async () => {
          const a = await codemode.double({ n: 3 });
          const b = await codemode.double({ n: a });
          return b;
        }
    """)

    while True:
        event = await session.next_event()
        if isinstance(event, HostCallRequest):
            result = event.input["n"] * 2
            await session.submit_result(event.call_id, result)
        elif isinstance(event, (RunCompleted, RunFailed)):
            break

    await session.cancel()
    executor.close()

asyncio.run(main())

这使您可以完全控制每个主机调用,这对于记录、审批流或路由到外部服务非常有用。

jsrun还支持通过以下方式将其他JavaScript库加载到隔离中 Runtime.add_static_module() 或者自定义模块加载器、用于更快冷启动的V8堆快照、堆大小限制和每次调用执行超时。请参阅 jsrun文档 了解详情。

延伸阅读

许可证

麻省理工学院