openai-node v7.20.0 更新解读:环境变量 vault 凭据、外部存储管理与 safety cases 检索
openai-node v7.20.0 一版带六个 PR:vault 凭据新增 environment_variable 类型(沙箱只拿占位符、出站代理 443/8443 替换密钥)、admin 外部存储配置管理面、safety cases 检索端点与 warning/deactivation 两个新 webhook 事件、三个来电事件的 SIP 媒体安全字段,外加遗留 GET 请求选项修复。逐项对应 PR 与 tag 源码拆解。
openai-node 在 2026-09-19 发布 v7.20.0:一个版本带进六个 PR——五个 API 功能加一个修复。功能集中在三条此前已有雏形的线上:Agents API 的 vaults 凭据体系补上第三种 auth 类型、admin 命名空间补上外部存储配置管理面、safety 家族从 alert 延伸出 case 检索端点和两个配套 webhook 事件;外加一个来电事件的 SIP 媒体安全字段和一个影响面不小的遗留 GET 调用修复。本文逐项对应 PR 与类型源码拆解(全部基于 2026-09-20 当日经 GitHub API 重抓的 release notes、PR diff 与 v7.20.0 tag 源文件核对),示例代码取自 tag 内官方文档字符串与类型定义。
截至 2026-09-20 经 GitHub releases 核对,openai-python 最新版仍为 v3.16.2(2026-09-18 发布),本批六项改动尚未出现在 python 侧的 release notes 中。
1. 版本速览
| PR | 类型 | 内容 | 主要源文件 |
|---|---|---|---|
| #2768 | feat | vault 凭据新增 environment_variable 类型与 networking 配置 | beta/agents/vaults/credentials.ts |
| #2773 | feat | admin 外部存储配置管理(AWS/Azure) | admin/organization/external-storage.ts |
| #2774 | feat | safety cases 检索端点 | safety/cases.ts、safety/safety.ts |
| #2772 | feat | safety.warning_issued / safety.deactivation_issued 两个 webhook 事件 | webhooks/webhooks.ts |
| #2770 | feat | 三个来电事件 data 新增可选 sip_media_security 字段 | webhooks/webhooks.ts |
| #2771 | fix | 遗留 GET 调用的请求选项保留 | 57 个源文件(见第 6 节) |
2. vault 凭据第三种类型:environment_variable(#2768)
Agents API 的 vault 凭据此前只有两种 auth 类型:mcp_oauth(OAuth 凭据,带自动刷新元数据)与 static_bearer(静态 Bearer 令牌)。#2768 把 CredentialAuth 联合扩为三值,新增 environment_variable,官方定位是"仅用于 OpenAI 托管环境的 HTTP 凭据"。它的工作方式与另外两种有本质区别:
- 创建凭据时把真实密钥(secret_value)存进 vault;
- 沙箱代码拿到的环境变量不是密钥,而是占位符(占位符通过 secret_name 指定的变量名注入);
- 代码照常把该变量放进出站请求;
- 出站代理对允许的 HTTPS 目标(端口 443 与 8443)把占位符替换为真实密钥。
官方文档字符串对边界的表述很明确:真实密钥不返回到凭据资源里、沙箱代码不可读取、也不能用于本地计算——文档字符串点名"签名请求"这类用法不行,因为那需要拿到明文密钥。
const credential = await client.beta.agents.vaults.credentials.create('vault_id', {
name: 'service-api-key',
auth: {
type: 'environment_variable',
secret_name: 'SERVICE_API_KEY',
secret_value: process.env.SERVICE_API_KEY ?? '',
networking: { type: 'limited', allowed_hosts: ['api.example.com'] },
},
});
// credential.object === 'vault.credential'
networking:代理替换目的地的两层约束
environment_variable 类型必须带 networking 字段,二选一:
| 取值 | 语义 | 附加条件 |
|---|---|---|
| unrestricted | 对环境网络策略允许的目的地都可替换 | 要求 environment.network.access 为 restricted 且显式配置 allowed_domains |
| limited | 只对列出的主机替换 | allowed_hosts 为 1-16 个去重主机名或 IPv4 地址(小写、不含 scheme/路径/端口/通配符;不支持 IPv6) |
文档字符串同时强调:networking 描述的是"代理可以替换这个密钥的目的地",它并不给环境授予网络访问权——环境自身的网络策略仍然独立生效,两层约束同时满足才走得通。
其余约束(均出自 tag 内类型文档字符串):凭据 name 去除首尾空白后须为 1-256 个 UTF-8 字节;secret_name 限 ASCII 字母、数字、下划线且以字母或下划线开头(如 SERVICE_API_KEY),CODEX_ 前缀与代理/证书托管变量名为保留名;secret_value 只写、必须非空、不得含回车/换行/NUL 字节;update 语义是轮换(CredentialAuthRotateParam),environment_variable 同样在支持之列。资源仍挂在 client.beta.agents.vaults.credentials 下,create / retrieve / update / list(cursor 分页)/ delete 五个操作与 OpenAI-Beta: agents=v1 请求头不变。
3. 外部存储配置管理:client.admin.organization.externalStorage(#2773)
#2773 在 admin 命名空间下新增外部存储配置资源,create 的官方文档字符串只有一句:Register one customer-managed external storage configuration(登记一条客户自管的外部存储配置)。五个操作对应五条端点:
- create — POST
/organization/external_storage - retrieve — GET
/organization/external_storage/{id} - list — GET
/organization/external_storage(cursor 分页,参数 after / order(asc、desc)/ project_id) - delete — DELETE
/organization/external_storage/{id} - validate — POST
/organization/external_storage/{id}/validate
配置对象(object 恒为 organization.external_storage)包含 id、created_at、geography、project_id、provider 与 status 三态枚举:pending / validated / unhealthy。provider 支持 AWS 与 Azure 两种:
| 字段 | AWS | Azure |
|---|---|---|
| 创建时必填 | bucket、role_arn | account_name、container、resource_group、subscription_id、tenant_id |
| 资源返回 | 另有 account_id、external_id、region | 另有 region |
SDK 文档字符串只给了 create 的定位一句话;这一资源与具体产品形态的绑定关系,官方未在 SDK 内说明,截至 2026-09-20 本站也未在可加载来源核实到更多信息,此处不做推断。鉴权层面该资源走 admin API key(adminAPIKeyAuth),与 admin 命名空间其他资源一致。
// 官方 JSDoc 示例(external-storage.ts 内)
const externalStorageConfiguration =
await client.admin.organization.externalStorage.create({
project_id: 'proj_123',
provider: {
bucket: 'bucket',
role_arn: 'role_arn',
type: 'aws',
},
});
4. safety cases:检索端点与两个新 webhook 事件(#2774 / #2772)
2026-09-03 的 SDK 批次里,safety 家族落地的是 alerts:GET /v1/safety/alerts/{id} 加上 safety.alert.created / safety.org_alert.created 事件。本批 #2774 在 client.safety 下并列新增 cases 子资源:
const safetyCase = await client.safety.cases.retrieve('case_id');
// GET /v1/safety/cases/{id}
// safetyCase.object === 'safety.case'
// safetyCase.notice.type === 'warning' | 'deactivation'
// safetyCase.reason === string | null
返回的 SafetyCase 对象字段:id、created_at、entity_identifier、notice(含 type 二值 warning / deactivation)、object 恒为 safety.case、reason(可空字符串)。
#2772 配套新增两个 webhook 事件,官方文档字符串原文:
- safety.warning_issued — Sent when a warning is issued for a safety identifier in your organization.(组织内某 safety 标识符被发出警告时发送)
- safety.deactivation_issued — Sent when a deactivation is issued for a safety identifier in your organization.(组织内某 safety 标识符被发出停用处理时发送)
两个事件的 payload.data 结构相同,只有一个 id 字段,文档字符串明确写出它的用途:The safety case ID to pass to GET /v1/safety/cases/{id}——事件与检索端点之间这条跳转路径是官方原文写死的。事件名(warning_issued / deactivation_issued)与 case 的 notice.type 二值在命名上对应。
消费侧用既有的 unwrap(本批未改其签名):
const event = await client.webhooks.unwrap(
req.body, // 原始 payload 字符串
req.headers, // 请求头(webhook-signature / webhook-timestamp / webhook-id)
process.env.OPENAI_WEBHOOK_SECRET, // 省略时用 client.webhookSecret
);
if (
event.type === 'safety.warning_issued' ||
event.type === 'safety.deactivation_issued'
) {
const safetyCase = await client.safety.cases.retrieve(event.data.id);
}
一个类型层面的精确事实:两个新事件加进了 UnwrapWebhookEvent(unwrap 返回的事件联合,v7.20.0 tag 实测共 21 类),但 WebhookCreateParams / WebhookUpdateParams 里 event_types 字段的静态订阅联合在本批之后仍是原 18 值——SDK 类型层尚未把两个新事件列为创建端点时的可订阅项(截至 2026-09-20 对 tag 源文件核对)。实际可订阅列表以 client.webhooks.event_types.list() 返回为准(该端点返回 string 数组,无静态枚举约束)。
5. 来电事件的 SIP 媒体安全字段(#2770)
#2770 给三个来电类 webhook 事件的 data 各新增一个可选字段 sip_media_security:
- live.call.incoming(LiveCallIncomingWebhookEvent)
- live.transport.incoming(LiveTransportIncomingWebhookEvent)
- realtime.call.incoming(RealtimeCallIncomingWebhookEvent)
取值类型是开放联合:'rtp' | 'srtp' | (string & {})。官方字段描述全文:SIP leg 在 SDP 协商中选定的媒体保护方式——srtp 表示 SRTP,rtp 表示未加密 RTP;未知时省略;该字段不描述 SIP 信令的安全,也不确认媒体已经开始流动;客户端应把未识别值当未知处理。两点注意:live.transport.incoming 事件本身此前已存在,本批只是加字段;字段可选,消费代码不能假设它必然出现。
6. 修复:遗留 GET 调用的请求选项保留(#2771)
release notes 里唯一的 fix:Preserve request options in legacy GET calls。背景是 SDK 内一批 list 型 GET 方法的第一参数在历史上同时承担"查询参数"与"请求选项"两种角色;本批为这些方法增加了重载与运行时归一化(normalizeRequestOptionsForQuery):第一参数里出现的传输选项——headers、maxRetries、timeout、signal、idempotencyKey——被识别为请求选项,不再被序列化进 URL 查询字符串。
改动面:57 个非测试源文件,覆盖 admin/organization 全系 21 个资源(api keys、audit logs、certificates、groups、invites、projects 系、roles、spend alerts、users 等)以及 batches、beta/agents 全家、beta/assistants、beta/threads、chat/completions、containers、conversations、evals、files、fine-tuning、images、responses、skills、vector-stores、videos、webhooks。
运行时行为随之收紧,两种传参会直接抛 TypeError:
- 查询参数与请求选项混在一个对象里传 — Query parameters and request options must be passed as separate arguments.
- 在查询位置传传输覆盖(method、path、body 等) — Pass transport overrides in the explicit request options argument.
正确写法是各归其位:
// 第一参数只放查询参数,第二参数放请求选项
const page = await client.admin.organization.externalStorage.list(
{ project_id: 'proj_123' },
{ timeout: 30_000, maxRetries: 2 },
);
如果既有代码把 timeout / signal 之类传在第一参数里且一直"没生效",这次升级后行为会改变(选项开始真正生效);如果依赖了被误序列化进查询串的旧行为,需要自查。
7. 常见错误与排查
- 沙箱里拿到的是占位符不是密钥:environment_variable 类型设计如此。检查三处——出站目标是否 HTTPS、端口是否 443/8443、networking 配置与环境网络策略是否都放行该目标;本地计算场景(如签名)官方明确不支持。
- secret_name 设置失败:检查命名规则——ASCII 字母/数字/下划线、以字母或下划线开头、不得使用 CODEX_ 前缀与代理/证书托管保留名。
- 创建 webhook 端点时事件列表里没有 safety.warning_issued:SDK 静态联合尚未收录(见第 4 节),以 client.webhooks.event_types.list() 返回为准;unwrap 侧的类型已经支持。
- 升级后 list 调用抛 TypeError:查询参数与请求选项分开放(见第 6 节的两个错误信息)。
- external storage 配置一直 pending:validate 端点用于发起校验;status 枚举 pending / validated / unhealthy,校验失败后的具体排查手段 SDK 内没有更多说明。
8. 下一步
- 想了解 safety alerts 的原始形态与 misalignment 错误码,读《gpt-6-astra 现身 OpenAI SDK:ChatModel 枚举新模型 ID 与 Safety Alerts API 解读》。
- vaults 资源的全景(含本次 credentials 所在的体系)见《Agents API 现身 OpenAI SDK(beta):/agents CRUD、environments、sessions 与 vaults 全景》。
- 三个来电事件与 SIP 通话控制(accept / reject / hangup / refer)的完整拆解见《Live API 现身 OpenAI SDK:gpt-live-1、WebRTC/WebSocket 双通道与 SIP 通话控制解读》。
- 上一批 SDK 六版连发(prewarm、client.webhooks 端点管理、connector_id 弃用)见《openai-python 3.15 / 3.16 与 openai-node 7.18 / 7.19 更新解读:缓存预热、Webhook 管理与 connector_id 弃用》。
关键要点
- environment_variable vault 凭据(#2768):CredentialAuth 联合从 mcp_oauth + static_bearer 两值扩为三值,新增 environment_variable——HTTP 凭据仅用于 OpenAI 托管环境:沙箱代码拿到的环境变量是占位符,出站代理对允许的 HTTPS 目标(端口 443 与 8443)把占位符替换为真实密钥;真实密钥不返回、沙箱代码不可读取、不能用于本地计算(如签名请求)
- networking 与约束(#2768):CredentialNetworking 二选一——unrestricted(要求 environment.network.access 为 restricted 且显式配 allowed_domains)或 limited(1-16 个去重主机名/IPv4,小写、不带 scheme/path/端口/通配符,不支持 IPv6);secret_name 命名限 ASCII 字母/数字/下划线且以字母或下划线开头,CODEX_ 前缀与代理/证书托管变量名为保留名;secret_value 只写、非空、不得含 CR/LF/NUL;rotate 同步支持该类型
- 外部存储配置管理(#2773):client.admin.organization.externalStorage 提供 create(POST /organization/external_storage,登记一条客户自管外部存储配置)/ retrieve / list(cursor 分页)/ delete / validate(POST .../{id}/validate);配置对象含 geography、project_id、status(pending/validated/unhealthy);provider 支持 AWS(bucket + role_arn)与 Azure(account_name/container/resource_group/subscription_id/tenant_id),鉴权为 admin API key
- safety cases 与新事件(#2774 / #2772):client.safety.cases.retrieve 对应 GET /v1/safety/cases/{id},返回 safety.case 对象(entity_identifier、reason 可空、notice.type 为 warning 或 deactivation);新 webhook 事件 safety.warning_issued 与 safety.deactivation_issued(官方文档字符串:组织内某 safety 标识符被发出警告/停用处理时发送)的 payload.data.id 即要传给该端点的 case ID;client.safety 下 alerts 与 cases 两个子资源并存
- SIP 媒体安全字段(#2770):live.call.incoming、live.transport.incoming、realtime.call.incoming 三个事件的 data 各新增可选 sip_media_security——取值 rtp / srtp 或其他未识别字符串(开放联合);官方描述:SIP leg 在 SDP 协商中选定的媒体保护,未知时省略;不描述 SIP 信令安全、也不确认媒体已流动,客户端应把未识别值当未知处理(live.transport.incoming 事件本身此前已存在,非本批新增)
- 遗留 GET 修复(#2771):为遗留 list 型 GET 方法增加重载与运行时归一化——第一参数里混入的传输选项(headers/maxRetries/timeout/signal/idempotencyKey)被识别为请求选项而非序列化进 URL 查询;查询参数与请求选项混传抛 TypeError(Query parameters and request options must be passed as separate arguments.);改动覆盖 57 个源文件(admin/organization 21 个 + batches、beta/agents、chat/completions、containers、evals、responses、videos 等)
常见问题
官方参考
- 更新openai-node v7.20.0 Release Notes(GitHub)
- 更新openai-node PR #2768:add environment-variable vault credentials
- 更新openai-node PR #2773:add external storage configuration management
- 更新openai-node PR #2774:add safety case retrieval
- 更新openai-node PR #2772:add safety warning and deactivation webhook events
- 更新openai-node PR #2770:add SIP media security to incoming call events
- 更新openai-node PR #2771:Preserve request options in legacy GET calls
相关文章
OpenAI API 429 限流错误排查:RateLimitError 与 SDK 重试机制
遇到 OpenAI API 429 时先分清两类:请求速率超限还是配额耗尽——两者都抛 RateLimitError 但解法完全不同。官方 Python SDK 默认已替你重试 2 次并遵守 Retry-After,本文按 SDK 源码把机制与排查路径讲清。
阅读全文openai-python 3.15 / 3.16 与 openai-node 7.18 / 7.19 更新解读:缓存预热、Webhook 管理与 connector_id 弃用
OpenAI 官方 SDK 9-18 一天六版:prompt_cache_options 新增 prewarm 缓存预热、client.webhooks 补齐 Webhook 端点管理 REST 面、MCP 工具 connector_id 标记弃用(2026-09-01 后模型)、WebSocket 会话 lane 路由库双语言落地。逐项对应 PR 拆解,附可复制示例。
阅读全文Responses API 压缩进度事件解读:response.compaction.compacting、compaction_trigger 与长会话上下文压缩
openai-node v7.17.0 给 Responses API 流式事件族补上压缩进度事件 response.compaction.compacting:处理 compaction_trigger 时至多每 30 秒上报一次,不携带任何摘要内容。它和 compaction_trigger 输入项、/responses/compact 端点、context_management 配置如何配合,本文逐项拆解。
阅读全文订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。
提交后将在新标签页打开 Buttondown 完成订阅确认。