Skip to content

v1.2.2

Choose a tag to compare

@Tokisakix Tokisakix released this 04 Jul 20:09
· 43 commits to main since this release

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_compressfinish_reason="length"(摘要被输出上限截断)时明确报错并提示加大输出预算,而非把残缺摘要当作权威替换。
  • 懒开沙箱重复打开_ensure_sandbox 改用双检锁,避免两个首用调用各开一个沙箱、第二个赋值挤掉第一个而留下永不释放的孤儿句柄。
  • Session 注册表内存增长SessionRegistry 改用 WeakValueDictionary,无外部引用的 session 可被回收,长跑进程不再无界增长。
  • 持久化空集合 round-tripspec_from_jsonableis 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 未设置时仍默认 openailitellm 为纯新增;所有新符号(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 — implements complete() and complete_stream(), auto-registered via register_chat_client("litellm", ...) and dispatched by chat_client_for() when provider_kind="litellm".
  • Optional dep, zero impactpip install "openrath[litellm]"; a lazy import falls back cleanly when it isn't installed, and provider_kind still defaults to openai when unset.
  • Credential resolution orderProvider.api_key / Provider.base_url first, then the LITELLM_API_KEY / LITELLM_API_BASE env 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_backoff for RateLimitError / 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 var

Session 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, or None when there is none yet. Callers previously had to walk the transcript by hand; example/11_dynamic_selector.py also crashed because it called this then-missing method, and now runs.
  • ChunkTable sequence protocol — new __len__ / __getitem__ (with slicing) / __iter__, so a ChunkTable supports len(), 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 summariesrun_session_compress raises a clear error on finish_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_sandbox now uses double-checked locking, preventing two first-use calls from each opening a sandbox and orphaning the first acquired handle.
  • Session registry memory growthSessionRegistry is backed by a WeakValueDictionary, so an unreferenced session is collected and a long-running process no longer grows without bound.
  • Empty-collection persistence round-tripspec_from_jsonable rebuilds entrypoint / env with is 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 --reruns accidentally 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_kind still defaults to openai when unset, litellm is purely additive, and all new symbols (Session.text(), the ChunkTable sequence methods) are additive and leave existing call sites unaffected.
  • litellm is 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