maxpool 1.22.2 → 1.22.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.js +43 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.22.2",
3
+ "version": "1.22.4",
4
4
  "description": "Multi-account Claude Code proxy with adaptive, rate-aware load balancing across Claude accounts",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/server.js CHANGED
@@ -1193,6 +1193,39 @@ async function forwardRequest(
1193
1193
  // the API's own stated rule, so no failover is needed and the user never sees the
1194
1194
  // 400. One-shot per request via its own flag so a second ordering 400 (a rule we
1195
1195
  // have not modeled) still surfaces honestly instead of looping.
1196
+ // THE REPAIR'S OWN REJECTION (2026-09-25): some accounts' validators 400 the
1197
+ // output_config FIELD ITSELF ("Extra inputs are not permitted") even though the
1198
+ // ordering rule's own error text names it as the accepted form — a gradual
1199
+ // rollout on Anthropic's side (max@dubner.io and mk@gomokka rejected it same-day
1200
+ // while max@gomokka.com accepted the identical repaired body). When that happens,
1201
+ // fall back to position-preserving re-anchoring instead of surfacing the 400.
1202
+ const isDirectiveFormRejection = account.type !== 'provider'
1203
+ && upstreamRes.status === 400
1204
+ && /output_config[^:]*: *Extra inputs are not permitted/i.test(errorBody);
1205
+ if (isDirectiveFormRejection && requestInfo.orderingRepaired && !requestInfo.orderingFallback && canRepairBody) {
1206
+ // Rewrite every directive-only system (the repair's own output) as a PLAIN
1207
+ // assistant turn carrying the directives text — ordinary history, accepted by
1208
+ // every validator, nothing dropped. A system ENDING the array stays legal
1209
+ // everywhere, so it is left alone.
1210
+ const json = JSON.parse(body.toString('utf8'));
1211
+ let folded = 0;
1212
+ json.messages = (json.messages ?? []).map((m, i, arr) => {
1213
+ if (m?.role !== 'system' || !('output_config' in m)) return m;
1214
+ if (i === arr.length - 1) return m; // end-of-array system is legal universally
1215
+ folded++;
1216
+ const text = String(m.output_config?.directives ?? '');
1217
+ return { role: 'assistant', content: text ? [{ type: 'text', text }] : [{ type: 'text', text: '(system directive)' }] };
1218
+ });
1219
+ if (folded > 0) {
1220
+ const fixedBody = Buffer.from(JSON.stringify(json));
1221
+ console.log(`[Maxpool] Account rejects the directive-only form — folded ${folded} system directive(s) into plain turns`);
1222
+ return forwardRequest(
1223
+ req, res, fixedBody, accountManager, upstream, retryCount + 1, hooks, reqId, ctx, logDir,
1224
+ retryConfig, queueConfig, { ...requestInfo, orderingFallback: true, repairCount: repairCount + 1 },
1225
+ fixedBody.length <= retryConfig.maxRetryBufferBytes, canQueueBufferedBody, excludedIndexes,
1226
+ );
1227
+ }
1228
+ }
1196
1229
  if (isOrderingRejection && !requestInfo.orderingRepaired && canRepairBody) {
1197
1230
  const coord = /messages\.(\d+)/.exec(errorBody);
1198
1231
  const { messages: fixedMessages, converted } = directiveOnlySystemMessages(
@@ -2144,9 +2177,16 @@ function directiveOnlySystemMessages(messages, coordIndex = -1) {
2144
2177
  };
2145
2178
  const out = messages.map((m, i) => {
2146
2179
  if (coordIndex >= 0 ? i !== coordIndex : !violates(i)) return m;
2147
- const text = (Array.isArray(m.content) ? m.content : [])
2148
- .map(b => (typeof b?.text === 'string' ? b.text : ''))
2149
- .filter(Boolean).join('\n');
2180
+ // Content arrives BOTH ways: array-of-blocks (compaction boundaries) and a plain
2181
+ // STRING (injected reminders — the common CLI shape). Reading only the array form
2182
+ // silently DISCARDED every string system message's text: the directive went out
2183
+ // empty AND some accounts 400 the emptied shape (measured 2026-09-25: directives ""
2184
+ // -> "messages.6.output_config: Extra inputs are not permitted").
2185
+ const text = typeof m.content === 'string'
2186
+ ? m.content
2187
+ : (Array.isArray(m.content) ? m.content : [])
2188
+ .map(b => (typeof b?.text === 'string' ? b.text : ''))
2189
+ .filter(Boolean).join('\n');
2150
2190
  converted++;
2151
2191
  // output_config shape per the API's own 400 text: directive-only system.
2152
2192
  return { role: 'system', content: [], output_config: { directives: text } };