hermes - ✅(Solved) Fix [Bug]: DeepSeek V4 Flash Discord session poisoned when tool-call assistant lacks reasoning_content [6 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#15250Fetched 2026-04-25 06:23:26
View on GitHub
Comments
0
Participants
1
Timeline
16
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×6labeled ×6referenced ×3closed ×1

Error Message

2026-04-24 15:57:19 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The reasoning_content in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}} 2026-04-24 15:58:51 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The reasoning_content in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}} 2026-04-24 16:03:58 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The reasoning_content in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}

Root Cause

Minimal Root Cause Hypothesis

Fix Action

Fix / Workaround

Local Patch Tested

A local patch that fixes the poisoned-session case:

Yes, I can submit the local patch as a PR if maintainers agree this fallback should live in _copy_reasoning_content_for_api() rather than a lower-level DeepSeek transport adapter.

PR fix notes

PR #15323: fix(kilo): workaround DeepSeek thinking-mode 400 on Kilo gateway (v4-pro/v4-flash/reasoner)

Description (problem / solution / changelog)

Summary

This PR fixes HTTP 400 errors ("The reasoning_content in the thinking mode must be passed back to the API.") for DeepSeek V3.2+ thinking models (deepseek-v4-pro, deepseek-v4-flash, deepseek-reasoner) accessed via the Kilo Code Gateway (https://api.kilo.ai/api/gateway).

Why this is distinct from #14941, #15228, #15237

Existing open/closed DeepSeek reasoning_content PRs target direct DeepSeek API access (api.deepseek.com) and all assume that setting reasoning_content = "" is sufficient. That assumption does not hold through the Kilo gateway:

  1. Kilo strips reasoning / reasoning_content / reasoning_details fields on forward — see Kilo-Org/cloud:apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts, function removeChatCompletionsReasoning, and also injectReasoningIntoContent which falls back to if (reasoning) — a truthy check that drops empty strings. So reasoning_content = "" reaches the upstream DeepSeek provider as absent.

  2. DeepSeek V3.2+ thinking mode additionally rejects conversations shaped as tool → user — i.e. any user turn after the last tool result causes the 400 even when reasoning_content is present. I reproduced this directly against api.kilo.ai with every combination of reasoning / reasoning_content / reasoning_details (empty, whitespace, non-empty, native and unified naming). The only shapes that succeed are:

    • No trailing user/assistant after the last tool, or
    • Such trailing text merged into the last tool message's content.

This is the same workaround Roo Code adopted in kilocode-legacy/src/api/transform/r1-format.ts (convertToR1Format(..., { mergeToolResultText: true })). Their comment:

"environment_details text after tool_results would create user messages that cause DeepSeek to drop all previous reasoning_content."

This PR ports that insight into Hermes.

Changes

All in run_agent.py, plus a new test file.

1. _needs_deepseek_thinking_tool_merge() (new)

Returns True when base_url is api.kilo.ai and the model contains "deepseek" but isn't deepseek-chat (which is non-thinking and unaffected).

2. _copy_reasoning_content_for_api() extended

New terminal branch: when the above predicate is true and source_msg has tool_calls but no reasoning_content/reasoning, inject reasoning_content = ".".

Why "." and not "": empirically verified against api.kilo.ai/api/gateway/chat/completions with deepseek-v4-pro:

  • reasoning_content = "" → HTTP 400 (falsy, gateway drops it).
  • reasoning_content = " " (single space) → HTTP 200.
  • reasoning_content = "." → HTTP 200.

Minimum-cost placeholder that survives the gateway's truthy filter.

3. _merge_post_tool_text_into_tool() (new, static)

Walks api_messages, finds the last tool message, and if only user/assistant-text messages (no further tool_calls) follow it, merges their text into the tool's content and truncates the list there. Does not mutate the input; returns a new list. Bails out if another tool-call round follows the last tool result, to preserve structure.

4. Invoked at both api_messages assembly sites

  • Main agent loop (after the per-message copy+sanitize pass).
  • flush_memories().

Testing

Unit tests (new file tests/run_agent/test_kilo_deepseek_thinking.py)

20 tests covering:

  • _needs_deepseek_thinking_tool_merge() matrix: kilo × [v4-pro, v4-flash, deepseek-reasoner, deepseek-chat, non-deepseek] + openrouter-with-deepseek (must be False).
  • _merge_post_tool_text_into_tool(): empty list, no tool, no trailing, single trailing user, multiple trailing users, mixed asst-text + user trailing, trailing asst-with-tool-calls (must bail), multi-round with merge only on last, input immutability.
  • _copy_reasoning_content_for_api() kilo+deepseek branch: "." injection, preservation of explicit reasoning_content, conversion from reasoning, non-injection on non-kilo, non-injection without tool_calls.

All 20 pass. Existing tests/run_agent/test_provider_parity.py (76 tests) still passes.

End-to-end verification

I replayed a real failing request_dump_*.json captured from a user-session (DeepSeek v4-pro via kilo, mid-agent-loop with 7 trailing user messages after the last tool result — caused by plugin context injection). Before fix: HTTP 400. After fix: HTTP 200 with proper content and reasoning fields returned by the model.

Interaction with #14941, #15228

Compatible. This PR only fires when base_url is api.kilo.ai; #15228 paths run for api.deepseek.com. They do not conflict at runtime. If #15228 merges first, a small rebase of this PR removes any duplicated condition around _copy_reasoning_content_for_api. If this merges first, #15228 can follow up unchanged.

References

Changed files

  • run_agent.py (modified, +112/-0)
  • tests/run_agent/test_kilo_deepseek_thinking.py (added, +287/-0)

PR #15325: fix(deepseek): inject empty reasoning_content on replay for OpenRouter DeepSeek

Description (problem / solution / changelog)

DeepSeek v4 in thinking mode 400s on multi-turn replay when any assistant message in history lacks reasoning_content:

HTTP 400: The reasoning_content in the thinking mode must be passed back to the API.

Hits three paths:

  1. Compressed histories (compressor synthesizes assistant messages without the field).
  2. Sessions persisted before thinking-mode support.
  3. The _handle_max_iterations summary turn, which builds its own api_messages and was missing the _copy_reasoning_content_for_api call.

This PR covers OpenRouter-routed DeepSeek (deepseek/*) — #15228 handles direct api.deepseek.com; they co-exist.

Fix

  • run_agent.py::_copy_reasoning_content_for_api — add a DeepSeek branch that injects reasoning_content="" as a placeholder. Detection mirrors the Kimi branch's shape: host is openrouter.ai with a deepseek/ model slug, OR host is api.deepseek.com. Deliberately scoped — a bare "deepseek" in model substring would wrongly fire on Bedrock, NIM, and third-party hosts we haven't validated.
  • run_agent.py::_handle_max_iterations — missing _copy_reasoning_content_for_api call in the summary-turn api_messages builder.
  • isinstance(dict) guard on reasoning_config mirrors line 7342.

Tests

New file tests/run_agent/test_deepseek_reasoning_content.py, 12 cases:

  • Happy path (enabled injects, disabled skips, non-deepseek skips)
  • Real reasoning wins over the default
  • reasoning_config variants (None, missing enabled, non-dict)
  • tool_calls turn (key divergence from Kimi branch — #15228)
  • Direct api.deepseek.com path
  • Regression: Bedrock deepseek.v3.2 + NIM deepseek-ai/deepseek-v3.2 must NOT be injected

Full suite: 994 passed.

Refs

  • Covers OpenRouter side of #15213
  • Complements #15228 (direct API)
  • Supersedes #14973 on modern SDKs (openai 2.x + pydantic 2.x with extra='allow' already exposes model_extra via __getattr__)

Tested on

macOS 15 · Python 3.11.15 · openai 2.30.0 · pydantic 2.12.5 · live OpenRouter DeepSeek V4 Flash traffic, no 400s after patch.


Three commits on the branch for reviewability — squash at merge is fine.

Changed files

  • run_agent.py (modified, +37/-0)
  • tests/run_agent/test_deepseek_reasoning_content.py (added, +231/-0)

PR #15407: fix: DeepSeek V4 thinking mode reasoning_content echo on tool-call messages

Description (problem / solution / changelog)

Summary

DeepSeek V4 sessions with tool calls no longer die with 400 reasoning_content must be passed back. Fixes the creation path (new sessions are not poisoned) and the replay path (already-poisoned sessions recover).

Salvages @chen1749144759's #15354 with detection logic consolidated into helpers and a new regression test.

Root cause

DeepSeek V4 thinking mode requires reasoning_content on every assistant tool-call turn. Hermes had a Kimi-specific fallback in _copy_reasoning_content_for_api, but no DeepSeek coverage at creation time (_build_assistant_message) or replay time. Sessions got poisoned in state.db and every subsequent replay hit HTTP 400.

Changes

  • run_agent.py:
    • _build_assistant_message pins reasoning_content="" on new tool-call turns when DeepSeek detected (prevents future poisoning).
    • _copy_reasoning_content_for_api padding now covers DeepSeek too (fixes poisoned history).
    • Extracted _needs_kimi_tool_reasoning() + _needs_deepseek_tool_reasoning() helpers — single source of truth, used by both the creation and replay paths.
    • Added missing _copy_reasoning_content_for_api() call in _handle_max_iterations() flush path (latent bug; was missing for Kimi too).
  • tests/run_agent/test_deepseek_reasoning_content_echo.py: 21 tests covering all 3 DeepSeek signals (provider/model/host), poisoned replay, creation path, Kimi regression.
  • scripts/release.py: AUTHOR_MAP entry for @chen1749144759.

Detection signals (DeepSeek)

  • provider == "deepseek" (native)
  • "deepseek" in model (custom-provider setups using deepseek model names)
  • base_url host matches api.deepseek.com

Validation

BeforeAfter
New DeepSeek tool-call messagesPersisted without reasoning_content → poisonedPinned reasoning_content="" at creation
Replay of poisoned historyHTTP 400 on next turnreasoning_content="" injected defensively, request succeeds
Kimi / MoonshotUnchanged (kimi-specific block preserved via _needs_kimi_tool_reasoning())Unchanged
Test suite21/21 targeted pass; 1046/1047 tests/run_agent/ pass (1 pre-existing unrelated failure)

Closes #15250, #15353. Supersedes #15228, #15354. Thanks @ruxme and @chen1749144759.

Changed files

  • run_agent.py (modified, +44/-7)
  • scripts/release.py (modified, +1/-0)
  • tests/run_agent/test_deepseek_reasoning_content_echo.py (added, +213/-0)

PR #15354: fix: add DeepSeek reasoning_content echo for tool-call messages (fixes #15353)

Description (problem / solution / changelog)

Summary

DeepSeek V4 thinking mode requires reasoning_content on every assistant message that includes tool_calls. When missing, replay causes HTTP 400.

Closes #15353 Related: #14938 #14933 #15213

Changes

1. Merge DeepSeek into needs_tool_reasoning_echo check

In _copy_reasoning_content_for_api(), replaced the Kimi-only detection with a combined check covering:

  • provider == "deepseek"
  • "deepseek" in model (case-insensitive)
  • api.deepseek.com base URL (custom provider)

This handles already-poisoned persisted sessions by injecting empty reasoning_content on replay.

2. Store reasoning_content on new tool-call messages

Added _needs_deepseek_tool_reasoning() helper method, wired into _build_assistant_message(). When a DeepSeek tool-call message is created without reasoning text (common for streaming tool-only turns), stores reasoning_content="" instead of omitting the field. Prevents future session poisoning at the source.

3. Fix _handle_max_iterations path

Added missing call to _copy_reasoning_content_for_api() in the max-iterations flush path. Previously only the main loop and flush_memories() had this call.

Test Plan

  • Verified in state.db: new tool-call messages store reasoning_content
  • Previously poisoned messages handled by replay fix
  • Tested on Rocky Linux 9.7 with deepseek-v4-pro via custom provider

Diff

1 file changed: run_agent.py (+30, -3)

Changed files

  • run_agent.py (modified, +30/-3)

PR #15478: fix: DeepSeek/Kimi thinking mode requires reasoning_content on ALL assistant messages

Description (problem / solution / changelog)

Problem

DeepSeek V4 thinking mode requires reasoning_content on every assistant message, not just tool-call turns. The existing fix (#15250) only covered the tool-call path.

When an assistant message is a plain text reply (no tool_calls) and reasoning is empty, _copy_reasoning_content_for_api skips padding entirely, causing DeepSeek to reject the next request with:

The reasoning_content in the thinking mode must be passed back to the API.

Fix

Remove the source_msg.get("tool_calls") and guard in _copy_reasoning_content_for_api so all DeepSeek/Kimi assistant messages get reasoning_content="" when needed.

Changes

  • run_agent.py: broaden condition from tool_calls + provider to just provider
  • test_deepseek_reasoning_content_echo.py: update test to expect padding on plain assistant turns

Verification

pytest tests/run_agent/test_deepseek_reasoning_content_echo.py -v — 21/21 passed.

Fixes #15213

Changed files

  • run_agent.py (modified, +1/-1)
  • tests/run_agent/test_deepseek_reasoning_content_echo.py (modified, +3/-3)

PR #15476: fix(deepseek): V4 reasoning_content consistency backfill

Description (problem / solution / changelog)

Problem

DeepSeek V4 models (deepseek-v4-pro, deepseek-v4-flash) require all assistant messages in the conversation history to have a reasoning_content field once any turn has produced reasoning. Mixing assistant messages with and without reasoning_content triggers HTTP 400 from the DeepSeek API.

Relation to Recent Upstream Fixes

Commits 93a2d6b3 and d58b305a (merged to main Apr 24–25) added _copy_reasoning_content_for_api() and _needs_deepseek_tool_reasoning() to protect tool-call assistant messages (#15250). This is excellent progress.

However, the upstream fix only covers assistant messages that contain tool_calls. Plain assistant turns (e.g., a simple acknowledgment like "Okay, let me check that") without tool_calls are not backfilled. In a long conversation where:

  1. Turn 2: assistant produces reasoning + tool calls → has reasoning_content
  2. Turn 4: assistant replies without reasoning or tool calls → no reasoning_content
  3. The API request contains a mix

DeepSeek V4 still rejects with HTTP 400.

This PR

This PR complements the upstream tool-call fixes by extending protection to all assistant messages:

  • Add _needs_reasoning_backfill(): detects when any assistant message in the history has reasoning (provider-scoped, excludes legacy deepseek-reasoner)
  • In three API message build paths, backfill empty "" reasoning_content for assistant messages that lack reasoning when backfill is needed:
    • Main conversation loop
    • Memory flush path
    • _handle_max_iterations summary path
  • Each backfill is applied after _copy_reasoning_content_for_api() so we don't interfere with existing Kimi/DeepSeek tool-call logic

Tests

10 regression tests in tests/agent/test_deepseek_v4_reasoning.py:

  • 5 tests for _needs_reasoning_backfill detection
  • 5 tests for reasoning_content injection across all three code paths

All passing on latest main.

Changed files

  • run_agent.py (modified, +31/-0)
  • tests/agent/test_deepseek_v4_reasoning.py (added, +201/-0)

Code Example

Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}

---

model:
  default: deepseek-v4-flash
  provider: deepseek
  base_url: https://api.deepseek.com/v1
agent:
  reasoning_effort: medium

---

2026-04-24 15:57:19 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
2026-04-24 15:58:51 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
2026-04-24 16:03:58 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}

---

select id, session_id, length(content), length(reasoning), length(reasoning_content), length(tool_calls)
from messages
where role='assistant'
  and tool_calls is not null
  and (reasoning_content is null or reasoning_content='')
order by id desc limit 20;

---

273|session-redacted|0|||632
232|session-redacted|0|||636

---

if kimi_requires_reasoning and source_msg.get("tool_calls"):
    api_msg["reasoning_content"] = ""

---

provider = (self.provider or "").lower()
model = (self.model or "").lower()
needs_tool_reasoning_echo = (
    provider in {"kimi-coding", "kimi-coding-cn", "deepseek"}
    or "deepseek" in model
    or base_url_host_matches(self.base_url, "api.kimi.com")
    or base_url_host_matches(self.base_url, "moonshot.ai")
    or base_url_host_matches(self.base_url, "moonshot.cn")
    or base_url_host_matches(self.base_url, "api.deepseek.com")
)
if needs_tool_reasoning_echo and source_msg.get("tool_calls"):
    api_msg["reasoning_content"] = ""

---

tests/run_agent/test_deepseek_reasoning_content_echo.py

---

venv/bin/python -m pytest tests/run_agent/test_deepseek_reasoning_content_echo.py -q
3 passed in 4.04s
RAW_BUFFERClick to expand / collapse

Bug Description

DeepSeek V4 Flash thinking mode can poison a Discord gateway session when an assistant message with tool_calls is persisted without reasoning_content. Subsequent turns replay that historical assistant tool-call message to DeepSeek without the required reasoning_content field and fail with HTTP 400:

Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}

This is related to #14938 / #14933 and adjacent to #15213, but the observed path here is the Discord gateway + persisted session replay, not cron/auxiliary.

Environment

  • Hermes repo: NousResearch/hermes-agent
  • Platform: Discord gateway
  • Provider: deepseek
  • Model: deepseek-v4-flash
  • Base URL: https://api.deepseek.com/v1
  • Thinking mode: DeepSeek V4 default enabled
  • OS: Ubuntu 24.04
  • Python: 3.11

Relevant config:

model:
  default: deepseek-v4-flash
  provider: deepseek
  base_url: https://api.deepseek.com/v1
agent:
  reasoning_effort: medium

Evidence

Gateway logs show repeated non-retryable 400s:

2026-04-24 15:57:19 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
2026-04-24 15:58:51 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
2026-04-24 16:03:58 ERROR [session-redacted] root: Non-retryable client error: Error code: 400 - {'error': {'message': 'The `reasoning_content` in the thinking mode must be passed back to the API.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}

Inspecting ~/.hermes/state.db found assistant messages with tool_calls but no stored reasoning_content:

select id, session_id, length(content), length(reasoning), length(reasoning_content), length(tool_calls)
from messages
where role='assistant'
  and tool_calls is not null
  and (reasoning_content is null or reasoning_content='')
order by id desc limit 20;

Result:

273|session-redacted|0|||632
232|session-redacted|0|||636

So the failed sessions contained assistant tool-call turns where the provider-required reasoning_content field was absent. Once those messages are in history, later turns are effectively poisoned: replaying the session to DeepSeek violates the documented thinking-mode tool-call requirement.

DeepSeek Documentation

DeepSeek thinking mode docs state that if there is a tool call between two user messages, the intermediate assistant message's reasoning_content must be included in all subsequent user interaction rounds:

https://api-docs.deepseek.com/zh-cn/guides/thinking_mode

Relevant rule (translated/paraphrased):

  • If no tool call occurred between two user messages, reasoning_content does not need to be included in later context.
  • If a tool call occurred between two user messages, assistant reasoning_content must participate in context assembly and must be passed back to the API in later rounds.

Expected Behavior

Hermes should either:

  1. Always persist and replay DeepSeek assistant reasoning_content for tool-call turns, or
  2. If a historical DeepSeek assistant message has tool_calls but missing reasoning_content, include an empty provider-facing reasoning_content: "" as a defensive compatibility fallback during API replay.

This prevents already-poisoned persisted sessions from failing forever.

Actual Behavior

For the affected Discord sessions, Hermes replayed assistant tool-call messages without reasoning_content, and DeepSeek rejected the next request with HTTP 400.

Minimal Root Cause Hypothesis

run_agent.py::_copy_reasoning_content_for_api() already has a defensive fallback for Kimi/Moonshot-like providers:

if kimi_requires_reasoning and source_msg.get("tool_calls"):
    api_msg["reasoning_content"] = ""

DeepSeek V4 official API has the same requirement for thinking-mode tool-call messages. It should be included in this provider-specific fallback as well.

Local Patch Tested

A local patch that fixes the poisoned-session case:

provider = (self.provider or "").lower()
model = (self.model or "").lower()
needs_tool_reasoning_echo = (
    provider in {"kimi-coding", "kimi-coding-cn", "deepseek"}
    or "deepseek" in model
    or base_url_host_matches(self.base_url, "api.kimi.com")
    or base_url_host_matches(self.base_url, "moonshot.ai")
    or base_url_host_matches(self.base_url, "moonshot.cn")
    or base_url_host_matches(self.base_url, "api.deepseek.com")
)
if needs_tool_reasoning_echo and source_msg.get("tool_calls"):
    api_msg["reasoning_content"] = ""

Regression test added locally:

tests/run_agent/test_deepseek_reasoning_content_echo.py

Test result:

venv/bin/python -m pytest tests/run_agent/test_deepseek_reasoning_content_echo.py -q
3 passed in 4.04s

Related Issues

  • #14938 — DeepSeek V4 Flash tool call fails with reasoning_content error
  • #14933 — DeepSeek V4 thinking mode fails with reasoning_content error
  • #15213 — DeepSeek V4 Pro cron/auxiliary path reasoning_content passthrough issue
  • Factory-AI/factory#1018 — same DeepSeek V4 thinking mode + tool call error in another agent
  • anomalyco/opencode#24130 — same DeepSeek V4 reasoning_content/interleaved issue in OpenCode
  • openclaw/openclaw#71169 — same DeepSeek V4 multi-turn reasoning_content replay error

Are you willing to submit a PR?

Yes, I can submit the local patch as a PR if maintainers agree this fallback should live in _copy_reasoning_content_for_api() rather than a lower-level DeepSeek transport adapter.

extent analysis

TL;DR

The most likely fix is to include a defensive compatibility fallback in _copy_reasoning_content_for_api() to handle DeepSeek V4 Flash tool-call messages without reasoning_content.

Guidance

  • Review the local patch provided in the issue to ensure it correctly handles the reasoning_content fallback for DeepSeek V4 Flash tool-call messages.
  • Verify that the needs_tool_reasoning_echo condition correctly identifies DeepSeek V4 Flash as a provider requiring reasoning_content echo.
  • Test the patch with the provided regression test test_deepseek_reasoning_content_echo.py to ensure it fixes the poisoned-session issue.
  • Consider submitting the local patch as a PR if maintainers agree on the implementation.

Example

The local patch provided in the issue includes the following code:

provider = (self.provider or "").lower()
model = (self.model or "").lower()
needs_tool_reasoning_echo = (
    provider in {"kimi-coding", "kimi-coding-cn", "deepseek"}
    or "deepseek" in model
    or base_url_host_matches(self.base_url, "api.kimi.com")
    or base_url_host_matches(self.base_url, "moonshot.ai")
    or base_url_host_matches(self.base_url, "moonshot.cn")
    or base_url_host_matches(self.base_url, "api.deepseek.com")
)
if needs_tool_reasoning_echo and source_msg.get("tool_calls"):
    api_msg["reasoning_content"] = ""

This code checks if the provider or model requires reasoning_content echo and sets an empty reasoning_content field if necessary.

Notes

The issue is specific to DeepSeek V4 Flash and the Discord gateway, so the fix may not apply to other providers or platforms.

Recommendation

Apply the workaround by including the defensive compatibility fallback in _copy_reasoning_content_for_api() to handle DeepSeek V4 Flash tool-call messages

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: DeepSeek V4 Flash Discord session poisoned when tool-call assistant lacks reasoning_content [6 pull requests, 1 participants]