Skip to content

fix(runtime): make Responses reasoning replay dialect-aware #2513

Description

@me2seeks

What happens

DeepSeek Responses reasoning now arrives and is stored after #2328, but a later tool-loop request tries to replay that plaintext reasoning through the OpenAI encrypted-reasoning shape.

With store: false, @ai-sdk/openai rejects that shape when it has no reasoningEncryptedContent, removes the reasoning item from the request, and prints this process warning:

AI SDK Warning (openai.responses / deepseek-v4-flash): Reasoning parts without encrypted content are not supported when store is false. Skipping reasoning parts.

This is not only noisy terminal output: the warning says the request projection is lossy.

The asymmetric round trip

Response direction (provider -> Maka) works today:

DeepSeek response.reasoning_text.delta
  -> plaintext Responses transport added in #2328
  -> AI SDK reasoning delta
  -> Maka ThinkingItem { text, itemId, no encrypted content }
  -> event log / UI

Request direction (Maka -> provider) does not:

stored ThinkingItem
  -> AiSdkBackend reasoning part
  -> @ai-sdk/openai Responses input converter
  -> store=false + encrypted_content missing
  -> warning + reasoning item removed
  -> provider receives function_call / function_call_output without the plaintext reasoning

For example, after DeepSeek reasons and calls a tool, the desired second request is conceptually:

message, reasoning, function_call, function_call_output

The current request is:

message, function_call, function_call_output

DeepSeek can mask this in ordinary runs by recovering reasoning from its own call_id, but that is provider-specific behavior rather than a complete replay contract. The provider-free serialization gap is tracked upstream in vercel/ai#18511, with a proposed @ai-sdk/open-responses fix in vercel/ai#18546.

Why encrypted_content is involved

Maka sends Responses requests with store: false. The native OpenAI provider in the AI SDK therefore treats a replayable reasoning item as OpenAI's encrypted-content contract. DeepSeek's Open Responses dialect instead returns and consumes plaintext content[].reasoning_text; it cannot satisfy the OpenAI serializer merely by having an itemId.

The current replay capability is too broad: openai-responses-item says that a Responses reasoning item can be replayed, but does not say which wire dialect can encode it.

Proposed direction

I think this should be resolved at the ModelAdapter/request-projection seam, not by suppressing AI SDK warnings globally.

  1. Do not project plaintext Responses reasoning as an OpenAI encrypted reasoning item when reasoningEncryptedContent is absent. This preserves today's actual wire body while removing the misleading attempted replay and process warning.
  2. Keep replaying genuine encrypted reasoning unchanged.
  3. Once the upstream @ai-sdk/open-responses request-side fix is released, evaluate routing measured Open Responses providers such as DeepSeek through a dialect-specific codec/provider so plaintext reasoning is really serialized in the correct order.

The short-term containment and the full plaintext round trip can be separate PRs. I’m happy to implement this; before I start, I’d like to confirm whether maintainers prefer that split or want to wait for the upstream provider fix.

Acceptance checks

  • A DeepSeek tool-loop request emits no plaintext-as-encrypted warning.
  • A fake-fetch assertion checks the actual request body, not only Maka's intermediate model messages.
  • Encrypted OpenAI Responses reasoning still replays.
  • The request preserves message, reasoning, function_call, function_call_output ordering once plaintext replay is enabled.
  • No global warning suppression is introduced.

Related: #2328, vercel/ai#18511, vercel/ai#18546

中文说明

现象

#2328 已经修复了响应方向:DeepSeek 返回的明文 reasoning_text 能进入 Maka 的事件日志和界面。但是下一次工具回合组装请求时,Maka 又把这段明文 reasoning 当成 OpenAI 的加密 reasoning item 重放。

因为当前请求使用 store: false@ai-sdk/openai 要求这种 reasoning item 携带 encrypted_content。DeepSeek 返回的是明文 reasoning_text,没有加密内容,所以 SDK 打印 warning 并在真正发请求前删除 reasoning item。

因此这不是单纯的日志噪音,而是说明请求投影发生了有损丢弃。

两个方向

  • 响应方向:Provider 返回内容给 Maka。这个方向已经能把 DeepSeek 的明文 reasoning 转换、保存并显示。
  • 请求方向:Maka 在工具调用后的下一轮,把历史消息重新发送给 Provider。这个方向目前尝试使用错误的 OpenAI 加密格式,随后被 SDK 丢弃。

普通运行有时仍然成功,是因为 DeepSeek 可以根据自己签发的 call_id 在服务端找回 reasoning;这不代表 Maka 已经正确发送了它。

建议

短期在 ModelAdapter/请求投影位置停止把缺少 reasoningEncryptedContent 的明文 reasoning 伪装成加密 item;真实的加密 reasoning 继续正常重放。长期等 @ai-sdk/open-responses 的请求侧修复发布后,再让 DeepSeek 使用能真正编码 reasoning_text 的 provider/codec。

不建议全局关闭 AI SDK warning,因为那只会隐藏有损请求。

我愿意实现这个修复;开始前想先确认维护者更希望拆成“短期止损 + 完整明文重放”两个 PR,还是等待上游 provider 修复。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions