更新日志¶
LLM-Rosetta 的所有重要变更均记录于此。本项目遵循 Keep a Changelog 规范。
v0.6.7 — 2026-06-04¶
修复¶
- Embedding 端点 upstream_model 别名:
/v1/embeddings透传处理器现在在转发前将upstream_model名称替换到请求体中,与 chat completions 代理处理器行为一致。此前模型别名(如bge-m3→BAAI/bge-m3)被忽略,导致上游返回模型不存在错误。 - 管理面板测试计时器泄漏:已用时计数器现在全局追踪,启动新测试时清除旧计时器,避免多个计时器交替写入同一显示元素。
- 管理面板测试超时自动取消:浏览器侧 120 秒超时触发时,现在通过 API 显式取消服务端任务,而非任其继续运行。
- 服务端测试任务超时:在
_run_test_task中添加asyncio.wait_for()设置 120 秒超时,确保挂起的上游调用在服务端被终止,而非等待 300 秒清理窗口。
v0.6.6 — 2026-06-03¶
新增¶
- 管理面板状态栏请求总数:页脚首段显示生命周期请求计数器,支持千位分隔符本地化格式;每个段落悬浮提示(中/英)说明各指标含义
- 内嵌 httpclient URL 编码表单数据:
httpclientv0.4.2 —— 当data为字典且无文件时,自动编码为application/x-www-form-urlencoded
变更¶
- Schema 清理模块拆分:JSON Schema 清理逻辑从
converters/base/tools.py拆分到独立的converters/base/schema.py模块,职责更清晰 - 圈复杂度降低:降低工具操作(跨转换器复用
extract_part_ids/log_orphan_warnings)、网关认证(check_admin_auth)、流式代理(process_stream_chunk)、配置解析、日志和管理路由的认知复杂度 - complexipy 阈值:
max-complexity-allowed从 15 提升至 25;添加complexipy-pre-commit钩子定义(已注释)以备后续启用
修复¶
- 管理面板页脚国际化:状态栏页脚切换语言时立即重新渲染,无需刷新页面
- Docker 非语义化版本构建:
make build-docker V=dev-test不再失败——非语义化版本号的V值回退为从本地 wheel 安装
v0.6.5 — 2026-06-02¶
新增¶
- API 密钥标签过滤:请求日志标签页新增下拉过滤器,按 API 密钥名称筛选日志条目
- 客户端 IP 记录:从
X-Forwarded-For/X-Real-IP/ TCP 对端地址提取客户端 IP,在请求日志表格中新增"客户端 IP"列 - 系统时钟:管理面板顶栏显示实时更新的系统时间,便于与日志时间戳对照
- 双阈值日志保留策略:成功请求和错误请求独立裁剪;错误条目有独立的上限(
error_max),不会被大量成功流量挤出 - 数据库大小页脚:管理面板底栏显示磁盘数据库大小、各类条目数量和保留上限
修复¶
- 服务商过滤器:过滤器现在按服务商显示名称正确匹配条目,支持三级回退(
target_provider_name→target_provider→ API 类型,用于遗留的 NULL 行),覆盖回填缺失和已禁用服务商的场景 /health信息泄露:端点不再向未认证调用方暴露完整的服务商和模型列表,现仅返回{"status": "ok"}- i18n 完善:补充页脚统计、系统时间标签、过滤选项、客户端 IP 列标题的缺失中文翻译
变更¶
- Shim 目录结构:服务商 shim 现支持分组子目录(如
argo/anthropic/、argo/openai_chat/) - Schema 迁移:
_migrate_add_columns()改为通用实现,一次性添加所有缺失的可空列 - CI:切换至 pre-commit 进行代码检查,固定 ty 版本
v0.6.4 — 2026-05-20¶
新增¶
- Tinyleaf 风格设置弹窗:用轻量居中弹窗替换旧的模态对话框——点击遮罩或按 Escape 关闭,主题和语言使用下拉选择即时生效,底部 About 区域含版本号和项目链接(GitHub、PyPI、Docker Hub、Docs)
- 轻量 Host IP 检测端点:
GET /admin/api/diagnostics/host-ip仅读取/proc/net/route(微秒级,无网络调用);页面加载时自动更新代理 URL 占位符为正确的 Docker 宿主机 IP - 管理面板登录持久化:登录状态存储在
localStorage,30 分钟无操作自动登出,顶部退出按钮,密码管理器兼容(标准<form>、autocomplete属性) - 行内删除确认:模型、API 密钥和请求日志的两步确认替代原生
confirm()对话框 - 测试弹窗改进:取消按钮带计时器、图表空状态提示、克隆按钮
- 移动端响应式:Header 自动换行、Tab 和表格可水平滚动
修复¶
- Argo Anthropic 响应归一化:检测并转换 Argo
/v1/messages端点返回的 OpenAI Chat 格式响应为 Anthropic Messages 格式 - Argo Anthropic 模型感知 thinking:
_normalize_thinking区分需要adaptive(如claudeopus47)和需要转换为enabled的模型 - 行内确认 i18n 和 onclick 恢复:补充缺失的
confirm.sure/confirm.yes翻译;确认超时回退后恢复原始 onclick 处理函数 - 反向代理缓存:所有 admin API 响应添加
Cache-Control: no-cache, no-store, must-revalidate;测试轮询改用 POST - 登录遮罩循环:防止登录遮罩关闭密码管理器的自动填充弹窗
- C901 复杂度:从
fetch_upstream_models提取_format_connection_error辅助函数
安全¶
- 管理面板登录限流:5 次失败后触发 5 分钟 IP 锁定
变更¶
- 设置界面精简:主题缩减为浅色/深色;主题和语言选择器从 Header 下拉框移入设置弹窗
v0.6.3 — 2026-05-17¶
新增¶
- OpenAI Responses API
custom_tool_call全链路支持:端到端处理type: "custom"工具类型 —— 请求侧(降级为 IRtype: "function"并通过_passthrough保留原始负载以支持同提供商往返)、响应解析(custom_tool_call项使用纯文本input)、流式传输(response.custom_tool_call_input.delta/done事件)。跨提供商降级时自动合成单字符串参数的 JSON Schema,使 custom tool 在 Anthropic/Google 上仍可使用 - IR
ToolCallStartEvent新增tool_type字段:流式事件现在携带tool_type("function"、"custom" 等),以便转换器发出正确的提供商特定事件类型 - Argo shim 支持
model_id_field和upstream_model别名:新增argo_openai、argo_anthropic、argo_google提供商 shim,可重写 Argo 代理端点的模型字段名。包含argo_anthropic的 thinking 规范化转换 - 异步服务端测试任务:管理面板测试请求改为后台任务运行,避免慢模型导致浏览器连接池耗尽
- 管理面板登录限流:管理面板登录端点增加暴力破解防护
修复¶
- 管理面板存储型 XSS:修复
esc()辅助函数中单引号未转义的问题,防止通过提供商/模型名称注入 - Gateway 流式传输中
custom_tool_call类型丢失:OpenAIResponsesStreamContext.from_base()现在复制_tool_call_types,修复 IR→提供商流式路径中 custom tool 退化为function_call事件类型的问题 - 管理面板 UI 回归:修复获取模型复选框无限递归、允许在
credential_visible关闭时编辑 API Key、消除前缀实时预览输入延迟、修复获取模型前缀丢失选中状态、关闭模态框时中止测试请求 - Reasoning 测试
max_tokens过小:强制budget_tokens >= 1024以满足推理能力测试需求 - httpclient AsyncClient 序列化锁:更新内嵌 httpclient 至 v0.4.1,测试自调用使用独立 AsyncClient 避免死锁
- ty 类型检查错误:解决与 ty 0.0.32+ 的兼容性问题
变更¶
- 管理面板路由拆分为子包:将单体
routes.py重构为routes/子包,分为 auth、config、keys、observability、testing 等模块 - CI 切换至 pre-commit:代码检查现使用
pre-commit run --all-files(ruff + ty);complexipy 因上游问题暂时挂起
v0.6.2 — 2026-05-15¶
新增¶
- 管理面板密码保护:配置中的
server.admin_password启用管理面板登录覆盖层,使用 HMAC 会话令牌 - 凭证可见性控制:
server.credential_visible: false在管理面板中隐藏 API Key 的查看/复制功能 - 提供商级联删除:删除提供商时展示受影响的模型并级联删除
修复¶
- Base URL 被覆盖:切换提供商类型不再覆盖用户已输入的 base URL
- 请求日志折叠:展开的错误详情行在自动刷新后保持展开状态
变更¶
- Python ≥3.11 零依赖:用内嵌的 zerodep yaml 模块替换 PyYAML
v0.6.1 — 2026-05-15¶
新增¶
/v1/embeddings透传端点:将 embedding 请求直接代理到上游提供商,无需 IR 转换 —— OpenAI embeddings 格式在兼容提供商间通用。包含指标和请求日志记录/v1/models增强响应:模型列表现在包含api_standard(如"openai_chat"、"anthropic")和每模型capabilities字段- 管理面板"从提供商获取"功能:在模型标签页中查询上游
/v1/models(或等效端点),浏览可用模型并通过复选框批量添加,支持可选前缀。已存在的模型显示为禁用状态 - 模型管理增强:模型标签页新增提供商过滤下拉框和模型名称搜索
- Embedding 能力和测试类型:模型编辑器中新增
embedding能力(与vision/tools互斥)。Embedding 模型获得单独的 Test 按钮,POST 到/v1/embeddings并显示维度数量 - Reasoning 能力和测试类型:新增
reasoning能力,配有专用测试(发送reasoning_effort: "low")。与embedding互斥 - 管理面板标签页持久化:活动标签页存储在
localStorage中,页面刷新后保持不变
修复¶
- SOCKS5 代理测试中缺失事件循环:当之前的测试关闭了默认事件循环时,使用
asyncio.new_event_loop()作为后备 - fetch_upstream_models 中的 httpclient 响应类型断言:解决
AsyncClient.get()返回类型的 ty 类型检查错误
v0.6.0 — 2026-05-15¶
新增¶
- 声明式 YAML 提供商 Shim 目录:Shim 现在以
provider.yaml+ 可选transforms.py文件定义在shims/providers/<name>/下,导入时自动发现并注册 - 提供商字段转换机制:三个可组合的原语 ——
strip_fields()、rename_field()、set_defaults()—— 处理提供商 API 方言与其基础标准之间的字段级差异 - 7 个新内置提供商 shim:xAI (Grok)、Qwen(通义千问/DashScope)、Moonshot(月之暗面/Kimi)、MiniMax、Zhipu(智谱 GLM)、OpenRouter、火山引擎 —— 各自附带提供商特定的转换规则
- 网关代理应用 Shim 转换规则:网关请求/响应管线现在对出站请求应用
to_transforms,对入站响应和流式 chunk 应用from_transforms - 管理面板显示提供商 Logo:提供商 shim 可声明
logoURL(SVG),在管理面板提供商卡片中显示 - 恢复 SOCKS5 代理支持:将内嵌的
httpclient从 zerodep v0.3.1 更新至 v0.4.0,包含完整的 SOCKS5 代理支持(RFC 1928/1929,支持用户名/密码认证)。--proxy socks5://...CLI 参数和配置文件中的"proxy": "socks5://..."现可用于所有上游请求
变更¶
- Shim 系统重构为声明式 YAML:将编程式
builtins.py替换为基于目录的系统(shims/providers/*/provider.yaml+transforms.py)。添加新提供商现在只需 YAML + 可选 Python,无需修改核心代码 - 内嵌
validate更新至 zerodep v0.5.0:新增FieldValidator和model_validator,支持字段级别的转换+校验管道
移除¶
ModelShim类已移除:模型级元数据已移除,改为更简洁的仅提供商级 shim。ProviderShim数据类不再包含models字段
重构¶
- 零依赖网关(#178):将 Starlette + uvicorn + httpx 替换为内嵌的 zerodep
httpserver和httpclient模块。[gateway]extra 现在无外部运行时依赖
修复¶
- Schema 扁平化中的深度合并(#161):修复
$ref/$defs解析以深度合并属性并剥离孤立的required条目 - 无条件 usage 回退与 StreamContext 合并(#176):防止缺失 usage 数据时的异常,确保 StreamContext 状态正确合并
已知问题¶
- Google 工具 schema
required验证失败(#161):部分 Anthropic 工具 schema 的required条目引用了未定义的属性,导致 Google API 以INVALID_ARGUMENT拒绝请求
v0.5.3 — 2026-04-25¶
新增¶
- OpenAI Chat 转换器:thinking 配置支持(#170):OpenAI Chat 转换器现在处理 IR 请求中的
reasoning_config,映射到 OpenAI 的reasoning_effort参数。支持通过 Chat Completions API 路由时配置 thinking/扩展思考参数 - OpenAI Chat 转换器:
reasoning_content字段处理:推理模型(如 o1、o3)的非流式和流式响应现在正确提取reasoning_content字段并转换为 IRReasoningPart,在跨提供商转换中保留思维链内容 - 管理面板请求日志显示上游错误体:当上游提供商返回错误时,响应体现在包含在管理面板的请求日志条目中,无需查看服务器日志即可诊断上游故障
- 管理面板提供商和模型复制按钮:管理面板中的提供商和模型条目新增复制/克隆按钮,支持基于现有配置快速创建新条目
修复¶
UserContentPart缺少FilePart(#160、#162):UserContentPart联合类型未包含FilePart,导致validate_ir_request()拒绝所有包含文件内容的用户消息(如 Claude Code 以 Anthropicdocument块发送的 PDF 附件)。Anthropic(document)、Google(inlineData)和 OpenAI Responses(input_file)的双向转换逻辑已完整实现,仅类型定义缺失google_genai/content_ops.py无条件导入httpx(#163):将 Google GenAI 内容转换器中图片 URL 下载使用的httpx替换为urllib.request。httpx仅声明为[gateway]可选依赖,但被无条件导入,导致未安装[gateway]extra 时报ModuleNotFoundError- API Key 管理中 emoji 图标替换为 SVG:管理面板中 API Key 操作按钮使用的 emoji 字符在不同平台渲染不一致。替换为内联 SVG 图标,并新增 Key 可见性切换按钮
- API Key 列布局偏移:修复 CSS 布局问题,切换 Key 可见性时列宽变化导致相邻按钮位置偏移
- Wheel 路径与 extras 括号的 glob 冲突:CI 安装命令中对 wheel 文件路径加引号,防止文件名包含
[extras]括号语法时被 shell glob 展开
重构¶
- SQLite 持久化后端:将基于 JSONL 的请求日志和基于 JSON 的指标持久化替换为统一的 SQLite 后端。提供更好的写入可靠性、原子操作,并消除日志轮转复杂性。内嵌 zerodep 的
persistdict(v0.4.1)作为键值存储层
CI/构建¶
- 安装冒烟测试:新增 CI 冒烟测试,验证
pip install在llm-rosetta(核心)和llm-rosetta[gateway]两种变体下均能成功安装,及早发现缺失或循环依赖
v0.5.2 — 2026-04-19¶
修复¶
- 流式往返事件膨胀(#157):修复了多种
Provider A → IR → Provider B流式转换中输出事件多于输入事件的场景:- OpenAI Chat、Anthropic 和 Google GenAI 转换器在没有打开内容块时发出多余的
content_block_end事件,导致输出流膨胀 - Google GenAI 复合 chunk(同一 SSE 帧中包含 text + finish)触发重复的文本和结束事件。通过
StreamContext.pending_text/pending_finish延迟合并为单个事件 - 工具调用事件在非 Anthropic 目标中生成多余的
content_block_start/content_block_end包装。通过_started生命周期守卫抑制
- OpenAI Chat、Anthropic 和 Google GenAI 转换器在没有打开内容块时发出多余的
重构¶
- 统一
stream_response_to_provider分派(#157):将 4 个 provider converter 中完全相同的分派逻辑(10 项_TO_P_DISPATCH表 + 分派骨架)提取到BaseConverter。每个 converter 只需实现特定于 provider 的_post_process_to_provider钩子(OpenAI Chat 注入 envelope 字段;OpenAI Responses 注入sequence_number)。净减少约 27 行 StreamContext缓冲便捷方法:新增buffer_usage()/pop_pending_usage()/buffer_finish()/pop_pending_finish(),替换 4 个 converter 中手动 set-and-clear 模式
变更¶
- 固定开发工具版本:
ty>=0.0.31和ruff>=0.15.0现在声明在pyproject.toml的 dev 依赖中。CI 不再单独安装,使用pip install -e ".[all]"中的版本 - Converter 测试加入 CI:
tests/converters/(1086+ 测试)现在与tests/test_types/一起在 GitHub Actions 中运行 - 往返膨胀回归测试:新增 pytest 参数化测试套件(
tests/converters/test_roundtrip_inflation.py,15 个用例),验证所有 4 个 provider 在文本、推理、工具调用和复合场景下len(output_events) <= len(input_events)
v0.5.1 — 2026-04-15¶
新增¶
tool_ops便利 API(#148):新增顶层llm_rosetta.tool_ops模块,无需实例化完整转换器即可独立进行工具定义转换。提供to_provider()/from_provider()统一分派及各提供商快捷函数(to_openai_chat()、to_anthropic()等)。所有导入均为延迟加载- 多 Key API 管理:管理面板支持每个网关多个 API Key,支持按 Key 标签标注、创建/查看/删除操作,以及请求日志中的使用追踪
- 网关 API Key 认证:可配置的 API Key(
server.api_key)保护 AI 请求端点(/v1/*)。支持各格式原生凭证提取——OpenAIAuthorization: Bearer、Anthropicx-api-key、Googlex-goog-api-key/?key=查询参数。未配置 Key 时所有请求直通(向后兼容) - 提供商启用/禁用:每个提供商现在支持
enabled字段(默认true)。禁用的提供商及其模型从路由中静默排除 - Docker 支持:官方
Dockerfile、docker-compose.yml和 Makefile 目标(build-docker、push-docker、run-docker),支持容器化部署。基于 Alpine 的镜像,非 root 用户,配置卷挂载,PUID/PGID 支持 - 管理面板增强:
- 提供商开关切换(启用/禁用,无需删除)
- 模型搜索和列排序
- 提供商重命名,自动更新模型引用
- 网络诊断按钮(连通性检查 + 代理测试)
- 模型测试支持可折叠的原始请求/响应详情及视觉测试的图片预览
- 内嵌测试图片(base64 Data URI),避免外部网络下载
- 推理模型测试使用
reasoning_effort: 'low'限制 token 预算
变更¶
- 移除管理面板的网关级认证:管理面板端点(
/admin/*)不再需要网关 API Key。管理访问控制委托给反向代理(如 Caddy、Nginx)。网关 API Key 仅认证 AI 请求端点(/v1/*) - C901 圈复杂度阈值降至 15:逐步从 25 → 20 → 15 降低所有转换器和网关模块的复杂度。提取跨提供商一致性辅助方法(
_build_ir_usage、_build_provider_usage、_convert_tools_from_p、_apply_tool_config),4 个转换器使用统一命名 BaseConverter抽象方法:新增 4 个抽象方法,规范化跨提供商辅助方法模式。preserve 模式钩子作为约定文档化,供支持无损往返的提供商使用- vendored
validate.py更新至 zerodep v0.4.2:内部重构,将单体_validate()拆分为专用辅助函数;无功能变化
修复¶
- 图片 URL 下载添加 User-Agent:Google GenAI 内容转换器下载图片 URL 进行 base64 内联转换时,现在发送
User-Agent: llm-rosetta/1.0 (image fetch),防止 Wikimedia 等服务器返回 403 Forbidden - 图片下载代理支持:Google GenAI 转换器的图片下载现在遵循
HTTPS_PROXY/HTTP_PROXY环境变量 - 推理模型空内容回退:管理面板测试结果现在正确处理
content: ""(推理模型将所有max_tokens消耗在推理 token 上时),而非显示原始 JSON - 配置文件未找到错误:网关在配置文件不存在时显示友好的错误信息,而非 Python 堆栈跟踪
- ty 类型检查兼容性:为 TypedDict 与
dict[str, Any]不匹配及FinishReasonLiteral 类型窄化添加ty: ignore注解 - Google 转换器在 thinking 耗尽所有 token 时崩溃(#152):Gemini 2.5 Pro 在
max_tokens较小时,thinking 可能消耗全部 token,产生无内容部分的响应。转换器现在回退到空 assistant 消息,而非 IR 验证失败
v0.5.0 — 2026-04-12¶
新增¶
- 网关管理面板:在
/admin/提供内置 Web 管理面板,支持管理网关配置、监控流量和查看请求日志,无需编辑配置文件或重启服务器- Configuration 标签页:可视化管理提供商(添加、编辑、重命名、删除)和模型路由,支持能力标记(text/vision/tools)
- Dashboard 标签页:实时指标摘要卡片(总请求数、错误率、活跃流式连接、运行时间),滚动 60 秒吞吐量和延迟图表,按提供商分类统计
- Request Log 标签页:可过滤的请求日志,支持按模型、提供商、状态筛选,分页显示,状态码颜色标记
- 8 种主题:Light、Indigo Dark、Dracula、Nord、Solarized、Osaka Jade、One Dark、Rosé Pine — 保存在 localStorage 中
- 国际化:支持 English 和中文切换,选择保存在 localStorage 中
- 文件持久化:指标计数器(JSON)和请求日志(JSONL)自动保存到配置文件旁的磁盘目录中,数据在服务器重启后恢复。日志轮转支持 gzip 压缩(2 MB 限制,最多 3 个备份)
- 提供商重命名:重命名提供商时自动更新所有模型路由引用
- API Key 安全:提供商卡片显示脱敏 Key,编辑弹窗中支持可见性切换和复制按钮。脱敏值不会被写回配置文件
变更¶
- 提供商名称与 API 标准类型解耦:提供商名称现在是用户自定义字符串(如
"my-openai"、"OpenRouter_anthropic"),不再受限于 4 种标准类型标识符。独立的type字段指定 API 标准(openai_chat、openai_responses、anthropic、google) - 将
write_config()提取到config.py,供 CLI 和管理面板共用
v0.4.2 — 2026-04-11¶
变更¶
ReasoningConfig.enabled替换为mode字段:布尔值enabled字段已被mode: Literal["auto", "enabled", "disabled"]替换。这使 IR 更贴近提供商语义(Anthropic 的三态thinking.type、OpenAI Responses 的reasoning.type)。省略mode保留原有的"提供商默认"行为。effort字段现在直接位于ReasoningConfig中,而非嵌套
修复¶
- Responses API
developer角色映射:OpenAI Responses API 使用role: "developer"(等同于 Chat 的"system")。此前该角色在 Provider→IR 转换中原样传递,导致验证失败。现已正确映射为 IR"system" - Google GenAI
additionalProperties拒绝:Google 的 function_declarations API 拒绝 JSON Schema 中的additionalProperties关键字。为sanitize_schema()新增extra_strip_keys参数,允许提供商剥离特定不支持的关键字。Google tool_ops 现递归剥离嵌套 schema 中的additionalProperties - Google GenAI
prompt_tokens_details格式不匹配:Google 以list[ModalityTokenCount]格式返回 modality token 详情(如[{"modality": "TEXT", "token_count": 42}]),但 IR 期望dict[str, int](如{"text_tokens": 42})。新增双向转换辅助函数_modality_list_to_dict()和_dict_to_modality_list(),同时支持 SDK(token_count)和 REST API(tokenCount)字段名 - 跨格式 tool call ID 前缀映射:Responses API 强制要求 tool call ID 以
fc_前缀,但 Chat 使用call_,Anthropic 使用toolu_。在 Responses 转换中新增自动前缀映射,防止跨格式场景下的验证失败 - 自适应思考回退:将 IR 推理配置转换为 Anthropic 格式时,
mode: "enabled"但缺少budget_tokens现在正确回退为{"type": "adaptive"}并发出警告,而非产生无效的不含必需budget_tokens的{"type": "enabled"}
v0.4.1 — 2026-04-10¶
新增¶
convert()新增force_conversion参数:新增force_conversion: bool = False仅关键字参数。设为True时,即使源和目标提供商相同,也会执行完整的 source→IR→target 转换管线,确保参数规范化(例如 OpenAI Chat 的max_tokens→max_completion_tokens)。默认False保留现有的直通行为
修复¶
- 内嵌
validate.py更新至 zerodep v0.4.1:应用 pyupgrade 修复 —Callable从collections.abc而非typing导入(UP035),@functools.cache替换@functools.lru_cache(maxsize=None)(UP033) - 移除 benchmark 脚本中未使用的
sys导入 - 对 benchmark 脚本执行
ruff format格式化
变更¶
- 移除 README 中不准确的"相关项目"段落 — LLM-Rosetta 是独立项目,不属于 ToolRegistry 生态系统
v0.4.0 — 2026-04-09¶
新增¶
- 元数据保留:实现无损 A→IR→A 往返转换 (#60, PR #119):
ConversionContext新增MetadataMode("strip"/"preserve")选项,在from_provider阶段捕获提供商特有字段,在to_provider阶段重新注入,实现无损往返转换。ConversionContext新增辅助方法:store_request_echo()、store_response_extras()、store_output_items_meta()、get_echo_fields()、get_output_items_meta()。各提供商覆盖范围:- OpenAI Responses:捕获/恢复 28+ 回显字段(temperature、tools、reasoning、truncation 等)、逐输出项元数据(id、status、annotations、logprobs),
RESPONSES_REQUIRED_DEFAULTS字典提供规范要求字段的合理默认值,所有 SSE 事件包含sequence_number - Anthropic:保留
stop_sequence、container、citations 及 OpenRouter 扩展 usage 字段 - OpenAI Chat:
response_to_provider现在重新输出refusal和annotations字段(此前被丢弃) - Google GenAI:保留 usage 元数据中的
promptTokensDetails和cachedContentTokenCount - 网关:流式和非流式路径自动启用 preserve 模式;流式传输中在
from_ctx和to_ctx之间桥接元数据
- OpenAI Responses:捕获/恢复 28+ 回显字段(temperature、tools、reasoning、truncation 等)、逐输出项元数据(id、status、annotations、logprobs),
修复¶
- Open Responses 规范合规性(流式与非流式):所有 SSE 事件添加必需字段(
item_id、logprobs、annotations、status、sequence_number、output_index、content_index),添加 usage 详细分解(output_tokens_details、input_tokens_details),非流式输出项生成消息 item ID 和 status,tool_ops 添加function_callstatus 字段,service_tier默认值改为"default"(字符串而非 null,符合规范),required defaults 中添加completed_at,未提供时created_at回退到当前时间,规范化回显工具的strict: null,网关流式传输中从from_ctx到to_ctx桥接元数据。全部 6 个 Open Responses 合规性测试通过(schema + 语义)
v0.3.1 — 2026-04-07¶
修复¶
service_tier: None和system_fingerprint: None导致验证错误 (PR #118):OpenAI 上游返回这些字段为null,但存在性检查(if "key" in dict)通过后将None赋值给 IR 的NotRequired[str]字段。在 OpenAI Chat 和 OpenAI Responses 两个转换器中改为值非空检查。发现于 Oaklight/argo-proxy#99 测试过程中- 基类
StreamContext在 Responses 流式传输中缺少提供商特定属性 (PR #118):当网关传入基类StreamContext给OpenAIResponsesConverter.stream_response_to_provider()时,方法访问的accumulated_text、output_item_emitted等字段仅存在于OpenAIResponsesStreamContext子类。新增from_base()类方法自动升级,并通过 metadata 缓存保持跨调用状态
v0.3.0 — 2026-04-07¶
新增¶
- 全部 4 个转换器支持多模态工具结果 (#92, PR #109):工具现在可以返回多模态内容(文本 + 图片 + 文件)作为
ToolResultPart.result。三个提供商(Anthropic、OpenAI Responses、Google GenAI)原生支持;内容块通过每个提供商的content_ops层转换。详见下方提供商支持矩阵 - OpenAI Chat 多模态工具结果无损往返 (#92, PR #108):OpenAI Chat Completions 的工具消息仅接受
content: string。实现双重编码策略——工具消息保留json.dumps(result)作为数据兜底,同时合成用户消息携带可视内容(image_url部分)包裹在<tool-content call-id="...">XML 标签中。解包时优先从合成消息恢复多模态结构,若合成消息被智能体框架裁剪则回退到 JSON 解析 extract_all_text()辅助函数 (PR #109):从TextPart和ReasoningPart内容中提取文本——适用于思考模型(如 gemini-2.5-flash),这类模型可能将答案放在 reasoning 部分而非 text 部分generate_chart示例工具 (PR #109):examples/tools.py中新增多模态工具,返回[TextPart, ImagePart](含内联 base64 PNG),以及multimodal_tools_spec组合全部 3 个示例工具- 全部 4 个提供商 SDK 的多模态集成测试 (PR #109):每个提供商新增两个测试场景——(A) 工具返回多模态内容(文本 + 图片),(B) 图片输入结合工具调用。全部 30 个测试通过官方 API 验证:OpenAI Chat 9/9、OpenAI Responses 6/6、Anthropic 8/8、Google GenAI 7/7
- 运行时 IR 验证(零依赖内嵌验证器) (#91):
validate_ir_request()、validate_ir_response()和validate_ir_messages()工具函数,在运行时对 IR 结构进行 TypedDict 定义验证。4 个转换器的request_from_provider()和response_from_provider()现自动验证输出。替代手动BaseMessageOps.validate_messages实现。包含 Python <3.11 的typing_extensions.TypedDict兼容修复 - 常量验证测试:4 个
test_constants.py文件中新增 39 个测试,验证所有 reason 映射值均为合法 IR finish reason、映射覆盖完整、事件类型常量格式正确、ID 生成产出正确格式 - Finish reason 映射测试覆盖:38 个测试验证 reason 映射正确性,为常量重构提供安全网
- 转换管线
ConversionContext基类 (#106, PR #111):新增ConversionContext数据类,包含warnings: list[str]、options: dict[str, Any]和metadata: dict[str, Any]——为非流式转换提供结构化上下文容器。新增BaseConverter.create_conversion_context(**options)工厂方法,与已有的create_stream_context()对称。全部 6 个BaseConverter非流式方法现在接受可选的context: ConversionContext关键字参数;各转换器实现将警告同步到context.warnings。网关代理为每个请求创建共享 context 并沿完整的 source→IR→target→response 管线传递
修复¶
- 工具转换失败时提供上下文错误信息 (#85, PR #110):当
p_tool_definition_to_ir()在处理格式错误或不支持的工具定义时失败,ValueError现在包含type=和name=上下文信息,帮助用户识别是哪个工具导致了问题。已应用于全部 4 个转换器(OpenAI Chat、OpenAI Responses、Anthropic、Google GenAI),附带单元测试 - OpenAI Responses
tool_choice格式 (PR #109):此前使用 Chat Completions 格式({"type": "function", "function": {"name": "..."}}),现在使用 Responses 格式({"type": "function", "name": "..."}) - OpenAI Responses 工具调用 ID 往返 (PR #109):Responses API 使用
fc_前缀 ID,IR 使用call_前缀。Responses 的id现在单独保存在provider_metadata中(与call_id分开),实现无损往返转换 - OpenAI Responses 推理项往返 (PR #109):推理模型(如 gpt-5-nano)发出带有
id(rs_ 前缀)、结构化summary数组和encrypted_content的推理项。这些信息现通过provider_metadata保留以实现无损往返——修复了推理项缺少原始id回传时导致的 400 错误 - IR 验证接受可选响应字段的
None值 (PR #109):IRResponse中的logprobs和system_fingerprint现在接受None值(此前仅接受缺失键) - OpenAI Responses
content_filterfinish reason 映射到错误状态 (#90):content_filter此前被错误映射到"completed"状态(response_to_provider和stream_response_to_provider)。现正确映射到"incomplete"状态,附带incomplete_details.reason = "content_filter" - Anthropic 流式传输缺少
refusalreason 映射:流式传输的reason_map缺少非流式路径中存在的refusal条目,导致 Anthropic refusal 停止原因在流式传输期间被静默丢弃。作为常量提取的副作用修复(#64)——两条路径现在共享同一个ANTHROPIC_REASON_FROM_PROVIDER字典
变更¶
ReasoningConfig.effort扩展为 5 级枚举 (#100):Effort 级别新增"minimal"、"low"、"medium"、"high"、"max"。提供商映射:Anthropic 映射到thinking.type="adaptive"配合thinking.effort;OpenAI Chat/Responses 将"minimal"钳位为"low"、"max"钳位为"high"(附带警告);Google GenAI 映射到thinking_config.thinking_levelReasoningConfig.type替换为ReasoningConfig.enabled(#70):type: Literal["enabled", "disabled"]字段替换为enabled: bool,避免遮蔽 Python 内建type,提供更自然的 API- 合并重复的 IR 概念 (#69):移除
GenerationConfig中的candidate_count——改用n(Google GenAI 转换器内部映射n↔candidate_count)。system_instruction类型从str | list[dict]统一为str - 规范化
ImagePart、FilePart、AudioPart为标准形式 (#68):每种 Part 现在恰好有两种标准形式——URL 引用 + 结构化内联数据(如image_data)——加上统一的provider_ref: dict[str, Any]用于提供商特定引用。移除冗余的顶层data/media_type字段,file_id/audio_id替换为provider_ref - IR 类型字段从
Iterable改为list;函数参数改为Sequence(#67):TypedDict 字段使用list以支持索引和序列化;函数参数使用Sequence(协变、只读)。同时修复strip_orphaned_tool_config中any()消耗单次迭代器的潜在 bug StreamContext继承自ConversionContext(#106, PR #111):StreamContext现为ConversionContext的子类(IS-A 关系),统一流式与非流式路径的上下文模型。文件重命名:base/stream_context.py→base/context.pyStreamContext转为 dataclass 并引入提供商子类 (#65):StreamContext现为@dataclass(消除防御性getattr/hasattr模式)。OpenAI Responses 特有状态提取至OpenAIResponsesStreamContext子类。新增BaseConverter.create_stream_context()工厂方法
重构¶
- Warnings 单源收敛 (#113, PR #115):4 个转换器的
request_to_provider方法现在统一使用ConversionContext作为警告的唯一积累点。消除了之前警告同时写入本地列表和context.warnings的双写模式。返回的 warnings 列表与context.warnings是同一个对象——不可能产生重复 ProviderMetadataStore替代全局 metadata 缓存 (#112, PR #117):proxy.py中的模块级_provider_metadata_cache字典替换为ProviderMetadataStore类——提供 TTL 过期(30 分钟)、最大容量淘汰(10k 条目)和显式生命周期管理。Store 在create_app()中按应用创建并通过app.state传递,消除隐式全局状态变更。close_clients()重命名为close_resources()以在关闭时同步清理 store- 缩减公共 API 导出面 (#114, PR #116):各转换器包的
__all__导出精简为仅包含主转换器类,移除内部实现细节(*MessageOps、*ContentOps、*ConfigOps、*ToolOps、*Constants)。内部模块仍可通过显式导入使用,但不再作为公共 API 面推广 - 将单体流式方法拆分为事件处理器 (#63):4 个转换器中 8 个单体
if/elif流式方法(约 1,781 行)替换为通过类级处理器表分发的独立处理器方法。公共 API 不变 - 提取 OpenAI Responses 转换器共享工具函数 (#66):
resolve_call_id()和build_message_preamble_events()从converter.py提取至utils.py,附带专用单元测试 - 提取各提供商常量用于 reason 映射及魔法值 (#64):4 个转换器中散布的内联 reason 映射字典、SSE 事件类型字符串字面量、status-to-reason 条件逻辑和 ID 生成模式,现已集中到各提供商的
_constants.py模块中。包含AnthropicEventType和ResponsesEventType常量类、REASON_FROM_PROVIDER/REASON_TO_PROVIDER字典,以及generate_tool_call_id()/generate_message_id()辅助函数
v0.2.6 — 2026-03-29¶
修复¶
- Responses API 转换后 Chat Completions tool 消息顺序错乱 (@caidao22):Codex CLI 在 Responses API 格式中会在
function_call_output与其他项目(如用户警告消息)之间交错排列——在 Responses API 中通过call_id匹配是合法的。但经 IR → Chat Completions 转换后,交错的消息打破了 OpenAI Chat API 约束(role: "tool"消息必须紧跟其assistanttool_calls),导致上游返回 400 错误。在OpenAIChatMessageOps.ir_messages_to_p()中新增_reorder_tool_messages()后处理步骤,将 tool 响应重新归组到对应的 assistant 消息之后 - 无工具定义时剥离孤立的
tool_choice/tool_config(@caidao22):Codex 上下文压缩可能移除所有工具定义但保留tool_choice(如"auto"),导致上游 API 拒绝请求("tool_choice is set but no tools are provided")。在四个转换器中新增strip_orphaned_tool_config()——属于 Codex 压缩修复家族:fix_orphaned_tool_calls_ir(孤立 tool_call/result 配对)、_reorder_tool_messages(tool 消息排序)。同时将fix_orphaned_tool_calls_ir扩展到 Google GenAI 转换器以保持完整性(#87) - 流式事件顺序修正:四个提供商转换器(OpenAI Chat、OpenAI Responses、Anthropic、Google GenAI)中
UsageEvent现在在FinishEvent之前发出。此前FinishEvent先处理,导致response.completed携带output_tokens=0——下游消费者(如 Codex token 追踪)看到的是过时的用量数据。对于跨 chunk 场景(OpenAI Chat 在不同 chunk 中发送finish_reason和usage),FinishEvent现在将response.completed延迟到StreamEndEvent中发出,后者会合并待处理的 usage 数据 - Anthropic/Google → Chat 流式传输中并行工具调用被合并:Anthropic 和 Google GenAI 的
stream_response_from_provider发出的ToolCallStartEvent和ToolCallDeltaEvent缺少tool_call_index。路由到 Chat Completions 时,所有并行工具调用默认索引为 0,导致客户端 SDK 将它们合并为一个调用。Anthropic 现在从context._tool_call_order位置派生tool_call_index;Google 从 context 中的注册顺序计算(#88, #89) - Responses
function_call输出缺少id字段:非流式response_to_provider在function_call输出项上缺少id字段。流式传输使用合成的fc_前缀,可能通过p_tool_call_to_ir回退路径泄漏到 IR。统一两条路径,直接使用call_id作为id(无前缀) - Responses 流式传输
item_id及空tool_call_id解析 (@caidao22):StreamContext新增item_id追踪(tool_call_item_id_map,双向映射)。Responsesstream_response_to_provider现在在output_item.added上发出item.id,在function_call_arguments.delta/done事件上发出item_id(非call_id)。纵深防御:通过 context 的tool_call_index解析空tool_call_id(#86) - 非 function 类型工具名被添加类型前缀 (@caidao22):非 function 的 IR 工具定义(如
type="custom"、name="apply_patch")转换时被添加了类型前缀(custom_apply_patch),导致工具调用匹配失败(客户端期望原始名称)。OpenAI Chat 和 Responses 转换器现在直接使用ir_tool["name"](#84)
v0.2.5 — 2026-03-23¶
修复¶
- Anthropic
input_schema无参数工具缺少type字段:无参数的 MCP 工具生成input_schema: {},但 Anthropic 要求必须包含"type"字段。现在当 schema 字典缺少type字段时默认为{"type": "object"}——修复了 Google GenAI 或 OpenAI Responses 工具调用路由到 Anthropic 上游时出现的tools.0.custom.input_schema.type: Field required错误 - Google GenAI 全栈 camelCase 字段处理:Gemini CLI 和 Google REST API 使用 camelCase(
inlineData、fileData、mimeType、fileUri、functionCall、functionResponse、finishReason、usageMetadata、responseMimeType、responseSchema、thinkingConfig、maxOutputTokens、stopSequences等),但转换器此前仅接受 snake_case。content_ops、config_ops、tool_ops、message_ops 和 converter 中所有 P→IR 方法现在同时接受两种命名;所有 IR→P 方法统一输出 camelCase 以兼容 REST API - Google→IR 转换丢失图片/音频/文件数据:
p_part_to_ir只检查inline_data(snake_case),但 Gemini CLI 发送inlineData(camelCase)——二进制内容被静默丢弃并输出不支持的Part类型警告。修复方式:在分发入口处规范化 camelCase 键名 - 跨格式图片转换失败(Google → OpenAI/Anthropic):Google 的
p_image_to_ir生成的ImagePart使用顶层data+media_type字段,但 OpenAI Chat、Anthropic 和 OpenAI Responses 的ir_image_to_p仅检查image_url和嵌套的image_data——导致ValueError。三个目标转换器现在都增加了对顶层字段的兜底处理(#68) - Google GenAI tool_call_id 对账:Google
functionCall没有 ID 字段,P→IR 时生成 UUID。但 Gemini CLI 为functionResponse分配自有 ID(格式:name_timestamp_index),造成不匹配。新增_reconcile_tool_call_ids方法,按函数名称匹配工具结果与工具调用,修复孤立 tool_call 错误 - tool_call_id 超出 OpenAI 40 字符限制:生成的 ID 使用
call_{name}_{8hex}格式——MCP 工具名如mcp_toolregistry-hub-server_datetime-now产生 54 字符 ID。缩短为call_{24hex}(固定 29 字符) - Google→IR 工具结果的 role 映射:
functionResponse部分生成role: "user"的 IR 消息,导致fix_orphaned_tool_calls_ir(检查role: "tool")无法检测。现在将functionResponse分离为role: "tool"消息,并在_IR_TO_GOOGLE_ROLE中添加显式"tool": "user"映射 - 混合内容消息排序:当 Google 消息同时包含
functionResponse和inlineData时,内容部分排在工具结果之前,打断了 OpenAI 要求的assistant(tool_calls) → tool(response)顺序。修复后工具结果排在内容部分之前 - Google 内建工具(googleSearch、codeExecution):
p_tool_definition_to_ir对没有name字段的工具条目返回None;converter 跳过这些条目,不再产生空function.name错误 - 网关:Starlette
on_shutdown弃用兼容:将已弃用的on_shutdown参数替换为lifespan异步上下文管理器——修复与 Starlette 0.38+(移除了on_shutdown/on_startup)的兼容性
新增¶
- StreamContext:
get_tool_call_args()和get_pending_tool_calls()方法,用于在流式处理期间查询已积累的工具调用状态
变更¶
BaseToolOps.p_tool_definition_to_ir返回类型:改为ToolDefinition | list[ToolDefinition] | None,支持不可转换的工具条目
新增(文档)¶
- 提供商与 CLI 兼容性矩阵:新增指南页面,记录通过格式转换代理实际集成测试 Gemini CLI、Claude Code 和 OpenCode 时发现的真实问题
v0.2.4 — 2026-03-22¶
新增¶
fix_orphaned_tool_calls()工具函数:converters/openai_chat/tool_ops.py、converters/openai_responses/tool_ops.py和converters/anthropic/tool_ops.py中的公开函数,双向检测和修复工具调用/结果的配对问题 — 为孤立的工具调用注入合成占位结果,同时移除没有匹配调用的孤立工具结果。OpenAI(Chat 和 Responses)及 Anthropic 严格要求此配对关系(否则返回 400 错误),仅 Google Gemini 对此宽松。在所有严格配对转换器的request_to_provider()中通过 IR 层级自动修复;检测到孤立工具调用或结果时输出WARNING级别日志(#82, #84)
修复¶
- Anthropic→IR
tool_result消息的 role 规范化:Anthropic 将tool_result块放在role: "user"消息中,但 IR 使用role: "tool"(与 OpenAI 一致)。Anthropic 转换器现在将纯tool_result的 user 消息规范化为role: "tool",并将混合tool_result+ text 的消息拆分为独立的role: "tool"和role: "user"IR 消息。修复了跨格式转换(如 Anthropic → OpenAI Chat)中fix_orphaned_tool_calls_ir()无法检测已回答工具调用的问题(#84) - OpenAI Responses→IR
function_call_output的 role 规范化:function_call_output和mcp_call_output项此前被归入role: "user"的 IR 消息,但 IR 对工具结果使用role: "tool"。Responses 转换器现在将这些项归入role: "tool"消息,修复了跨格式转换(如 Responses → OpenAI Chat)中fix_orphaned_tool_calls_ir()无法检测已回答工具调用的问题(#84)
新增(文档)¶
- 提供商方言差异指南:在转换器指南中新增章节(中英文),记录工具 schema 清理、孤立工具调用处理、Google camelCase/snake_case 差异
v0.2.3 — 2026-03-22¶
修复¶
- 所有转换器均执行工具 schema 清洗:此前
_sanitize_schema()仅在 OpenAI Chat 转换器中调用。Google GenAI、OpenAI Responses 和 Anthropic 转换器现在也在发送到上游前清洗工具参数 schema,防止 Vertex AI 等严格端点拒绝请求(#80) - 移除非标准
ref和$schema关键字:OpenCode 内置工具使用不带$前缀的裸ref字段和顶层$schema,均被 Vertex AI 拒绝。已添加到不支持关键字黑名单(#80) - 通过内联解析
$ref/$defs引用:JSON Schema$ref引用现在通过从$defs/definitions内联被引用的定义来解析,两个关键字均从输出中移除。支持嵌套和链式引用(#80) - 流式传输中工具调用参数未累积:OpenAI Chat、Anthropic 和 Google GenAI 转换器在
StreamContext中注册了工具调用,但在流式传输期间从未调用append_tool_call_args()累积参数增量。这导致工具调用参数到达上游时为空(如 MCP 工具返回'query' is a required property)。此前仅 OpenAI Responses 转换器正确处理(#81) - OpenAI Chat 流式工具调用 ID 解析:仅携带
index而无id的增量 chunk 产生了空字符串tool_call_id。现在通过 chunk 索引从StreamContext._tool_call_order解析有效 ID(#81)
变更¶
sanitize_schema提取至converters/base/tools.py:Schema 清洗工具函数(此前为openai_chat/tool_ops.py中的私有函数_sanitize_schema)现已提升为converters/base/tools.py中的公开共享函数,通过converters.base导出。所有 4 个转换器的tool_ops.py均从共享位置导入,消除了跨转换器的交叉导入依赖(#66)
v0.2.2 — 2026-03-22¶
修复¶
- Anthropic SSE 输出缺少
content_block_stop:将 OpenAI Chat 流式响应转换为 Anthropic SSE 格式时,content_block_stop事件未在message_delta之前发送,导致 Claude Code 静默丢弃响应内容。Anthropic 转换器现在在处理FinishEvent时为任何打开的内容块发送content_block_stop(#77) - 上游预检 chunk 被误判为流结束:Argo API 在实际内容之前发送一个
choices: []且id/model为空的预检 chunk。OpenAI Chat 转换器现在仅在流已实际启动后才将空 choices chunk 视为流结束(context.is_started守卫)(#77)
v0.2.1 — 2026-03-20¶
新增¶
- 网关请求/响应体日志:可配置的调试日志,支持彩色输出、请求体脱敏和截断 — 通过配置(
"debug": {"verbose": true, "log_bodies": true})、环境变量(LLM_ROSETTA_VERBOSE、LLM_ROSETTA_LOG_BODIES)或--verboseCLI 参数启用 - Google
request_to_provider()支持output_format="rest":传入output_format="rest"可直接获得 REST API 格式的请求体,tools/tool_config提升至顶层,生成参数包装在generationConfig中 — 无需再手动进行 SDK→REST 格式转换
变更¶
- 网关模块化重构:将
app.py(1057 行)拆分为proxy.py(代理引擎、SSE 处理、上游请求)、cli.py(CLI 入口、argparse、子命令)和精简后的app.py(路由处理、应用工厂,约 210 行) - Google REST 请求体转换迁移至核心包:
_fixup_google_body()逻辑从gateway/proxy.py迁移至GoogleGenAIConverter._to_rest_body(),消除了网关和全部 6 个 REST 示例中的重复 SDK→REST 转换代码
修复¶
- OpenAI Responses 流式传输:为
response.completed添加缺失的id/object/model字段,为文本增量事件添加output_index/content_index,并补充完整的生命周期事件(output_item.added、content_part.added、content_part.done、output_item.done)(#56) - OpenAI Chat 流式传输:
tool_calls条目现在始终包含必需的index字段,当上游 IR 事件未明确提供时默认为0(#57) - OpenAI Chat 流式传输:usage-only 数据块现在包含
"choices": [],以满足要求每个chat.completion.chunk必须包含choices数组的客户端验证(#55) stream_options(Chat Completions 专用字段)不再泄漏到 OpenAI Responses API 请求中 — Responses 转换器的ir_stream_config_to_p()之前错误地输出了stream_options,导致 Chat 格式客户端(Kilo、OpenCode)通过网关代理到 Responses API 时被上游拒绝(#58)- Google GenAI 转换器现在可以处理 REST 格式请求中顶层的 tools 和 tool_config(除了 SDK 格式的
config.tools)— 之前只识别 SDK 格式,导致网关代理请求中的工具定义被静默丢弃(#59) - Google camelCase
functionDeclarations未解析:p_tool_definition_to_ir()现在同时处理functionDeclarations(camelCase/REST)和function_declarations(snake_case/SDK),并提取所有声明而非仅第一个。同时为functionCallingConfig/allowedFunctionNames和toolConfig添加 camelCase 支持 — 修复 Gemini CLI 通过网关的工具调用(#61) - Google 流式工具调用被拆分为两个 chunk:
stream_response_to_provider()现在延迟tool_call_start,在tool_call_delta时发送完整的function_call(name + args),匹配 Google API 的原生格式(#62)
v0.2.0 — 2026-03-18¶
新增¶
- 独立 API 测试脚本 (
llm_api_simple_tests/):20 个测试脚本(每个提供商 5 个),直接使用官方 SDK,覆盖简单查询、多轮对话、图片、函数调用和综合场景 — 作为 git 子模块从 Oaklight/llm_api_simple_tests 引入 - LLM-Rosetta Gateway:跨提供商 HTTP 代理的 REST 网关应用
- CLI 入口 (
llm-rosetta-gateway) 及网关包结构 - 网关配置文件自动发现:依次搜索
./config.jsonc、~/.config/llm-rosetta-gateway/config.jsonc、~/.llm-rosetta-gateway/config.jsonc --edit/-e标志:在$EDITOR中打开配置文件(回退到 nano/vi/vim)--version/-V标志:显示当前版本- ASCII 艺术启动横幅,支持
--no-banner选项抑制显示 add provider <name>子命令:添加提供商条目到配置(支持--api-key、--base-url参数或交互式提示;已知提供商自动填充默认值)add model <name>子命令:添加模型路由条目(支持--provider参数或交互式提示)- 网关提供商模块 (
providers.py):集中管理提供商定义,包括认证头构建器、URL 模板、默认基础 URL 和 API 密钥环境变量名 - API 密钥轮转:每个提供商支持逗号分隔的多 API 密钥,通过
KeyRing轮询使用 - 代理支持:全局
server.proxy和逐提供商proxy配置,支持 HTTP/SOCKS 代理;CLI--proxy参数覆盖配置 - Makefile 新增
test-integration目标,使用proxychains(如已安装)运行集成测试 init子命令:在 XDG 默认位置 (~/.config/llm-rosetta-gateway/) 创建模板config.jsonc文件- 模型列表端点:
GET /v1/models(兼容 OpenAI 和 Anthropic SDK)和GET /v1beta/models(Google GenAI SDK 格式)— 使三种 SDK 的client.models.list()均可正常使用(#54)
变更¶
- 最低 Python 版本提升至 3.10+;迁移至标准库
typing(移除typing_extensions) - 使用
ruff格式化整个代码库 - 更新 Makefile,增加
lint、test和build目标 - 新增
ty(类型检查器)配置 - 在
pyproject.toml中配置rufflint 规则(E、F、UP);忽略UP007(Union 语法)和E501(行长度) - 现代化
src/、tests/、examples/和scripts/中的 typing 导入 — 将typing.Dict、List、Tuple、Optional、Type替换为标准库内建类型
修复¶
- 修复 Anthropic 提供商流式传输中 usage tokens 为
null时的崩溃 — 所有转换器中TypeError: NoneType + int(将.get("*_tokens", 0)替换为.get("*_tokens") or 0) - 网关提供商
base_url验证 — 配置错误(如https:example.com缺少//)时提前报错并给出清晰提示 - 网关依赖新增
socksio以支持 SOCKS 代理(httpx[socks]) - 补充
types包缺失的__init__.py - 更新文档中
git cloneURL,从llm-rosetta改为llm-rosetta - 解决
src/中所有ty类型检查器诊断(31 → 0):- 修复
is_part_type()TypeGuard 类型窄化 — 替换为特定类型守卫函数(is_text_part等) - 补充缺失的 TypedDict 字段:
TextPart/ReasoningPart上的provider_metadata,ImagePart/FilePart上的file_id - 修复
IRRequest.messages类型,从Required[Message]改为Required[Iterable[Message]] - 使用
cast()桥接dict[str, Any]中间值到 TypedDict 返回类型 - 修复转换器响应构建器中的 dict 字面量类型推断冲突
- 修复
- 解决
tests/中所有ty类型检查器诊断(1506 → 0):- 为传递给期望 TypedDict 参数的函数的 dict 字面量添加
cast()包装(GenerationConfig、IRRequest、IRResponse、ToolDefinition、ToolChoice等) - 使用
cast(list[Any], ...)或cast(Message, ...)窄化Message | ExtensionItem联合类型结果 - 将
Iterable内容字段转换为list以支持下标和len()访问 - 在对可选返回类型进行下标访问前添加
assert ... is not None守卫 - 修复
FinishReason,从裸字符串改为 TypedDict 形式{"reason": "stop"} - 修复
IRResponse.object字面量,从"chat.completion"改为"response"
- 为传递给期望 TypedDict 参数的函数的 dict 字面量添加
- 解决
src/和tests/中所有rufflint 违规(UP035 弃用导入、F401 未使用导入) - Google
thought_signature在网关往返中的保留 — 新版 Google 模型要求在函数调用部分中回传thoughtSignature;网关现在按tool_call_id缓存provider_metadata(含thought_signature),并在后续请求中重新注入,支持流式和非流式模式(#51) - OpenAI Responses 转换器现在支持全部 3 种
input格式:裸字符串("input": "hello")、简写列表([{"role": "user", "content": "hi"}])和结构化列表 — 此前仅支持结构化格式,导致 OpenAI Python SDK 发送的简写项被静默丢弃,跨提供商转换到 Anthropic 或 Google 时生成空 IR 消息
2026-03-15 — 品牌重塑为 LLM-Rosetta¶
变更¶
- 项目从 LLM-Rosetta 重命名为 LLM-Rosetta,涵盖所有代码、文档及配置
- 包名从
llm-rosetta改为llm_rosetta;pyproject.toml相应更新 - 使用 Zensical 全面重写英文 (
docs_en) 和中文 (docs_zh) 文档 - README(中/英)更新品牌标识、徽章及
pyproject.toml元数据
2026-03-06 — 流式传输与 StreamContext¶
新增¶
StreamContext:为所有 4 个提供商提供有状态的流式数据块处理- 所有转换器新增
stream_response_from_provider()和stream_response_to_provider()方法 accumulate_stream_to_assistant_message()辅助函数BaseConverter新增流式抽象方法(stream_response_to_provider、stream_response_from_provider)- 4 种新 IR 流式事件类型:
StreamStart、StreamEnd、ContentBlockStart、ContentBlockEnd ReasoningDeltaEvent及 IR 流式类型新增tool_call_index字段- 所有提供商组合的跨提供商流式示例(SDK 和 REST 版本)
- 示例中图片下载新增本地文件缓存和重试逻辑
变更¶
- 流式方法签名更新,增加可选
context参数 - 移除已弃用的
from_provider方法;auto_detect更新为新 API - 移除过时的单提供商示例脚本(已被跨提供商示例替代)
_normalize()提取至BaseConverter作为共享工具方法
修复¶
- Google GenAI REST 流式/响应字段的 camelCase 回退处理
- Anthropic 流式转换器:
thinking_delta、signature_delta、tool_call_id处理 - OpenAI Chat 流式转换器:
reasoning_content、空字符串、tool_call_index处理 - 补充测试包发现所需的
__init__.py google_genai_rest_e2e集成测试中的from_provider调用
2026-02-14 — 跨提供商示例与流式转换器¶
新增¶
- 所有 4 个提供商的流式转换器:OpenAI Chat、Anthropic、Google GenAI、OpenAI Responses
- 所有提供商的流式转换器单元测试
- 6 个跨提供商对话示例(基于 SDK):OpenAI Chat ↔ Anthropic、OpenAI Chat ↔ Google GenAI、OpenAI Chat ↔ OpenAI Responses、Anthropic ↔ Google GenAI、Anthropic ↔ OpenAI Responses、Google GenAI ↔ OpenAI Responses
- 跨提供商对话示例的公共资源模块
- Google GenAI 兼容性的图片 URL 转内联 base64 辅助工具
- OpenAI Responses E2E 集成测试(REST + SDK)
- OpenAI Responses Ops 类及转换器的单元测试
- 示例 README(中英文)
变更¶
- OpenAI Responses 转换器重构为 Bottom-Up Ops 模式
- 重构后清理:移除弃用工具和空目录
修复¶
- 为 Google GenAI 提供商兼容性将图片 URL 转换为内联 base64
2026-02-13 — Bottom-Up Ops 架构¶
新增¶
- Google GenAI 转换器使用 Bottom-Up Ops 模式重建
- OpenAI Responses API 类型的 TypedDict 副本
- Google GenAI SDK 类型的 TypedDict 副本
- Google GenAI REST 和 SDK E2E 集成测试
google_genai转换器 Ops 类的单元测试- Anthropic SDK 和 REST E2E 集成测试
- OpenAI Chat E2E 测试拆分为 SDK 和 REST 版本
- GitHub Actions CI/CD 工作流及 Dependabot 配置
变更¶
- Anthropic 转换器重新设计为 Bottom-Up Ops 架构
- 导入更新为使用新的
google_genai转换器模块 - 移除旧的
google/转换器及遗留测试
2026-02-12 — 转换器重新设计¶
新增¶
- Anthropic SDK 类型的 TypedDict 副本
- OpenAI Chat 类型的 TypedDict 副本,包含向后兼容性和测试
- 保留遗留 body 转换器设计作为历史参考
变更¶
- OpenAI Chat 转换器使用 Bottom-Up Ops 架构重新设计
- 修复整个代码库的 ruff lint 错误
2026-01-06 — 分层架构与文档¶
新增¶
- 初始化英文和中文文档结构(
docs_en、docs_zh) - 完整的错误处理文档
- OpenAI Chat Converter 集成测试
BaseConverter测试类的完整 mock 实现- 基础转换器的文件处理功能
- 提供商到 IR 的映射文档
变更¶
- 转换器基类完善为分层抽象模板
- 所有 4 个转换器重构为分层架构(Anthropic、OpenAI Chat、OpenAI Responses、Google GenAI)
- IR 内容/部件转换方法的类型注解更新
- IR 类型系统重组和增强
- 代码注释和文档字符串添加英文翻译
修复¶
- 修正推理内容字段断言
- 修复 OpenAI Chat Completions 转换器的文件内容处理
2026-01-05 — 自动检测与包成熟化¶
新增¶
detect_provider():自动检测提供商格式convert():一步格式转换便捷函数- 消息验证中支持
developer角色 BaseConverter、Anthropic、Google GenAI 和 OpenAI 转换器的综合验证测试- 工具调用和工具定义转换测试
- pytest 配置及
pytest-cov依赖 - 竞品分析文档
变更¶
- 包重命名:从
llm-provider-converter改为llm-rosetta - 所有提供商标准化 IR 格式用法
- 示例中使用
Message类标准化消息创建 - 测试套件从 unittest 迁移至 pytest
- 提取公共逻辑至共享工具模块
修复¶
- OpenAI Responses 转换器中无当前消息上下文时的独立工具调用处理
- Google GenAI Pydantic 模型处理重新排序以兼容元组
- OpenAI 单文本部件的内容处理逻辑简化
2026-01-04 — 示例与打包¶
新增¶
pyproject.toml包配置- 带工具集成的多轮对话示例
- 多轮对话示例中的 Anthropic 切换
- 多轮对话示例中的 Google GenAI 函数调用
变更¶
- 工具函数从转换器移至 IR 类型模块
- OpenAI Chat 转换器代码格式化改进
- 移除弃用的多提供商查询和天气工具模块
2025-12-24 — 初始实现¶
新增¶
- IR 类型系统:消息、内容部分、工具、配置、请求/响应的中间表示类型
BaseConverter抽象类:LLM 提供商转换基类AnthropicConverter:Anthropic Messages API 双向转换OpenAIChatConverter:OpenAI Chat Completions API 双向转换OpenAIResponsesConverter:OpenAI Responses API 双向转换GoogleGenAIConverter:Google GenAI SDK 格式双向转换- 所有 4 个转换器的综合测试套件
- 包初始化和导出
- 带模拟数据的天气工具示例
2025-12-09 — 研究与设计¶
新增¶
- 初始项目结构
- LLM 提供商消息类型 schema 文档及比较
- 提供商消息 IR 设计文档
- 跨提供商 MCP 支持对比(OpenAI、Anthropic、Google)
- Google GenAI Interactions API 类型分析
- 多提供商查询示例函数
- 查询示例中增加 OpenAI Responses API 支持