功能特性
连续上下文
变量会在多次调用之间持久化,适合分步执行复杂任务。
异步不阻塞
代码执行运行在独立线程,不阻塞主事件循环。
实时事件输出
可通过
event_emitter 实时获取 stdout、stderr 和输入请求。Session 隔离
不同
PyRepl 实例互相隔离,不共享状态。长输出截断
超长输出可自动写入临时文件并截断回传。
Runtime 原语
可通过
runtime.selfref.* 暴露受控运行时能力。快速开始
多 PyRepl 隔离
工具详解
execute_code
执行 Python 代码,返回执行结果。execute_code 默认有 600 秒活动执行超时保护。等待 input() 期间不会计入超时;每次 input() 成功回填后会重置超时计时。同时,单次 input() 默认 300 秒空闲超时。任一超时触发时 success=False,并在 error 或 stderr 中返回超时信息。你也可以在工具调用时传入 timeout_seconds 为该次执行单独设置超时。execute_code 已启用 too_long_to_file 功能。当代码输出超过 20000 tokens 时,完整结果会自动保存到临时文件,路径会在 <system-reminder> 文本中告知;返回内容会截断到前 20000 tokens,以避免上下文溢出。发送给模型的工具指引会强调:直接编写当前 REPL 会话可执行的顶层代码;先用
runtime.list_primitives() 发现原语,再用 runtime.list_primitives(contains="<namespace>.") 做命名空间过滤;查看契约时优先使用 runtime.get_primitive_spec(name),需要批量查看时再用 runtime.list_primitive_specs(names=[...], contains="...");如果要在代码中直接读取契约字段,请使用 format="dict";reset_repl 只会清理 REPL 变量,不会移除 runtime backend。| 参数 | 类型 | 描述 |
|---|---|---|
| code | str | 要执行的 Python 代码 |
| timeout_seconds | float | 可选,单次调用活动执行超时(秒),不传则使用实例默认值 |
| event_emitter | ToolEventEmitter | 可选,事件发射器用于实时输出 |
PyRepl.execute()。
Python API 返回值:
错误定位增强
execute_code 会尽量直接返回输入代码的定位信息,而不是仅显示框架内部 exec 栈。
典型字段(在 error_details 中):
error_type: 异常类型(如SyntaxError、ZeroDivisionError)message: 异常原始消息line/column: 出错行列(若可解析)snippet: 出错行源码pointer: 列指针(例如^)summary: 面向模型/用户的简洁可读报错摘要user_traceback: 聚焦用户代码栈的 traceback 文本
reset_repl
重置 repl 状态,清除所有变量。面向模型的工具描述为英文,并明确说明:
reset_repl 只清理 REPL 变量,保留已注册的 runtime backend。Streaming 事件
当enable_event=True 时,execute_code 会实时发射以下事件:
| 事件名 | data 字段 | 描述 |
|---|---|---|
kernel_stdout | {text: str} | 标准输出 |
kernel_stderr | {text: str} | 标准错误 |
kernel_input_request | {request_id: str, prompt: str, idle_timeout_seconds: float} | input() 请求用户输入(含本次输入空闲超时) |
捕获 Streaming 事件
@llm_chat(enable_event=True) 消费事件流时,可直接使用 output.origin 区分主链路和 fork 链路:
使用示例
数据分析助手
连续编程上下文
配置选项
PyRepl 构造函数参数
使用 self-reference runtime
PyRepl() 启动时会默认安装内置 selfref pack。
如果你需要在宿主侧预先写入或读取同一份记忆状态,可以直接获取这份默认 backend:
通用 runtime 后端 / 原语注册
如果你只是想扩展一组自定义 runtime primitives,优先使用
pack -> @pack.primitive -> install_pack 这条路径。它把 namespace、backend、guidance 和生命周期放在同一层抽象里,更适合长期维护。PyRepl 也支持通用 runtime 扩展点,不仅限于 selfref 包:
若需要更完整的概念说明,见 Primitive 原语。
其中 pack(..., guidance="...") 适合描述这一整包 runtime 能力的心智模型;具体 primitive 的细节仍然通过 runtime.get_primitive_spec(name) / runtime.list_primitive_specs(...) 查询。
对大多数自定义 runtime primitive 场景,推荐直接采用 pack -> @pack.primitive -> install_pack 这条路径;它会把 namespace、共享 backend、pack guidance 和安装生命周期放在同一个抽象里。
pack(name, backend=..., backend_name=None, guidance="")install_pack(pack, replace=False)@repl.primitive(name, backend="...")register_runtime_backend(name, backend, replace=False)register_primitive(name, handler, description="", backend_name=None, replace=False)register_primitive_pack_installer(pack_name, installer, replace=False)install_primitive_pack(pack_name, **options)list_runtime_backends()andlist_primitives()list_installed_packs()get_primitive_contract(name)/list_primitive_contracts(...)runtime.get_primitive_spec(name)(在 REPL 内)查看单个原语契约runtime.list_primitives(contains="<namespace>.")(在 REPL 内)按命名空间发现原语runtime.list_primitive_specs(names=[...], contains="...")(在 REPL 内)按条件过滤查看:名称、描述、输入/输出、参数与最佳实践
ctx.backend / ctx.get_backend(...) 访问能力,
这样框架才能在 fork/clone 时正确管理依赖。
RuntimePrimitiveBackend 生命周期
如果你的 backend 是一个带状态的服务对象,建议让它实现RuntimePrimitiveBackend:
clone_for_fork(context=...):fork child 时如何复制/共享 backend(默认共享,返回 self)on_install(repl):backend 安装到 PyRepl 时回调on_close(repl):PyRepl 关闭时回调,用于释放资源或清理状态
@llm_chat(...) 使用带 runtime 的工具(如 PyRepl)时,框架会在 prompt 顶部注入去重后的 Tool Best Practices 块;runtime 原语指引会包含在工具自己的最佳实践条目中。
由于 PyRepl() 默认已经安装 builtin selfref pack,llm_chat 可以直接从 toolkit 的 runtime backend 自动解析 SelfReference。
首次回合安全:若 memory key 为空,会在执行工具前把当前 system prompt 写入 self_reference,确保 runtime 读取不为空且包含 system 消息。
在 execute_code 中通过 runtime 原语访问上下文:
将持久经验追加到 system context
这是最常见且推荐的模式:把用户偏好或稳定经验落到 system 内的 experience block 中。常见上下文操作示例
runtime.selfref.guide(): 返回命名空间概览与 fork/context 最佳实践清单。runtime.selfref.context.inspect(key=None): 读取完整上下文快照,包含experiences、结构化summary与完整只读messages。runtime.selfref.context.remember(text, key=None): 向 system experience block 追加 durable experience。runtime.selfref.context.forget(experience_id, key=None): 删除一条错误或过时的 durable experience。runtime.selfref.context.compact(..., key=None): 排队 milestone compaction;当前工具批次结束后会优先提交,让下一次同 turn 的 LLM 调用看到结构化 assistant summary;如果当前 turn 不再继续调用 LLM,finalize 阶段会兜底提交。runtime.selfref.fork.spawn(message, ...): 异步创建子 fork(chat 形态)。子 fork 继承的是 fork 前的上下文快照,不会把父 agent 当前尚未闭合的 fork tool-call 场景当成自己的当前动作。runtime.selfref.fork.gather_all(fork_id_or_list=None, include_history=False): 聚合 fork 结果,返回dict[fork_id -> ForkResult](用.items()/.values()遍历)。
fork_id、memory_key、status、response、result、history_count、history_included=False 等元数据。
读取结果时先看 status,成功后读 response 或 result,失败时检查 error_type / error_message。
只有确实需要子历史时才设置 include_history=True。
Fork 规划清单(runtime.selfref.guide() 会返回同样的 guidance):
- 每一层 agent 只做本层规划,执行下放给子 fork。
- 无依赖的任务尽量并行
fork.spawn(...)。 - fork 前先整理上下文:弱相关信息先总结或落盘。
- fork 提示词写清完成边界和验收标准,优先文件+回传消息交接。
- fork 结果默认是紧凑模式;需要子历史时再按需
include_history=True。 - 每个里程碑后回收并整理上下文,再进入下一阶段。
- 使用
reset_repl清理 REPL 命名空间中的 Python 变量。 - 需要查看原始消息时,使用
runtime.selfref.context.inspect()并从messages字段读取。 - 需要删除错误经验时,使用
runtime.selfref.context.forget(...)。 - 需要在 milestone 结束后清空 stale transcript 时,使用
runtime.selfref.context.compact(...)。
SelfReference 的内部存储,而不是直接暴露可写的原始列表。单次对话中的上下文变更会在工具批次后尽早合并到同 turn 的后续上下文里,并且最迟会在回合结束时合并进返回的 updated_history(事件模式下为 ReactEndEvent.final_messages)。
单个 REPL 中多 agent 共享
为不同 agent 使用不同的self_reference_key:
最佳实践
1. Session 隔离
2. 错误处理
5. 审计日志(每实例独立)
PyRepl 会把代码执行审计记录落盘到独立目录:
- 根目录来自
.env/ 环境变量中的LOG_DIR - 每个实例独立子目录:
<LOG_DIR>/pyrepl/<instance_id>/ - 审计文件:
executions.jsonl
3. 实时反馈
启用event_emitter 获取实时输出,提供更好的用户体验:
4. 重置状态
当需要重新开始时,可以使用reset_repl 清除所有变量:
Related Links
- Example:
examples/pyrepl_example.py - Local runtime context demo:
examples/runtime_primitives_basic_example.py - General TUI agent demo:
examples/tui_general_agent_example.py(workspace scoped to./sandbox) - Responses API TUI agent demo:
examples/response_api_example.py