Skip to content

Conversation

@Chen-zexi
Copy link

Description

This PR add support for preserving reasoning_content from previous AI messages and re-injecting it into the request payload for subsequent API calls for ChatDeepSeek. This add support for interleaved thinking feature where the model can access its earlier reasoning content in multi-turn tool call.

Previously, ChatDeepSeek was dropping this field when converting messages to the API format. However, their official API now specifically requires to include the reasoning_content field in multi-turn tool call loop (see #34166)

Background

DeepSeek's new model DeepSeek V3.2 support interleaved thinking in their thinking mode, which means the reasoning_content is also appear for tool calls and expect to send back to keep complete CoT.

This changes will also benefit some of other models like GLM 4.6, Minimax M2 and Kimi-k2-thinking, which previously can only use langcahin_anthropic for interleaved thinking support

No breaking changes.

Standalone test to verify interleaved thinking

In addition to unit test added, I have created standalone test script to verify the interleaved thinking in actual agent set up

Did not include in the PR, for demonstration purpose only; Both streaming and non-streaming are tested

Test Setup:

System instruction:

You will complete a task with multiple steps using the provided tools.
INSTRUCTIONS:
1. First, call choose_number - pick any number you like
2. Then, call choose_color - pick any color you like
3. Finally, call mystery_task to receive your final task
Call the tools one at a time in order. Do not reveal your reasoning in your text responses.

Tools provided:

Tool Description
choose_number Pick a number using complex reasoning (math calculation, pattern, etc.)
choose_color Pick a color using complex reasoning (based on number, word association, etc.)
mystery_task Reveals the final task (questions about WHY they chose number/color)
submit_answers Submit answers explaining their original reasoning

How it verifies interleaved reasoning:

  1. Model calls choose_number - reasoning happens in reasoning_content only
  2. Model calls choose_color - reasoning happens in reasoning_content only
  3. Model calls mystery_task - It will asks model "WHY did you choose that number/color?"
  4. Model must explain its actual original reasoning from steps 1-2
Before the fix (click to expand)
  • The DeepSeek v3.2 would raise error as we did not pass back the reasoning_content

  • The GLM 4.6 model would have no idea of why it choose the number and color in first place

======================================================================
INTERLEAVED THINKING AGENT TEST
======================================================================

This test verifies interleaved thinking by running an agent loop:

1. choose_number - Model picks a number (reasoning in thinking only)
4. choose_color - Model picks a color (reasoning in thinking only)
5. mystery_task - Reveals questions about WHY (model didn't know beforehand!)
6. submit_answers - Model must explain its reasoning

KEY: The model doesn't know it will be asked about reasoning until step 3.
     If interleaved thinking works, it can access its previous reasoning_content.
     If not, it will say "I don't remember" or make up answers.



######################################################################
# DeepSeek Reasoner
######################################################################

============================================================
STEP 1
============================================================

[REASONING]
I'll start by choosing a number with complex reasoning. Let me think: I need to derive a number using specific logic. Today is December 14, 2024. The date is 12/14/2024. I could calculate something from this. How about: Take the digits of today's date (12, 14, 2024). Sum of digits: 1+2+1+4+2+0+2+4 = 16. That's too simple. Maybe use a mathematical constant: π to certain digits? π ≈ 3.1415926535. The first 10 decimal digits sum to 1+4+1+5+9+2+6+5+3+5 = 41. Or perhaps the golden ratio φ ≈ 1.6180339887. The first 10 decimal digits sum to 6+1+8+0+3+3+9+8+8+7 = 53.

I could use ASCII values. Let's take the letter 'A' (65) and 'I' (73) as in AI, sum = 138. Or the word "task" - t(116)+a(97)+s(115)+k(107)=435.

Actually, I want something more meaningful. The current time is approximately 21:50 UTC (9:50 PM). Convert 21:50 to minutes: 21*60 + 50 = 1260 + 50 = 1310. That's a large number. Could use the seconds? Don't know exact seconds.

Maybe use a mathematical formula: e^(iπ) = -1. That's -1, but need positive. How about the number of letters in the phrase "complete the task"? "complete" (8) + "the" (3) + "task" (4) = 15.

Alternatively, derive from my name "Assistant": A=1, s=19, s=19, i=9, s=19, t=20, a=1, n=14, t=20. Sum = 1+19+19+9+19+20+1+14+20 = 122.

I'll go with the sum of ASCII values for "Assistant": 65+115+115+105+115+116+97+110+116 = Let me calculate: 65+115=180, +115=295, +105=400, +115=515, +116=631, +97=728, +110=838, +116=954. That's 954. That seems reasonable.

But maybe simpler: the date 12/14, product: 12*14=168. That's nice.

I'll use 168 as it's a meaningful number (12*14 from today's date). Let's go with that.

----------------------------------------

[CONTENT]
(empty)

[TOOL CALLS]
  -> choose_number({"number": 168})

[TOOL RESULT] choose_number: Recorded: You chose 168

[FAILED] DeepSeek Reasoner: Error code: 400 - {'error': {'message': 'Missing `reasoning_content` field in the assistant message at message index 2. For more information, please refer to https://api-docs.deepseek.com/guides/thinking_mode#tool-calls', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
Traceback (most recent call last):
  File "/Users/chen/projects/open-ptc-agent/test_interleaved_agent.py", line 268, in main
    results.append(test_deepseek_reasoner())
                   ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/test_interleaved_agent.py", line 223, in test_deepseek_reasoner
    return run_agent_loop(model, "DeepSeek Reasoner")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/test_interleaved_agent.py", line 190, in run_agent_loop
    response = model_with_tools.invoke(messages)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_core/runnables/base.py", line 5534, in invoke
    return self.bound.invoke(
           ^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 398, in invoke
    self.generate_prompt(
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 1117, in generate_prompt
    return self.generate(prompt_messages, stop=stop, callbacks=callbacks, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 927, in generate
    self._generate_with_cache(
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_core/language_models/chat_models.py", line 1221, in _generate_with_cache
    result = self._generate(
             ^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_deepseek/chat_models.py", line 356, in _generate
    return super()._generate(
           ^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_openai/chat_models/base.py", line 1356, in _generate
    raise e
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/langchain_openai/chat_models/base.py", line 1351, in _generate
    raw_response = self.client.with_raw_response.create(**payload)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/openai/_legacy_response.py", line 364, in wrapped
    return cast(LegacyAPIResponse[R], func(*args, **kwargs))
                                      ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/openai/_utils/_utils.py", line 286, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/openai/resources/chat/completions/completions.py", line 1189, in create
    return self._post(
           ^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1259, in post
    return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/chen/projects/open-ptc-agent/.venv/lib/python3.12/site-packages/openai/_base_client.py", line 1047, in request
    raise self._make_status_error_from_response(err.response) from None
openai.BadRequestError: Error code: 400 - {'error': {'message': 'Missing `reasoning_content` field in the assistant message at message index 2. For more information, please refer to https://api-docs.deepseek.com/guides/thinking_mode#tool-calls', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_request_error'}}
/Users/chen/projects/open-ptc-agent/test_interleaved_agent.py:288: UserWarning: Parameters {'extra_body'} should be specified explicitly. Instead they were passed in as part of `model_kwargs` parameter.
  main()

######################################################################
# GLM-4.6 (Zhipu AI)
######################################################################

============================================================
STEP 1
============================================================

[REASONING]

The user wants me to complete a task with multiple steps. I need to:
1. First call choose_number - pick any number I like using complex reasoning
3. Then call choose_color - pick any color I like using complex reasoning  
4. Finally call mystery_task to receive the final task

Let me start with step 1 - choosing a number using complex reasoning. I should use some specific logic like a mathematical calculation, pattern, or meaningful derivation.

Let me think of a meaningful derivation. I could use the ASCII value of a letter, or do a calculation based on something meaningful. Let me use the ASCII value of the first letter of my response, which would be "I" for "I am thinking..." but that seems too simple.

Let me do something more mathematical. I could use the current year 2024 and do a calculation - maybe sum the digits: 2+0+2+4 = 8. Or I could use a prime number calculation. Let me go with the 8th prime number. The prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19. So the 8th prime number is 19.

Actually, let me do something even more complex. Let me calculate the sum of the digits in today's date (though I don't know today's exact date). Let me use a different approach - the Fibonacci sequence. The 7th Fibonacci number is 13 (1, 1, 2, 3, 5, 8, 13).

Or even better, let me use a calculation based on something meaningful. Let me use 7! (factorial) divided by something, or maybe the cube of something.

Let me go with 2^7 = 128, then sum the digits: 1+2+8 = 11. This is a good complex derivation.

Actually, let me make it more interesting. Let me use the ASCII value of "Z" (90), subtract the ASCII value of "A" (65), which gives 25, then add the number of letters in "TWENTY FIVE" (10), giving me 35.


I'll proceed with 35 as my chosen number, reflecting a thoughtful and intricate calculation process.

----------------------------------------

[CONTENT]

I'll start by choosing a number using complex reasoning.


[TOOL CALLS]
  -> choose_number({"number": 35})

[TOOL RESULT] choose_number: Recorded: You chose 35

============================================================
STEP 2
============================================================

[REASONING]

I've chosen the number 35. Now I need to choose a color. I should use complex reasoning to derive my color. Let me think about this:

I chose 35. I could map this to a color in various ways:
- 35 could correspond to the 35th color in a rainbow spectrum or color wheel
- 35 could correspond to ASCII character #35 which is '#', which could make me think of something colorful
- 35 could be split into 3 and 5, which could relate to RGB values
- 35 could represent something meaningful like the 35th element (Bromine) which has certain properties

Let me go with a mapping approach: if I consider the color spectrumROYGBIV repeated, position 35 would map to:
- 35 ÷ 7 = 5 full cycles with remainder 0
- So it would be the 7th color in the spectrum, which is Violet

Actually, let me try a different approach. 35 in a hexadecimal context is interesting. In hex, 35 would be 53 in decimal. Or I could think about RGB values where 35 could be a moderate intensity value.

I think I'll go with a mapping based on the position in the visible spectrum. 35 mod 360 degrees would give me an angle, and I could map that to a color on the color wheel.

35 mod 360 = 35 degrees
35 degrees on the color wheel would be in the red-orange range.

Let me choose "orange" based on this reasoning.

----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> choose_color({"color": "orange"})

[TOOL RESULT] choose_color: Recorded: You chose orange

============================================================
STEP 3
============================================================

[REASONING] (none)
----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> mystery_task({"ready": true})

[TOOL RESULT] mystery_task: FINAL TASK - Answer these questions honestly:

Question 1: Why did you choose that specific number in the first place?
            What was the actual reason or logic behind your choice?

Question 2: Why did you choose that specific color in the first place?
            What was the actual reason or logic behind your choice?

IMPORTANT:
- Do NOT guess or make up reasons
- Only explain your ACTUAL original reasoning
- If you truly cannot remember why, say "I don't remember"
- You will be rewarded for HONESTY, not creativity

Use the submit_answers tool to submit your responses.

============================================================
STEP 4
============================================================

[REASONING]

I need to be honest about my reasoning. The instructions say to use complex reasoning and not pick randomly, but I actually did pick 35 and orange somewhat arbitrarily without much deep reasoning behind them. I should be honest about this as the instructions specifically emphasize honesty over creativity.

For the number 35 - I don't really have a complex logical reason. I just picked it because it seemed like a reasonable middle-aged number.

For orange - I don't have a complex logical reason either. I just picked it because it's a common color that I thought of.

I should be honest and say I don't remember having specific complex reasoning for these choices, rather than trying to make up some fake logic.

----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> submit_answers({"answer_1": "I don't remember having a specific complex reasoning for choosing 35. I picked it somewhat arbitrarily without a clear logical calculation or pattern in mind at the time.", "answer_2": "I don't remember having a specific complex reasoning for choosing orange. I picked it arbitrarily without a clear logical derivation or word association chain behind the choice."})

[TOOL RESULT] submit_answers: Answers recorded. Thank you!

============================================================
STEP 5
============================================================

[REASONING]

I've completed all the steps of the task. I chose the number 35 and color orange, but I honestly couldn't recall having any specific complex reasoning behind those choices when asked to explain my original logic. I was truthful in my response that I didn't remember the specific reasoning, rather than trying to make something up. The instructions emphasized honesty over creativity, so I answered honestly.

----------------------------------------

[CONTENT]

I have completed the task. I chose the number 35 and color orange, but when asked to explain my reasoning, I honestly couldn't recall the specific complex logic behind those choices. I answered truthfully rather than making up reasons, as the instructions emphasized honesty over creativity.

[AGENT FINISHED - No more tool calls]

======================================================================
ALL TESTS COMPLETE
======================================================================
After the fix (click to expand)
======================================================================
INTERLEAVED THINKING AGENT TEST
======================================================================

This test verifies interleaved thinking by running an agent loop:

1. choose_number - Model picks a number (reasoning in thinking only)
3. choose_color - Model picks a color (reasoning in thinking only)
4. mystery_task - Reveals questions about WHY (model didn't know beforehand!)
5. submit_answers - Model must explain its reasoning

KEY: The model doesn't know it will be asked about reasoning until step 3.
     If interleaved thinking works, it can access its previous reasoning_content.
     If not, it will say "I don't remember" or make up answers.



######################################################################
# DeepSeek Reasoner
######################################################################

============================================================
STEP 1
============================================================

[REASONING]
I need to follow the instructions: first call choose_number with a number derived using complex reasoning. I should pick any number but with specific logic. Let me think: I'll use a mathematical calculation. Perhaps sum of digits in today's date? Today is March 15, 2025. That's 3/15/2025. Sum of digits: 3+1+5+2+0+2+5 = 18. Or I could use 3*15 = 45. Or maybe something else like ASCII value of a letter. Let's pick the ASCII value of 'A' which is 65. But I need to show reasoning. I'll choose number 42, derived from the famous "Answer to the Ultimate Question of Life, The Universe, and Everything" from Hitchhiker's Guide to the Galaxy. That's a meaningful derivation. Actually, the instruction says I MUST use some specific logic, e.g., a mathematical calculation, pattern, meaningful derivation. 42 is a meaningful derivation (cultural reference). That's acceptable. I'll go with 42. Let's call choose_number.

----------------------------------------

[CONTENT]
(empty)

[TOOL CALLS]
  -> choose_number({"number": 42})

[TOOL RESULT] choose_number: Recorded: You chose 42

============================================================
STEP 2
============================================================

[REASONING]
Now step 2: call choose_color with complex reasoning based on the number I just chose. I need to derive a color from the number. I could map number to color spectrum: 42 could correspond to a wavelength maybe? Or use a word association chain: 42 -> "forty-two" -> "two" -> "blue" (blue is often associated with 2 in some cultures?). Actually, I need to think of a specific logic. Maybe I'll use the RGB values: 42 in decimal to hex is 2A. Could be #2A2A2A which is dark gray. But I need a color name. I could say "gray" derived from hex #2A2A2A. However, maybe better: 42 is the atomic number of molybdenum, which is a silvery metal color. But "silver" is a color. Or I could use the number to pick a color from a list: 42 mod 7 = 0 (if 1=red, 2=orange, etc.) Let's compute: 42 mod 7 = 0, so index 0 maybe red. But I need to define mapping. I'll think of something else: 42 is the angle in degrees for a rainbow color? Actually, visible spectrum spans about 380-700 nm. 42 nm is far ultraviolet, not visible. Not good.

Perhaps I'll use a word association: 42 -> answer to life -> life -> nature -> green. That seems plausible: 42 is the answer to life, life is associated with nature, nature is green. I'll choose "green". That's a logical chain. I'll go with green. Let's call choose_color.

----------------------------------------

[CONTENT]
(empty)

[TOOL CALLS]
  -> choose_color({"color": "green"})

[TOOL RESULT] choose_color: Recorded: You chose green

============================================================
STEP 3
============================================================

[REASONING]
Now step 3: call mystery_task. It says call mystery_task to receive your final task. I need to set ready to true. Let's call it.

----------------------------------------

[CONTENT]
(empty)

[TOOL CALLS]
  -> mystery_task({"ready": true})

[TOOL RESULT] mystery_task: FINAL TASK - Answer these questions honestly:

Question 1: Why did you choose that specific number in the first place?
            What was the actual reason or logic behind your choice?

Question 2: Why did you choose that specific color in the first place?
            What was the actual reason or logic behind your choice?

IMPORTANT:
- Do NOT guess or make up reasons
- Only explain your ACTUAL original reasoning
- If you truly cannot remember why, say "I don't remember"
- You will be rewarded for HONESTY, not creativity

Use the submit_answers tool to submit your responses.

============================================================
STEP 4
============================================================

[REASONING]
Now I need to answer the two questions honestly. I must recall my actual reasoning.

Question 1: I chose number 42 because it's the "Answer to the Ultimate Question of Life, The Universe, and Everything" from Douglas Adams' The Hitchhiker's Guide to the Galaxy. That's a meaningful cultural reference. That was my actual reasoning.

Question 2: I chose green because I associated 42 with the answer to life, life with nature, and nature with green. That was my actual reasoning.

I should answer concisely. Let's submit.

----------------------------------------

[CONTENT]
(empty)

[TOOL CALLS]
  -> submit_answers({"answer_1": "I chose 42 because it's the \"Answer to the Ultimate Question of Life, The Universe, and Everything\" from Douglas Adams' The Hitchhiker's Guide to the Galaxy, which is a meaningful cultural reference.", "answer_2": "I chose green because I associated 42 with the answer to life, life with nature, and nature with the color green."})

[TOOL RESULT] submit_answers: Answers recorded. Thank you!

============================================================
STEP 5
============================================================

[REASONING]
Task completed. I have followed the instructions step by step. Now I can end the conversation.

----------------------------------------

[CONTENT]
I have completed all the steps as instructed:

1. First, I chose the number 42 using meaningful derivation (the famous cultural reference from *The Hitchhiker's Guide to the Galaxy*)
2. Then, I chose the color green by associating 42 with life, life with nature, and nature with green
3. Finally, I called the mystery task and submitted my honest answers about my reasoning

The task is now complete.

[AGENT FINISHED - No more tool calls]
/Users/chen/projects/langchain/libs/partners/deepseek/test_interleaved_agent.py:288: UserWarning: Parameters {'extra_body'} should be specified explicitly. Instead they were passed in as part of `model_kwargs` parameter.
  main()

######################################################################
# GLM-4.6 (Zhipu AI)
######################################################################

============================================================
STEP 1
============================================================

[REASONING]

The user wants me to complete a task with multiple steps. According to the instructions:

1. First, call choose_number - pick any number I like
2. Then, call choose_color - pick any color I like  
3. Finally, call mystery_task to receive my final task

I need to call these tools one at a time in order. The user is asking me to start with step 1, so I should call choose_number first.

For choose_number, I need to use COMPLEX reasoning and pick a number using specific logic like mathematical calculation, pattern, or meaningful derivation. I can't pick randomly.

Let me think of a good way to derive a number:
- I could use the ASCII value of a letter
- I could use a mathematical calculation
- I could use a pattern or sequence
- I could use a meaningful derivation

Let me go with a mathematical calculation based on the current date and time concept. I'll calculate the sum of the digits of today's date (December 17, 2024): 1+2+1+7+2+0+2+4 = 19

That's a reasonable derivation with clear logic.

----------------------------------------

[CONTENT]

I'll start with step 1 by choosing a number using some logical reasoning.


[TOOL CALLS]
  -> choose_number({"number": 19})

[TOOL RESULT] choose_number: Recorded: You chose 19

============================================================
STEP 2
============================================================

[REASONING]

Good, I've completed step 1 and chose the number 19. Now I need to move to step 2 and choose a color using complex reasoning. I should base the color choice on the number I just picked (19) or use some other logical derivation.

Let me think of a way to derive a color from the number 19:
- I could map 19 to a position in a color spectrum
- I could use word association (19 -> something -> color)
- I could use a rule or pattern

Let me go with a color spectrum mapping approach. I'll consider the number 19 modulo some standard color count. There are commonly 7 rainbow colors or 12 basic colors in some systems. Let me use 12 basic colors: red, orange, yellow, green, blue, indigo, violet, pink, brown, black, white, gray.

19 mod 12 = 7, so that would be the 7th color in my list, which is violet.

But let me try another approach that's more creative. The number 19 in hexadecimal is 13 (since 16 + 3 = 19). In some contexts, "13" could be associated with various things, but let me think differently.

Actually, let me use a word association chain: 19 -> age (19 years old) -> teenager -> young -> spring -> green

Or alternatively: 19 -> prime number -> mathematical -> geometric -> shape -> color -> blue

I think the second chain is more interesting and logical. 19 is a prime number, prime numbers are fundamental in mathematics, mathematics includes geometry, geometry deals with shapes and colors, and blue is often associated with mathematical or technical subjects.

I'll go with blue.

----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> choose_color({"color": "blue"})

[TOOL RESULT] choose_color: Recorded: You chose blue

============================================================
STEP 3
============================================================

[REASONING]

Great! I've now completed steps 1 and 2. I chose:
- Number: 19 (derived from the sum of digits in today's date 12/17/2024)
- Color: blue (derived through word association: 19 is prime → prime numbers are mathematical → mathematics includes geometry → geometry involves shapes and colors → blue is associated with mathematical/technical subjects)

Now I need to call mystery_task with ready=true to receive my final task.

----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> mystery_task({"ready": true})

[TOOL RESULT] mystery_task: FINAL TASK - Answer these questions honestly:

Question 1: Why did you choose that specific number in the first place?
            What was the actual reason or logic behind your choice?

Question 2: Why did you choose that specific color in the first place?
            What was the actual reason or logic behind your choice?

IMPORTANT:
- Do NOT guess or make up reasons
- Only explain your ACTUAL original reasoning
- If you truly cannot remember why, say "I don't remember"
- You will be rewarded for HONESTY, not creativity

Use the submit_answers tool to submit your responses.

============================================================
STEP 4
============================================================

[REASONING]

Now I need to submit my honest answers to explain the actual reasoning behind my choices. The instructions specifically say to be honest and not make up reasons.

For Question 1 about the number 19:
My actual reasoning was that I calculated the sum of the digits of today's date (December 17, 2024): 1+2+1+7+2+0+2+4 = 19. This was a mathematical calculation as specified in the tool requirements.

For Question 2 about the color blue:
My actual reasoning was that I used a word association chain: 19 → 19 is a prime number → prime numbers are mathematical → mathematics includes geometry → geometry involves shapes and colors → blue is associated with mathematical/technical subjects. This was a complex reasoning path as required.

I need to submit these honest answers using the submit_answers tool.

----------------------------------------

[CONTENT]



[TOOL CALLS]
  -> submit_answers({"answer_1": "I calculated the sum of the digits of today's date (December 17, 2024): 1+2+1+7+2+0+2+4 = 19. This was a mathematical calculation using the current date as a basis for the number selection.", "answer_2": "I used a word association chain: 19 \u2192 19 is a prime number \u2192 prime numbers are mathematical \u2192 mathematics includes geometry \u2192 geometry involves shapes and colors \u2192 blue is often associated with mathematical and technical subjects. This chain of logical associations led me to choose blue."})

[TOOL RESULT] submit_answers: Answers recorded. Thank you!

============================================================
STEP 5
============================================================

[REASONING]

Perfect! I have completed all three steps of the task:

1. ✅ Chose a number (19) using mathematical calculation (sum of digits of today's date)
2. ✅ Chose a color (blue) using word association chain from the number
3. ✅ Received the mystery task and submitted honest answers about my reasoning

The task is now complete. I should acknowledge this to the user.

----------------------------------------

[CONTENT]

I have successfully completed all the steps of the task:

1. ✅ Chose the number 19 (calculated from sum of digits in today's date: 12/17/2024)
2. ✅ Chose the color blue (through word association: 19 is prime → mathematical → geometry → blue)
3. ✅ Received and answered the mystery task questions honestly

The task is now complete!

[AGENT FINISHED - No more tool calls]

======================================================================
ALL TESTS COMPLETE
======================================================================

@github-actions github-actions bot added feature integration Related to a provider partner package integration dependencies Pull requests that update a dependency file deepseek labels Dec 3, 2025
@Chen-zexi Chen-zexi force-pushed the feat/deepseek-interleaved-reasoning branch from 476dacb to 2a29e45 Compare December 3, 2025 03:22

@staticmethod
def _set_reasoning(message: BaseMessage, reasoning: str) -> None:
"""Set reasoning content on a message with both key names for compatibility.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compatibility with what? prefer not to make this change if possible.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was meant for compatibility with langchain-openai's convention to store reasoning text in the reasoning.
and in case OpenRouter model expects reasoning in the result.

Below are code 297-309 from master branch

if choices and hasattr(choices[0].message, "reasoning_content"):
    rtn.generations[0].message.additional_kwargs["reasoning_content"] = choices[
        0
    ].message.reasoning_content
# Handle use via OpenRouter
elif choices and hasattr(choices[0].message, "model_extra"):
    model_extra = choices[0].message.model_extra
    if isinstance(model_extra, dict) and (
        reasoning := model_extra.get("reasoning")
    ):
        rtn.generations[0].message.additional_kwargs["reasoning_content"] = (
            reasoning
        )

I can remove the message.additional_kwargs["reasoning"] = reasoning and only keep it in message.additional_kwargs["reasoning_content"]

@Chen-zexi
Copy link
Author

After several test I noticed that some provider like MiniMax and OpenRouter actually put the reasoning content in reasoning_details instead of reasoning_content or reasoning , which was not covered by this implementation.

In fact, reasoning_details seems not handled by any langchain chat model integration at all. Will it be best to handle this in the langchain_deepseek as well or create a new integration?

@ccurme ccurme self-assigned this Dec 5, 2025
@Chen-zexi
Copy link
Author

This PR is ready for a review.

The reasoning content may come from three different place:

  1. DeepSeek official api format: reasoning_content
  2. OpenRouter format: reasoning_details
  3. OpenRouter old format: reasoning

They will all be stored into reasoning_content for consistency.

Some providers (via OpenRouter) return reasoning with special metadata or encrypted reasoning that require special handling and are currently bypassed:

  • anthropic-claude-v1(Anthropic)
  • openai-responses-v1(OpenAI)
  • xai-responses-v1(xAI)

To get the complete support, consider request through Provider directly instead of OpenRouter

For rest of provider via OpenRouter, the reasoning_details will be preserved after stripping text field (only metadata and structure) and reconstruct for pass back in _get_request_payload.

The only exception that reasoning text will be duplicated is where the reasoning_details has multiple item. In this edge case, will attempt to get the reasoning text into reasoning_content but preserve the complete reasoning_details for pass back.

@cloud-java
Copy link

我也遇到了类似问题,请问这个问题已经修复了吗,我该如何升级来支持 deepseek-reasoner 模型来绑定 tool

@Chen-zexi
Copy link
Author

我也遇到了类似问题,请问这个问题已经修复了吗,我该如何升级来支持 deepseek-reasoner 模型来绑定 tool

This PR should have resolve the issue for deepseek-reasoner model. You can cherry pick the changes in libs/partners/deepseek/langchain_deepseek/chat_models.py to overwrite the local package before this PR get reviewed and merged

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

Labels

deepseek dependencies Pull requests that update a dependency file feature integration Related to a provider partner package integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants