fix(providers): preserve all reasoning_details types for OpenRouter models

OpenRouter models like Kimi K2.5 return reasoning_details with type
reasoning.text at message level. The pi-ai library only handled
reasoning.encrypted type. This patch stores all reasoning_details
and passes them back in subsequent requests.

Fixes multi-turn tool calls with Kimi K2.5 and similar models.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kiranjd 2026-01-27 21:43:41 +05:30
parent 6aeb79e0db
commit 7b3d5739da
3 changed files with 71 additions and 5 deletions

View File

@ -246,6 +246,9 @@
"@sinclair/typebox": "0.34.47",
"hono": "4.11.4",
"tar": "7.5.4"
},
"patchedDependencies": {
"@mariozechner/pi-ai@0.49.3": "patches/@mariozechner__pi-ai@0.49.3.patch"
}
},
"vitest": {

View File

@ -0,0 +1,58 @@
diff --git a/dist/providers/openai-completions.js b/dist/providers/openai-completions.js
index c4b291d86ce40b2df319c439263d16d67592d22e..449da02d0d2c85309979e392909df5d3fb2ad083 100644
--- a/dist/providers/openai-completions.js
+++ b/dist/providers/openai-completions.js
@@ -228,7 +228,13 @@ export const streamOpenAICompletions = (model, context, options) => {
}
const reasoningDetails = choice.delta.reasoning_details;
if (reasoningDetails && Array.isArray(reasoningDetails)) {
+ // Store ALL reasoning_details for OpenRouter compatibility (not just encrypted)
+ if (!output._rawReasoningDetails) {
+ output._rawReasoningDetails = [];
+ }
for (const detail of reasoningDetails) {
+ output._rawReasoningDetails.push(detail);
+ // Also handle encrypted type tied to tool calls (existing behavior)
if (detail.type === "reasoning.encrypted" && detail.id && detail.data) {
const matchingToolCall = output.content.find((b) => b.type === "toolCall" && b.id === detail.id);
if (matchingToolCall) {
@@ -500,19 +506,27 @@ function convertMessages(model, context, compat) {
arguments: JSON.stringify(tc.arguments),
},
}));
- const reasoningDetails = toolCalls
- .filter((tc) => tc.thoughtSignature)
- .map((tc) => {
- try {
- return JSON.parse(tc.thoughtSignature);
- }
- catch {
- return null;
+ // First check for raw reasoning_details stored on the message (OpenRouter models like Kimi)
+ const rawDetails = msg._rawReasoningDetails;
+ if (rawDetails && Array.isArray(rawDetails) && rawDetails.length > 0) {
+ assistantMsg.reasoning_details = rawDetails;
+ }
+ else {
+ // Fall back to extracting from tool call thoughtSignatures (encrypted type)
+ const reasoningDetails = toolCalls
+ .filter((tc) => tc.thoughtSignature)
+ .map((tc) => {
+ try {
+ return JSON.parse(tc.thoughtSignature);
+ }
+ catch {
+ return null;
+ }
+ })
+ .filter(Boolean);
+ if (reasoningDetails.length > 0) {
+ assistantMsg.reasoning_details = reasoningDetails;
}
- })
- .filter(Boolean);
- if (reasoningDetails.length > 0) {
- assistantMsg.reasoning_details = reasoningDetails;
}
}
// Skip assistant messages that have no content and no tool calls.

15
pnpm-lock.yaml generated
View File

@ -9,6 +9,11 @@ overrides:
hono: 4.11.4
tar: 7.5.4
patchedDependencies:
'@mariozechner/pi-ai@0.49.3':
hash: 8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32
path: patches/@mariozechner__pi-ai@0.49.3.patch
importers:
.:
@ -45,7 +50,7 @@ importers:
version: 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai':
specifier: 0.49.3
version: 0.49.3(ws@8.19.0)(zod@4.3.6)
version: 0.49.3(patch_hash=8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32)(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-coding-agent':
specifier: 0.49.3
version: 0.49.3(ws@8.19.0)(zod@4.3.6)
@ -6989,7 +6994,7 @@ snapshots:
'@mariozechner/pi-agent-core@0.49.3(ws@8.19.0)(zod@4.3.6)':
dependencies:
'@mariozechner/pi-ai': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai': 0.49.3(patch_hash=8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32)(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-tui': 0.49.3
transitivePeerDependencies:
- '@modelcontextprotocol/sdk'
@ -7000,7 +7005,7 @@ snapshots:
- ws
- zod
'@mariozechner/pi-ai@0.49.3(ws@8.19.0)(zod@4.3.6)':
'@mariozechner/pi-ai@0.49.3(patch_hash=8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32)(ws@8.19.0)(zod@4.3.6)':
dependencies:
'@anthropic-ai/sdk': 0.71.2(zod@4.3.6)
'@aws-sdk/client-bedrock-runtime': 3.972.0
@ -7027,7 +7032,7 @@ snapshots:
'@mariozechner/clipboard': 0.3.0
'@mariozechner/jiti': 2.6.5
'@mariozechner/pi-agent-core': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai': 0.49.3(patch_hash=8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32)(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-tui': 0.49.3
'@silvia-odwyer/photon-node': 0.3.4
chalk: 5.6.2
@ -9104,7 +9109,7 @@ snapshots:
'@line/bot-sdk': 10.6.0
'@lydell/node-pty': 1.2.0-beta.3
'@mariozechner/pi-agent-core': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-ai': 0.49.3(patch_hash=8fada8af40beb6c2780b3adec72505288272a5df0ec6227b710caef6afb1dc32)(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-coding-agent': 0.49.3(ws@8.19.0)(zod@4.3.6)
'@mariozechner/pi-tui': 0.49.3
'@mozilla/readability': 0.6.0