fix(claude): cap re-anchored cache_control at the 4-marker budget and keep single-object content turns
Anthropic accepts at most 4 blocks carrying cache_control per request. When the client had already spent that budget, the re-anchor added a 5th marker and the request was rejected with a non-retryable 400 that the failure path treated as an account problem, retrying the same malformed body across the whole pool until every account locked. anchorClaudeCache now normalizes bare-object content, strips the invalid cache_control carried by defer_loading tools, pins the 1h head anchors on the last system block and last cacheable tool, then trims an over-budget body to 4 markers. The trim holds those head anchors and fills the remaining slots with the tail-most message markers: a plain "keep the last four in document order" rule drops the anchors first even though they lead document order, and skipping the re-anchor at a spent budget left system/tools on the 5m default instead of 1h. Some clients send content as a single block object rather than a one-element array. Such a turn was dropped or zeroed on every leg that reads messages, silently losing conversation history. normalizeMessageContent wraps it as a one-block array on all four paths, and hasValidContent keeps it.
This commit is contained in:
@@ -142,6 +142,13 @@ function systemReminderText(content) {
|
||||
|
||||
// Convert single Claude message - returns single message or array of messages
|
||||
function convertClaudeMessage(msg) {
|
||||
// Some clients send content as a single block object; normalize to the
|
||||
// one-element array every branch below (the system-reminder fold included)
|
||||
// expects. Must run BEFORE the role branch: systemReminderText only reads
|
||||
// arrays and strings, so a bare-object system turn was dropped outright.
|
||||
if (msg.content && typeof msg.content === "object" && !Array.isArray(msg.content)) {
|
||||
msg.content = [msg.content];
|
||||
}
|
||||
// Mid-conversation system message -> user (per Anthropic placement rules)
|
||||
if (msg.role === ROLE.SYSTEM) {
|
||||
const text = systemReminderText(msg.content);
|
||||
|
||||
Reference in New Issue
Block a user