• Will Chen's avatar
    fix: filter orphaned reasoning items to prevent OpenAI API error (#2508) · aa71f805
    Will Chen 提交于
    fixes https://github.com/dyad-sh/dyad/issues/2500
    
    ## Summary
    - Adds `filterOrphanedReasoningParts()` function to filter out OpenAI
    reasoning items that aren't followed by output items
    - Fixes error: "Item of type 'reasoning' was provided without its
    required following item"
    - This error occurs with OpenAI reasoning models (o1, o3, o4-mini) when
    conversation history contains orphaned reasoning items
    
    ## Test plan
    - Added 4 unit tests covering:
      - Reasoning with following output is preserved
      - Orphaned reasoning (alone in message) is filtered out
      - Reasoning followed by tool-call is preserved
      - Trailing reasoning after text output is filtered
    - All 672 tests pass
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    <!-- devin-review-badge-begin -->
    
    ---
    
    <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2508"
    target="_blank">
      <picture>
    <source media="(prefers-color-scheme: dark)"
    srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
    <img
    src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
    alt="Open with Devin">
      </picture>
    </a>
    <!-- devin-review-badge-end -->
    
    <!-- CURSOR_SUMMARY -->
    ---
    
    > [!NOTE]
    > **Medium Risk**
    > Touches message-history shaping sent to OpenAI (including multi-step
    local-agent flows); incorrect filtering could drop reasoning parts or
    change message arrays, potentially impacting model behavior, but changes
    are scoped and covered by new unit tests.
    > 
    > **Overview**
    > Prevents OpenAI Responses API errors by **cleaning conversation
    history** before reuse: message parts now have stale
    `providerOptions/providerMetadata.{openai,azure}.itemId` removed and
    **orphaned `reasoning` parts (not followed by any non-reasoning
    output)** filtered out via `cleanMessageForOpenAI()`.
    > 
    > This cleaning is applied both when parsing persisted `aiMessagesJson`
    (`parseAiMessagesJson`) and during local-agent multi-step
    `prepareStepMessages`, with expanded unit tests covering preservation vs
    filtering cases; `thinking_utils` also disables OpenAI `store` for
    `local-agent` mode and `AGENTS.md` documents the failure mode and fix.
    > 
    > <sup>Written by [Cursor
    Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
    5b0c70c2817345598e2eb88dcefbb0f859d6bb88. This will update automatically
    on new commits. Configure
    [here](https://cursor.com/dashboard?tab=bugbot).</sup>
    <!-- /CURSOR_SUMMARY -->
    
    <!-- This is an auto-generated description by cubic. -->
    ---
    ## Summary by cubic
    Filters orphaned reasoning parts in conversation history to prevent
    OpenAI Responses API errors when a reasoning item isn’t followed by
    output. Applies filtering when parsing stored messages and during
    multi-step prepare step.
    
    - **Bug Fixes**
    - Replaced stripItemIds with cleanMessageForOpenAI in
    parseAiMessagesJson and prepareStepMessages to strip provider itemId and
    filter orphaned reasoning parts.
    - Preserves reasoning when followed by text or tool-call, preventing
    “reasoning without required following item” errors on o1/o3/o4-mini;
    sets store: false to avoid expired item references.
    - Expanded tests for parsing and multi-step flows; documented behavior
    and fix in AGENTS.md.
    
    <sup>Written for commit 5b0c70c2817345598e2eb88dcefbb0f859d6bb88.
    Summary will update on new commits.</sup>
    
    <!-- End of auto-generated description by cubic. -->
    Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com>
    aa71f805
名称
最后提交
最后更新
.claude 正在载入提交数据...
.cursor/rules 正在载入提交数据...
.devcontainer 正在载入提交数据...
.github 正在载入提交数据...
.husky 正在载入提交数据...
.storybook 正在载入提交数据...
assets 正在载入提交数据...
docs 正在载入提交数据...
drizzle 正在载入提交数据...
e2e-tests 正在载入提交数据...
makers 正在载入提交数据...
packages/@dyad-sh 正在载入提交数据...
scaffold 正在载入提交数据...
scripts 正在载入提交数据...
shared 正在载入提交数据...
src 正在载入提交数据...
testing 正在载入提交数据...
tools 正在载入提交数据...
worker 正在载入提交数据...
workers/tsc 正在载入提交数据...
.cursorignore 正在载入提交数据...
.env.example 正在载入提交数据...
.eslintrc.json 正在载入提交数据...
.gitattributes 正在载入提交数据...
.gitignore 正在载入提交数据...
.oxfmtrc.json 正在载入提交数据...
.oxlintrc.json 正在载入提交数据...
.prettierignore 正在载入提交数据...
.prettierrc 正在载入提交数据...
AGENTS.md 正在载入提交数据...
CLA.md 正在载入提交数据...
CLAUDE.md 正在载入提交数据...
CONTRIBUTING.md 正在载入提交数据...
LICENSE 正在载入提交数据...
README.md 正在载入提交数据...
SECURITY.md 正在载入提交数据...
biome.json 正在载入提交数据...
components.json 正在载入提交数据...
drizzle.config.ts 正在载入提交数据...
forge.config.ts 正在载入提交数据...
forge.env.d.ts 正在载入提交数据...
index.html 正在载入提交数据...
lint-staged.config.js 正在载入提交数据...
merge.config.ts 正在载入提交数据...
package-lock.json 正在载入提交数据...
package.json 正在载入提交数据...
playwright.config.ts 正在载入提交数据...
tsconfig.app.json 正在载入提交数据...
tsconfig.json 正在载入提交数据...
tsconfig.node.json 正在载入提交数据...
vite.main.config.mts 正在载入提交数据...
vite.preload.config.mts 正在载入提交数据...
vite.renderer.config.mts 正在载入提交数据...
vite.worker.config.mts 正在载入提交数据...
vitest.config.ts 正在载入提交数据...
windowsSign.ts 正在载入提交数据...