@gajae-code/ai 0.13.1 → 0.13.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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.13.
|
|
4
|
+
"version": "0.13.2",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
42
42
|
"@bufbuild/protobuf": "^2.12.0",
|
|
43
|
-
"@gajae-code/utils": "0.13.
|
|
43
|
+
"@gajae-code/utils": "0.13.2",
|
|
44
44
|
"openai": "^6.36.0",
|
|
45
45
|
"partial-json": "^0.1.7",
|
|
46
46
|
"zod": "4.4.3"
|
|
@@ -2396,12 +2396,15 @@ function latestAssistantThinkingIsUnreplayable(messages: Message[], model: Model
|
|
|
2396
2396
|
if (block.type !== "thinking") return false;
|
|
2397
2397
|
// A block with empty text and no signature cannot go back on the wire:
|
|
2398
2398
|
// `convertAnthropicMessages` drops it, and Anthropic rejects the turn for
|
|
2399
|
-
// arriving without it. A block with a valid signature
|
|
2400
|
-
//
|
|
2401
|
-
//
|
|
2402
|
-
//
|
|
2399
|
+
// arriving without it. A block with a valid signature AND non-empty text is
|
|
2400
|
+
// replayable. But a signed block whose text was emptied — e.g. by
|
|
2401
|
+
// clear_thinking_20251015 — carries a stale signature that signing endpoints
|
|
2402
|
+
// reject on replay (issue #4247). Non-signing endpoints replay unsigned
|
|
2403
|
+
// blocks verbatim, so only they treat a missing signature as unreplayable.
|
|
2403
2404
|
const hasSignature = !!block.thinkingSignature?.trim();
|
|
2405
|
+
const isEmpty = !block.thinking.trim();
|
|
2404
2406
|
if (!hasSignature) return requiresSignature;
|
|
2407
|
+
if (isEmpty && requiresSignature) return true;
|
|
2405
2408
|
return false;
|
|
2406
2409
|
});
|
|
2407
2410
|
}
|
|
@@ -98,8 +98,15 @@ export function transformMessages<TApi extends Api>(
|
|
|
98
98
|
if (dropAssistantThinkingForRepair && replaysAsNativeThinking) return [];
|
|
99
99
|
if (mustPreserveLatestAnthropicThinking) return sanitized;
|
|
100
100
|
// For same model: keep thinking blocks with signatures (needed for replay)
|
|
101
|
-
// even if the thinking text is empty
|
|
102
|
-
|
|
101
|
+
// even if the thinking text is empty — but only for non-Anthropic APIs where
|
|
102
|
+
// the signature represents OpenAI encrypted reasoning. For anthropic-messages,
|
|
103
|
+
// a signed block with empty text means clear_thinking_20251015 stripped the
|
|
104
|
+
// content server-side while the stale signature remained; replaying it
|
|
105
|
+
// produces `thinking ... cannot be modified` 400s on every turn (#4247).
|
|
106
|
+
if (isSameModel && sanitized.thinkingSignature) {
|
|
107
|
+
if (sanitized.thinking.trim() === "" && model.api === "anthropic-messages") return [];
|
|
108
|
+
return sanitized;
|
|
109
|
+
}
|
|
103
110
|
// Skip empty thinking blocks, convert others to plain text
|
|
104
111
|
if (!sanitized.thinking || sanitized.thinking.trim() === "") return [];
|
|
105
112
|
if (isSameModel) return sanitized;
|