Skip to content

Commit 27186c5

Browse files
fix(core): support reasoning/thinking blocks in StringOutputParser (#10002)
Co-authored-by: Christian Bromann <[email protected]>
1 parent af001da commit 27186c5

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

.changeset/odd-mugs-tease.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@langchain/core": patch
3+
---
4+
5+
fix(core): support reasoning/thinking blocks in StringOutputParser

libs/langchain-core/src/output_parsers/string.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export class StringOutputParser extends BaseTransformOutputParser<string> {
7373
);
7474
}
7575
break;
76+
case "reasoning":
77+
case "thinking":
78+
case "redacted_thinking":
79+
return "";
7680
default:
7781
throw new Error(
7882
`Cannot coerce "${content.type}" message part into a string.`

libs/langchain-core/src/output_parsers/tests/string.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,63 @@ describe("StringOutputParser", () => {
7171
}).rejects.toThrowError();
7272
});
7373
});
74+
75+
test("ignores reasoning blocks and returns only text", async () => {
76+
const parser = new StringOutputParser();
77+
78+
const content: ContentBlock[] = [
79+
{
80+
type: "reasoning",
81+
reasoning: "internal reasoning",
82+
},
83+
{
84+
type: "text",
85+
text: "final answer",
86+
},
87+
];
88+
89+
const msg: BaseMessage = new AIMessage({ content });
90+
const result = await parser.invoke(msg);
91+
92+
expect(result).toEqual("final answer");
93+
});
94+
95+
test("ignores thinking blocks", async () => {
96+
const parser = new StringOutputParser();
97+
98+
const content: ContentBlock[] = [
99+
{
100+
type: "thinking",
101+
thinking: "hidden thoughts",
102+
},
103+
{
104+
type: "text",
105+
text: "visible output",
106+
},
107+
];
108+
109+
const msg: BaseMessage = new AIMessage({ content });
110+
const result = await parser.invoke(msg);
111+
112+
expect(result).toEqual("visible output");
113+
});
114+
115+
test("ignores redacted_thinking blocks", async () => {
116+
const parser = new StringOutputParser();
117+
118+
const content: ContentBlock[] = [
119+
{
120+
type: "redacted_thinking",
121+
redacted_thinking: "redacted",
122+
},
123+
{
124+
type: "text",
125+
text: "answer",
126+
},
127+
];
128+
129+
const msg: BaseMessage = new AIMessage({ content });
130+
const result = await parser.invoke(msg);
131+
132+
expect(result).toEqual("answer");
133+
});

0 commit comments

Comments
 (0)