
openai-agents-python 沙箱核心类型体系深度解析User、Permissions、ExecResult 与 ExposedPortEndpoint 源码级指南【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-pythonagents.sandbox.types是 openai-agents-python 沙箱Sandbox子系统最底层的数据类型模块定义了沙箱中谁在运行、以什么权限运行、运行结果如何返回、对外端口如何暴露这四类基础模型。本文以 types.md 对应的 types.py 源码为骨架逐一拆解每个类型的字段、方法、设计意图与底层实现并对照unix_local、docker等实际运行时与测试用例帮助你真正读懂沙箱的运行模型为自定义 Sandbox 运行时或排查沙箱问题打下基础。一、模块定位沙箱世界的“基础类型层”在 openai-agents-python 中沙箱Sandbox为 Agent 的代码执行提供隔离环境。整个沙箱体系分布在src/agents/sandbox/下而types.py是其中最基础、被引用面最广的模块——它不依赖任何沙箱实现只定义纯粹的数据结构。从 sandbox/init.py 可以看到该模块向包外公开了六个符号from .types import ExecResult, ExposedPortEndpoint, FileMode, Group, Permissions, User也就是说任何使用者都可以通过from agents.sandbox import User, Permissions, ...直接导入。而在模块内部这些类型被大量消费entries/base.py 导入FileMode, Group, Permissions, User用于描述工作区条目文件、目录、挂载点的属主与权限manifest.py 导入Group, User用于生成沙箱清单sandboxes/unix_local.py 与 sandboxes/docker.py 导入ExecResult, ExposedPortEndpoint, Permissions, User用于两种实际运行时的执行结果封装与端口映射capabilities/capability.py、apply_patch.py、runtime.py等大量模块导入User用于表示沙箱内操作的用户身份。可以这样理解分层types.py是词汇表entries、manifest、runtime是语法而docker、unix_local是方言实现。本文就从这个词汇表讲起。二、User 与 Group沙箱内的身份模型沙箱内的每个文件、进程都归属某个用户跨文件系统操作时权限判定也依赖用户身份。types.py用两个极简的 Pydantic 模型表达这一概念。2.1 User单一身份class User(BaseModel): name: str def __hash__(self) - int: return hash(self.name) def __eq__(self, other: object) - bool: if not isinstance(other, User): return NotImplemented return self.name other.name要点字段只有一个name即用户名语义上对应 Unix 用户名如root、sandbox。重写了__eq__与__hash__以 name 作为身份判等与哈希的唯一依据。这意味着两个User(nameroot)实例在集合、字典、去重场景中被视为同一个用户。它是 PydanticBaseModel子类支持User(nameroot)这样的构造方式与字段校验。2.2 Group用户组class Group(BaseModel): name: str users: list[User] def __hash__(self) - int: return hash(self.name) def __eq__(self, other: object) - bool: if not isinstance(other, Group): return NotImplemented return self.name other.name要点字段name组名与users组成员列表。同样以name为判等依据users不参与相等比较——一个组是什么由名字决定成员变化不改变组的身份。从源码结构看Group 主要用于manifest.py与entries/base.py中表达组权限场景某个文件/目录归属于某个组组内成员共享group权限位。2.3 为什么实现__hash__Python 中定义了__eq__的类默认会失去可哈希性__hash__置为None。这里显式补回__hash__是为了让User/Group能安全地放进set或作为dict的键——例如沙箱在计算用户去重、权限合并时可以依赖这一身份语义。这是实现细节但也是阅读后续沙箱代码时容易踩坑的地方。三、Permissions与 Unix 权限位完全对齐的权限模型Permissions是types.py中实现最丰富、也最值得精读的类。它把 Unix 权限三元组owner/group/other与目录标志封装为可双向转换的模型同时兼容八进制 mode与ls -l 风格字符串两种表达。3.1 字段与默认值class Permissions(BaseModel): owner: int Field(default0o7) group: int Field(default0) other: int Field(default0) directory: bool Field(defaultFalse)字段类型默认值含义ownerint0o7属主权限位0~7groupint0属组权限位0~7otherint0其他用户权限位0~7directoryboolFalse是否为目录默认值即属主完全控制、其余无权限0o700这是沙箱内工作区文件默认权限的合理选择——默认不给组和其他用户任何访问权。注意默认值用八进制字面量0o7与 FileMode.ALL 常量保持一致见后文。3.2 to_mode()转换为 Unix mode 整数def to_mode(self) - int: mode 0 for perms, shift in [(self.owner, 6), (self.group, 3), (self.other, 0)]: mode | int(perms) shift if self.directory: mode | stat.S_IFDIR return mode实现逻辑owner 左移 6 位rwx 对应 bit 6~8group 左移 3 位other 不移动三者按位或合并若是目录则再叠加stat.S_IFDIR文件类型位。结果可直接用于os.chmod、stat比较等场景。3.3 from_mode()从 mode 整数反解classmethod def from_mode(cls, mode: int) - Permissions: return cls( owner(mode 6) 0b111, group(mode 3) 0b111, other(mode 0) 0b111, directorybool(mode stat.S_IFDIR), )与to_mode互逆。在 unix_local.py 中本地运行时正是用Permissions.from_mode(stat_result.st_mode)把os.stat得到的真实文件 mode 还原为权限对象用于向沙箱侧描述文件状态。3.4 from_str()解析 ls -l 风格字符串这是兼容性最强的入口专门处理drwxr-xr-x这类 10 字符或带后缀的 11 字符权限串classmethod def from_str(cls, perms: str) - Permissions: # coreutils/BSD ls append a single trailing marker to the mode field to flag # alternate access methods: (ACL), (macOS extended attributes), and # . (SELinux security context). Strip it before parsing the 10 mode chars. if len(perms) 11 and perms[-1] in {, , .}: perms perms[:-1] if len(perms) ! 10: raise ValueError(finvalid permissions string length: {perms!r}) directory perms[0] d if perms[0] not in {d, -}: raise ValueError(finvalid permissions type: {perms!r}) ...解析规则首位字符d表示目录-表示普通文件其他字符直接抛ValueError每三位一组分别解析 owner/group/other 的r读、w写、执行位执行位支持特殊字符属主/属组位置可接受x/s/Ss为带 setuid/setgid 的执行位S为无执行位的 setuid/setgidother 位置接受x/t/Tsticky bit 语义长度不是 10 时抛错特别地会先剥离 coreutils/BSDls附加的 ACL、macOS 扩展属性、SELinux 上下文.后缀标记。这意味着你可以直接把ls -l的输出喂给Permissions.from_str而无需手动清洗字符串——对解析外部工具输出非常友好。3.5 链式配置方法def owner_can(self, mode: int) - Self: self.owner mode return self def group_can(self, mode: int) - Self: self.group mode return self def others_can(self, mode: int) - Self: self.other mode return self三个方法分别设置属主/属组/其他权限位并返回self支持链式调用。注意返回类型是Selftyping_extensions且原地修改后返回自身适合在构建配置时写出声明式风格例如perms Permissions().owner_can(FileMode.ALL).group_can(FileMode.READ | FileMode.EXEC)3.6 字符串表示与判等语义__repr__输出形如d rwx r-x ---的 10 字符串目录标志 三组 rwx 展开__str__复用repr__eq__以to_mode()的结果判等——只要最终 mode 相同即便内部 owner/group/other 组合不同也视为相等__hash__同样基于to_mode()保证相等的对象哈希一致。从源码结构可以推断以 mode 为判等基准是为了让同一个权限状态在不同表达方式八进制、字符串、字段组合下可以互等便于沙箱状态同步与 diff 检测。四、FileMode权限位的枚举常量class FileMode(IntEnum): ALL 0o7 NONE 0 READ 1 2 WRITE 1 1 EXEC 1FileMode继承IntEnum因此可直接与整数位运算混用常量值含义READ412读权限WRITE211写权限EXEC1执行权限ALL70o7全部权限rwxNONE0无权限典型用法是位或组合例如FileMode.READ | FileMode.WRITE表示 rw-。测试代码 tests/sandbox/capabilities/test_skills_capability.py 中的Permissions(ownerFileMode.ALL, group0, other0)即用FileMode.ALL表达属主全权。由于是IntEnum它还能与来自stat模块的 mode 整数直接比较、运算避免了常量语义漂移。五、ExecResult命令执行结果的统一载体沙箱内执行命令后所有运行时Docker、Unix 本地、甚至测试替身都用同一个ExecResult返回结果保证上层调用方无需关心后端差异。class ExecResult: stdout: bytes stderr: bytes exit_code: int def __init__(self, *, stdout: bytes, stderr: bytes, exit_code: int) - None: self.stdout stdout self.stderr stderr self.exit_code exit_code def ok(self) - bool: return self.exit_code 0要点三个字段全部为bytes/intstdout、stderr是原始字节流exit_code是进程退出码三个参数均为关键字参数*强制调用形如ExecResult(stdoutb..., stderrb, exit_code0)ok()方法封装退出码是否为 0的判断供上层快速判断成败。它在代码库中的使用非常普遍例如 tests/sandbox/_filesystem_test_session.py 用ExecResult(stdoutb, stderrb, exit_code0 if exists else 1)模拟文件存在性检查unix_local.py 则把本地子进程的真实输出封装进ExecResult返回。错误场景下stderr携带错误信息、exit_code非 0配合 errors.py 中的ExecTimeoutError、ExecTransportError等异常类型构成完整的执行错误模型。六、ExposedPortEndpoint沙箱对外端口映射描述当沙箱需要暴露端口如启动一个 HTTP 服务供外部访问时ExposedPortEndpoint描述如何访问这个端口。dataclass(frozenTrue) class ExposedPortEndpoint: host: str port: int tls: bool False query: str def url_for(self, scheme: str) - str: ...字段一览字段类型默认值含义hoststr—主机地址如127.0.0.1或 IPv6 地址portint—端口号tlsboolFalse是否启用 TLS影响协议前缀与默认端口querystr附加查询串可带?前缀它是frozenTrue的 dataclass创建后不可修改天然适合作为不可变描述对象。例如 unix_local.py 中本地运行时的实现async def _resolve_exposed_port(self, port: int) - ExposedPortEndpoint: return ExposedPortEndpoint(host127.0.0.1, portport, tlsFalse)即本地端口直接映射到回环地址。6.1 url_for()一键生成访问 URLdef url_for(self, scheme: str) - str: normalized scheme.lower() if normalized not in {http, ws}: raise ValueError(scheme must be either http or ws) ...行为规则只接受http与ws两种 scheme大小写不敏感其余抛ValueError根据tls自动选择协议前缀http→https/httpws→wss/ws默认端口分别为 443/80当端口等于默认端口时省略端口号非默认端口则显式拼接:portIPv6 主机地址自动加方括号如[::1]query自动去掉开头的?后拼接到 URL 末尾。例如ExposedPortEndpoint(host127.0.0.1, port8080).url_for(http)得到http://127.0.0.1:8080/而tlsTrue且port443时得到https://127.0.0.1/。这一方法让沙箱调用方无需关心协议与端口细节直接拿到可访问的 URL。七、源码级关联这些类型如何支撑沙箱运转理解了六个类型之后把它们放回沙箱运行链路中看脉络会非常清晰身份与权限User/Group描述以谁的身份Permissions/FileMode描述能做什么。它们被 entries/base.py 用于构造工作区条目Dir、File、各挂载类型被 manifest.py 用于生成沙箱清单Manifest中的属主与权限声明最终在创建沙箱文件系统时落地为真实的 mode 位。执行与结果沙箱运行命令后sandboxes/unix_local.py 与 sandboxes/docker.py 统一以ExecResult返回 stdout/stderr/exit_code上层 Capability如 shell、apply_patch、skills基于ok()与输出内容决策下一步。网络暴露沙箱暴露端口时运行时通过_resolve_exposed_port返回ExposedPortEndpoint调用方用url_for生成 HTTP/WebSocket 地址访问沙箱内服务。对应的参考文档还可继续深入permissions.md 单独收录了User/Group/Permissions/FileMode四个类型的 API 参考entries.md 收录工作区条目类型snapshot.md 收录快照相关模型完整的沙箱运行配置可参阅 config.md 与 runtime.md。八、实战速查常用构造示例以下示例均基于 types.py 的公开 API可直接在项目中验证from agents.sandbox import ( ExecResult, ExposedPortEndpoint, FileMode, Group, Permissions, User, ) # 1. 身份 alice User(namealice) devs Group(namedevs, users[alice]) # 2. 权限属主读写执行组内可读执行其他无权限 perms Permissions(ownerFileMode.ALL, groupFileMode.READ | FileMode.EXEC, other0) assert perms.to_mode() 0o750 assert Permissions.from_mode(0o750) perms assert Permissions.from_str(drwxr-x---) Permissions( ownerFileMode.ALL, groupFileMode.READ | FileMode.EXEC, other0, directoryTrue ) # 3. 链式配置 rw Permissions().owner_can(FileMode.READ | FileMode.WRITE) # 4. 执行结果 result ExecResult(stdoutbhello\n, stderrb, exit_code0) assert result.ok() is True # 5. 端口端点 endpoint ExposedPortEndpoint(host127.0.0.1, port8080) assert endpoint.url_for(http) http://127.0.0.1:8080/ tls_endpoint ExposedPortEndpoint(hostexample.com, port443, tlsTrue) assert tls_endpoint.url_for(ws) wss://example.com/九、总结agents.sandbox.types用六个精炼的类型把沙箱最底层的四个关注点——身份User/Group、权限Permissions/FileMode、执行结果ExecResult、端口暴露ExposedPortEndpoint——完整地模型化。它们既是沙箱各运行时Docker、Unix 本地与上层能力Capability、Manifest、Entries之间的公共契约也是阅读整个src/agents/sandbox/代码库的最佳起点。当你需要自定义 Sandbox 运行时或调试沙箱行为时先吃透这份词汇表往往能事半功倍。【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考