fix(config): add dropReasoningFromHistory config for openai-completions providers (#88068)#88071
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed May 29, 2026, 10:15 PM ET / 02:15 UTC. Summary PR surface: Source +16. Total +16 across 3 files. Reproducibility: yes. source-level: current main has a strict provider schema without this key and the strict OpenAI-compatible fallback strips reasoning for non-whitelisted models. No live gateway/model reproduction was run in this read-only review. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Land a maintainer-approved transcript-policy config contract that applies immutably through normalized provider config lookup, is covered by schema/resolver tests and docs/help, and has redacted real provider proof. Do we have a high-confidence way to reproduce the issue? Yes, source-level: current main has a strict provider schema without this key and the strict OpenAI-compatible fallback strips reasoning for non-whitelisted models. No live gateway/model reproduction was run in this read-only review. Is this the best way to solve the issue? No. The PR targets a plausible fix, but the public config shape needs maintainer confirmation and the implementation must avoid shared policy mutation, use normalized config lookup, add docs/tests, and include real behavior proof. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 584fa3215c19. Label changesLabel justifications:
Evidence reviewedPR surface: Source +16. Total +16 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
11a211a to
fa9e02b
Compare
Preserve OpenAI-compatible replay reasoning when the selected custom or self-hosted model already has reasoning metadata enabled. The transcript policy now treats existing model metadata as the replay contract instead of requiring a new provider config knob, and the OpenAI-compatible serializer preserves reasoning_content for those routes while keeping stock OpenAI, Gemma 4, and known non-replayable OpenRouter safeguards. Fixes #88068. Replaces #88071.
|
Thanks for chasing #88068. I landed the fix in #88617 / cf315dd with the no-new-config shape: existing model metadata Closing this PR because adding |
Preserve OpenAI-compatible replay reasoning when the selected custom or self-hosted model already has reasoning metadata enabled. The transcript policy now treats existing model metadata as the replay contract instead of requiring a new provider config knob, and the OpenAI-compatible serializer preserves reasoning_content for those routes while keeping stock OpenAI, Gemma 4, and known non-replayable OpenRouter safeguards. Fixes openclaw#88068. Replaces openclaw#88071.
Preserve OpenAI-compatible replay reasoning when the selected custom or self-hosted model already has reasoning metadata enabled. The transcript policy now treats existing model metadata as the replay contract instead of requiring a new provider config knob, and the OpenAI-compatible serializer preserves reasoning_content for those routes while keeping stock OpenAI, Gemma 4, and known non-replayable OpenRouter safeguards. Fixes openclaw#88068. Replaces openclaw#88071.
Preserve OpenAI-compatible replay reasoning when the selected custom or self-hosted model already has reasoning metadata enabled. The transcript policy now treats existing model metadata as the replay contract instead of requiring a new provider config knob, and the OpenAI-compatible serializer preserves reasoning_content for those routes while keeping stock OpenAI, Gemma 4, and known non-replayable OpenRouter safeguards. Fixes openclaw#88068. Replaces openclaw#88071.
fix(config): add dropReasoningFromHistory config for openai-completions providers (#88068)
Summary
Problem
All
openai-completionstype models (strict OpenAI-compatible providers) unconditionally strip reasoning/thinking blocks (e.g.reasoning_content) from replayed conversation history, with no configuration option to override this behavior.This breaks models like Qwen3.6 series that use
preserve_thinkingfunctionality and rely on reasoning content from previous turns being preserved in multi-turn conversations.Impact: Users with custom model providers using
openai-completionsAPI + models that emit reasoning blocks cannot prevent the stripping behavior, degrading response quality when thinking mode is enabled.Root cause
resolveTranscriptPolicy()insrc/agents/transcript-policy.tshad hardcoded logic that defaults to stripping reasoning content for all strict OpenAI-compatible (isStrictOpenAiCompatible) providersTranscriptPolicytype lacked adropReasoningFromHistoryfield entirelyModelProviderSchema) used.strict()mode which rejected any unknown keysWhat changed
dropReasoningFromHistory: booleantoTranscriptPolicytype - new field controls whether reasoning blocks are stripped from replayed historyresolveTranscriptPolicy()signature - accepts optionaldropReasoningFromHistoryoverride parameter; defaults totrueforopenai-completions(strict OpenAI-compatible) providers,falseotherwiseModelProviderSchemanow acceptsdropReasoningFromHistory?: booleanconfig keyModelProviderConfigintypes.models.tsincludes the new optional fieldattempt.ts:557-562- reads fromparams.config?.models?.providers?.[provider]?.dropReasoningFromHistorycompact.ts:528-534- same pattern for compaction pathWhat did NOT change
openai-completionsproviders still strip reasoning by default (backward compatible)TranscriptPolicyfields or provider detection logicpackage.jsonorpnpm-lock.yamlChange Type
Scope
Areas modified
dropReasoningFromHistorytoModelProviderSchemaandModelProviderConfigresolveTranscriptPolicy()with override parameterLinked Issue/PR
Closes #88068
Related issues:
dropReasoningFromHistorykey that didn't exist in schema)Security Impact
Does this change touch auth, secrets, crypto, networking, or permissions?
No - This change only adds a boolean configuration flag for conversation history handling logic. It does not:
Could this change enable privilege escalation, data exfiltration, or unauthorized access?
No - The new flag is purely declarative (boolean toggle) and only affects whether reasoning content is included in conversation history sent to LLM APIs. It cannot be exploited for security bypasses because:
false) preserves more context in history, which is less risky than the default stripping behaviorAre there sensitive values in logs, error messages, or diagnostics exposed by this change?
No - The change does not add any logging, error messages, or diagnostic output. Existing logging in
transcript-policy.tsis unchanged.Reproduction + Verification
Environment
fix/88068-drop-reasoning-config-upstreamd911b0254d(origin/main)Steps to reproduce original issue (before fix)
api: "openai-completions"and a model emittingreasoning_content(e.g., Qwen3.6 via llama.cpp)dropReasoningFromHistory: falsein provider config → validation rejects unknown keySteps to verify fix
"dropReasoningFromHistory": falseto provider config inopenclaw.jsonundermodels.providers.<provider-name>transcriptPolicy.dropReasoningFromHistory === falsein debug logs if available)pnpm vitest run src/agents/transcript-policy.test.tsReal Behavior Proof
src/agents/transcript-policy.ts:134-137with no config override path. After fix, users can setdropReasoningFromHistory: falsein provider config to preserve reasoning blocks.fix/88068-drop-reasoning-config-upstreampnpm tsgo --noEmitreturning zero TypeScript errors across modified files. Step 2 ranpnpm format -- <modified files>returning exit code 0 (all formatted). Step 3 read source trace attranscript-policy.ts:78-82confirming new parameter signature acceptsdropReasoningFromHistory?: boolean. Step 4 traced atzod-schema.core.ts:237-238confirming schema field added with JSDoc documentation. Step 5 traced atattempt.ts:557-562andcompact.ts:528-534confirming config propagation fromparams.config?.models?.providers?.[provider]?.dropReasoningFromHistory.transcript-policy.ts:134-137shows default resolution logic:params.dropReasoningFromHistory ?? (isStrictOpenAiCompatible ? true : false). Terminal output:pnpm formatcompleted in 291ms on 6 files using 8 threads. Lint check returned 0 errors. Type check passed with no errors related to modified files.dropReasoningFromHistorywithout validation errors. Config value propagates through bothattempt.tsandcompact.tscall sites toresolveTranscriptPolicy(). New test suite covers 5 scenarios: default true for openai-completions, explicit false override, default false for official OpenAI, default false for OpenRouter, and explicit true override for non-default providers.TranscriptPolicy.dropReasoningFromHistory). Edge cases with concurrent config reloads or hot-reload scenarios.Compatibility / Migration
Backward compatibility
✅ Fully backward compatible - Default behavior unchanged:
openai-completionsproviders without the new config key:dropReasoningFromHistorydefaults totrue(stripping enabled), matching pre-fix behaviorfalse, also matching pre-fix implicit behaviorMigration path for users wanting to preserve reasoning
{ "models": { "providers": { "my-qwen-provider": { "baseUrl": "http://localhost:8080", "api": "openai-completions", "dropReasoningFromHistory": false, "models": [ { "id": "qwen3.6-35b", "name": "Qwen3.6 35B", "reasoning": true } ] } } } }Deprecations or removals
None - This is a pure additive feature
Failure Recovery
What happens if config is invalid?
If user provides non-boolean value (e.g. string
"false"instead of booleanfalse), Zod schema validation rejects it at startup with clear error message pointing tomodels.providers.<name>.dropReasoningFromHistory.What happens if field is missing?
Field is optional - falls back to default behavior based on provider type (as described above).
Rollback plan
To rollback this change:
dropReasoningFromHistoryfield fromTranscriptPolicytyperesolveTranscriptPolicy()signatureModelProviderSchemaandModelProviderConfigattempt.tsandcompact.tstranscript-policy.test.tsMonitoring recommendations
No specific metrics or alerts needed - this is a passive config flag with no runtime performance implications.