v1.2.2
OpenRath v1.2.2
延续 v1.2.1 的动态工作流之后,v1.2.2 把重心放在接入面与运行时健壮性上。核心新特性是 litellm provider:通过一个薄适配器把 OpenRath 接到 100+ 模型供应商(Gemini、Bedrock、Azure、Ollama、Groq……),不必再在内置 Provider / chat_client_for 之外手工接线。围绕它,本版补齐了 Session 的常用取值与序列协议,并集中修复了一批并发竞态、内存增长与持久化 round-trip 的问题。没有破坏性改动,可从 v1.2.1 直接升级。
核心特性
LiteLLM provider(一个适配器接入 100+ 模型)
新增 provider_kind="litellm",经 LiteLLM 路由到上百家供应商。RathLiteLLMChatClient 复用 OpenRath 既有的 OpenAI 归一化与 kwargs 构造逻辑(LiteLLM 返回 OpenAI 兼容响应),因此适配层很薄,并且不改动既有 provider 分派,也不引入新的运行时依赖:
RathLiteLLMChatClient— 实现complete()与complete_stream(),经register_chat_client("litellm", ...)自动注册,chat_client_for()在provider_kind="litellm"时分派。- 可选依赖,零侵入 —
pip install "openrath[litellm]";未安装时懒加载回退,对现有安装毫无影响,provider_kind未设置时仍默认openai。 - 凭据解析顺序 — 先
Provider.api_key/Provider.base_url,再LITELLM_API_KEY/LITELLM_API_BASE环境变量,最后交给 LiteLLM 自身的按供应商解析。 drop_params=True(默认) — 供应商不支持的 kwargs 被静默丢弃,避免因参数差异报错。- 重试 — 复用 OpenRath 的
retry_with_backoff,对RateLimitError/Timeout/APIConnectionError/ServiceUnavailableError/InternalServerError退避重试。
快速上手:
from rath.llm import Provider, chat_client_for
provider = Provider(
provider_kind="litellm",
model="gemini/gemini-2.0-flash", # 或 anthropic/…、bedrock/…、ollama/… 等
api_key="sk-...", # 也可留空,交由 LiteLLM 从环境变量解析
)
client = chat_client_for(provider)
resp = client.complete(req)或经配置:
llm:
provider_kind: litellm
model: anthropic/claude-sonnet-4-20250514
# api_key 由 LiteLLM 从供应商专属环境变量解析Session 易用性
Session.text()— 一行取回本次运行的最终回答:从末尾回溯,返回最近一条带文本的 assistant 消息,跳过纯 tool-call 轮次,无文本时返回None。此前调用方需手动遍历 transcript;example/11_dynamic_selector.py也因调用了这个不存在的方法而崩溃,现已修复。ChunkTable序列协议 — 新增__len__/__getitem__(含切片)/__iter__,ChunkTable现可直接len()、索引、切片与迭代;Session.__repr__也带上了短 session id,便于日志区分。
修复
- 文件系统同路径竞态 — 内置文件工具统一到单一
("fs", path)资源键;同一路径的读/写/list 现按 transcript 顺序串行,不同路径仍并行,消除读到写一半中间态的问题。 - 压缩截断静默丢历史 —
run_session_compress在finish_reason="length"(摘要被输出上限截断)时明确报错并提示加大输出预算,而非把残缺摘要当作权威替换。 - 懒开沙箱重复打开 —
_ensure_sandbox改用双检锁,避免两个首用调用各开一个沙箱、第二个赋值挤掉第一个而留下永不释放的孤儿句柄。 - Session 注册表内存增长 —
SessionRegistry改用WeakValueDictionary,无外部引用的 session 可被回收,长跑进程不再无界增长。 - 持久化空集合 round-trip —
spec_from_jsonable用is not None(而非真值判断)重建entrypoint/env,空()/{}现能在 persist/reload 后存活,与序列化端对齐。
其他改进
- 文档 — README_zh 全面对齐英文版结构(logo、arXiv badge、示意图、PyTorch 对照表、示例阶梯表);英文 README 补充 arXiv badge。
- CI / 打包 — 找回 v1.2.0 准备阶段误删的 opensandbox
--reruns,抵御 server 偶发的 stdout/exit_code 捕获竞态;延长 opensandbox code-run 测试超时以适配冷启动;sdist 收敛到源码必需文件。 - CI — Lint、Test Fast、Build、OpenSandbox 全部通过。
安装
pip install --upgrade openrath
# 可选:多供应商接入(Gemini/Bedrock/Azure/Ollama/Groq…)
pip install --upgrade "openrath[litellm]"
# 可选 memory backend
pip install --upgrade "openrath[openviking]"
# 可选 sandbox backend
pip install --upgrade "openrath[opensandbox]"兼容性
- 完全向后兼容:
provider_kind未设置时仍默认openai,litellm为纯新增;所有新符号(Session.text()、ChunkTable序列方法)均为增量,不影响既有调用点。 litellm为可选依赖,未安装时懒加载静默回退,对现有环境无影响。- 支持 Python 3.10 – 3.13。
完整变更: v1.2.1...v1.2.2
OpenRath v1.2.2
Following v1.2.1's dynamic workflows, v1.2.2 focuses on provider reach and runtime robustness. The headline feature is the litellm provider: a thin adapter that connects OpenRath to 100+ model providers (Gemini, Bedrock, Azure, Ollama, Groq, …) without hand-wiring a client outside the built-in Provider / chat_client_for dispatch. Around it, this release rounds out Session's common accessors and sequence protocol, and lands a batch of fixes for concurrency races, unbounded memory growth, and a lossy persistence round-trip. No breaking changes; upgrade straight from v1.2.1.
Major Features
LiteLLM provider (one adapter, 100+ models)
A new provider_kind="litellm" routes through LiteLLM to hundreds of providers. RathLiteLLMChatClient reuses OpenRath's existing OpenAI normalization and kwargs-building helpers (LiteLLM returns OpenAI-compatible responses), so the adapter stays thin and introduces no change to existing provider dispatch and no new runtime dependency:
RathLiteLLMChatClient— implementscomplete()andcomplete_stream(), auto-registered viaregister_chat_client("litellm", ...)and dispatched bychat_client_for()whenprovider_kind="litellm".- Optional dep, zero impact —
pip install "openrath[litellm]"; a lazy import falls back cleanly when it isn't installed, andprovider_kindstill defaults toopenaiwhen unset. - Credential resolution order —
Provider.api_key/Provider.base_urlfirst, then theLITELLM_API_KEY/LITELLM_API_BASEenv vars, then LiteLLM's own provider-specific resolution. drop_params=True(default) — provider-unsupported kwargs are silently dropped instead of raising on parameter mismatches.- Retries — reuses OpenRath's
retry_with_backoffforRateLimitError/Timeout/APIConnectionError/ServiceUnavailableError/InternalServerError.
Quick start:
from rath.llm import Provider, chat_client_for
provider = Provider(
provider_kind="litellm",
model="gemini/gemini-2.0-flash", # or anthropic/…, bedrock/…, ollama/…, etc.
api_key="sk-...", # or leave unset and let LiteLLM read the env var
)
client = chat_client_for(provider)
resp = client.complete(req)Or via config:
llm:
provider_kind: litellm
model: anthropic/claude-sonnet-4-20250514
# api_key resolved by LiteLLM from the provider-specific env varSession ergonomics
Session.text()— a one-call accessor for the run's final answer: walks the transcript from the end and returns the most recent assistant message carrying text, skipping pure tool-call turns, orNonewhen there is none yet. Callers previously had to walk the transcript by hand;example/11_dynamic_selector.pyalso crashed because it called this then-missing method, and now runs.ChunkTablesequence protocol — new__len__/__getitem__(with slicing) /__iter__, so aChunkTablesupportslen(), indexing, slicing, and iteration directly;Session.__repr__now carries a short session id for easier log disambiguation.
Fixes
- Same-path filesystem race — the built-in file tools collapse onto a single
("fs", path)resource key; reads/writes/lists on the same path now run in transcript order while distinct paths still fan out in parallel, removing the read-during-write intermediate-state bug. - Truncated compression summaries —
run_session_compressraises a clear error onfinish_reason="length"(a summary cut off by the output limit) telling the caller to retry with a larger output budget, instead of promoting a truncated summary as the canonical replacement. - Lazy sandbox double-open —
_ensure_sandboxnow uses double-checked locking, preventing two first-use calls from each opening a sandbox and orphaning the first acquired handle. - Session registry memory growth —
SessionRegistryis backed by aWeakValueDictionary, so an unreferenced session is collected and a long-running process no longer grows without bound. - Empty-collection persistence round-trip —
spec_from_jsonablerebuildsentrypoint/envwithis not None(not truthiness), so empty()/{}survive a persist/reload cycle, mirroring the serializer.
Other Improvements
- Docs — README_zh is fully aligned with the English structure (logo, arXiv badge, diagrams, PyTorch mapping table, example ladder); the English README gains an arXiv badge.
- CI / packaging — restored the opensandbox
--rerunsaccidentally dropped during v1.2.0 prep, riding out the server's occasional stdout/exit_code capture race; extended the opensandbox code-run test timeout for cold starts; trimmed the sdist to source essentials. - CI — Lint, Test Fast, Build, and OpenSandbox all pass.
Install
pip install --upgrade openrath
# optional: multi-provider reach (Gemini/Bedrock/Azure/Ollama/Groq…)
pip install --upgrade "openrath[litellm]"
# optional memory backend
pip install --upgrade "openrath[openviking]"
# optional sandbox backend
pip install --upgrade "openrath[opensandbox]"Compatibility
- Fully backward compatible:
provider_kindstill defaults toopenaiwhen unset,litellmis purely additive, and all new symbols (Session.text(), theChunkTablesequence methods) are additive and leave existing call sites unaffected. litellmis an optional dependency; when it isn't installed, a lazy import falls back silently with no impact on existing environments.- Python 3.10 – 3.13 supported.
Full changelog: v1.2.1...v1.2.2