@oh-my-pi/pi-ai 15.4.1 → 15.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.4.2] - 2026-05-26
6
+
7
+ ### Fixed
8
+
9
+ - Fixed OpenCode Zen `big-pickle` follow-up requests replaying assistant tool-call turns without DeepSeek-required `reasoning_content`, which caused HTTP 400 errors in thinking mode.
10
+
5
11
  ## [15.4.1] - 2026-05-26
6
12
  ### Added
7
13
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "15.4.1",
4
+ "version": "15.4.2",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@anthropic-ai/sdk": "^0.94.0",
45
45
  "@bufbuild/protobuf": "^2.12.0",
46
- "@oh-my-pi/pi-utils": "15.4.1",
46
+ "@oh-my-pi/pi-utils": "15.4.2",
47
47
  "openai": "^6.36.0",
48
48
  "partial-json": "^0.1.7",
49
49
  "zod": "4.4.3"
@@ -74,11 +74,16 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
74
74
  // applies when thinking mode is actually engaged.
75
75
  const lowerId = model.id.toLowerCase();
76
76
  const lowerName = (model.name ?? "").toLowerCase();
77
+ // OpenCode Zen's `big-pickle` is a DeepSeek reasoning alias; the upstream
78
+ // 400s come from DeepSeek and require exact reasoning_content replay.
79
+ const isOpenCodeDeepseekAlias =
80
+ provider === "opencode-zen" && (lowerId === "big-pickle" || lowerName === "big pickle");
77
81
  const isDeepseekFamily =
78
82
  provider === "deepseek" ||
79
83
  baseUrl.includes("deepseek.com") ||
80
84
  lowerId.includes("deepseek") ||
81
- lowerName.includes("deepseek");
85
+ lowerName.includes("deepseek") ||
86
+ isOpenCodeDeepseekAlias;
82
87
  const isDirectDeepseekApi = provider === "deepseek" || baseUrl.includes("api.deepseek.com");
83
88
  const isDirectDeepseekReasoning = isDirectDeepseekApi && isDeepseekFamily && Boolean(model.reasoning);
84
89
  const isNonStandard =
@@ -211,12 +216,14 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
211
216
  reasoningContentField: "reasoning_content",
212
217
  // Backends that 400 follow-up requests when prior assistant tool-call turns lack `reasoning_content`:
213
218
  // - Kimi: documented invariant on its native API.
214
- // - Any reasoning-capable model reached through OpenRouter: DeepSeek V4 Pro and similar enforce
215
- // this server-side whenever the request is in thinking mode. We can't translate Anthropic's
216
- // redacted/encrypted reasoning into DeepSeek's plaintext form, so cross-provider continuations
217
- // rely on a placeholder see `convertMessages` for the placeholder injection.
218
- // - OpenCode-Go and OpenCode-Zen handle reasoning content internally and reject
219
- // `reasoning_content` in client-sent messages exclude them even for Kimi models.
219
+ // - DeepSeek-family reasoning models, including aliased OpenCode Zen models
220
+ // like `big-pickle`, validate exact thinking-mode replay.
221
+ // - Any reasoning-capable model reached through OpenRouter can enforce this
222
+ // server-side whenever the request is in thinking mode. We can't translate
223
+ // Anthropic's redacted/encrypted reasoning into provider-native plaintext,
224
+ // so cross-provider continuations rely on a placeholder.
225
+ // OpenCode Kimi aliases handle reasoning content internally and reject
226
+ // client-sent `reasoning_content`, so exclude only that Kimi-on-OpenCode path.
220
227
  requiresReasoningContentForToolCalls:
221
228
  (isKimiModel && !isOpenCodeProvider) ||
222
229
  (isDeepseekFamily && Boolean(model.reasoning)) ||