pi-cache-optimizer 2.6.15 → 2.6.16
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/index.ts +78 -24
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -3943,6 +3943,22 @@ function isSessionAffinity403Applicable(model: PiModel): boolean {
|
|
|
3943
3943
|
return getCompat(model).sendSessionAffinityHeaders === true;
|
|
3944
3944
|
}
|
|
3945
3945
|
|
|
3946
|
+
/**
|
|
3947
|
+
* Whether an OpenAI SDK header/User-Agent 403 diagnostic applies.
|
|
3948
|
+
*
|
|
3949
|
+
* Some third-party OpenAI-compatible proxies/CDNs/WAFs allow a plain curl
|
|
3950
|
+
* request but block the OpenAI JS SDK's default request fingerprint, especially
|
|
3951
|
+
* its `User-Agent: OpenAI/JS ...` and `X-Stainless-*` headers. This is distinct
|
|
3952
|
+
* from session-affinity header blocking: it applies when session-affinity
|
|
3953
|
+
* headers are NOT enabled but the model still uses a non-official
|
|
3954
|
+
* OpenAI-compatible proxy transport.
|
|
3955
|
+
*/
|
|
3956
|
+
function isOpenAISdkHeader403Applicable(model: PiModel): boolean {
|
|
3957
|
+
if (!isOpenAICompatibleProxyApi(model.api)) return false;
|
|
3958
|
+
if (isOfficialOpenAIBaseUrl(model)) return false;
|
|
3959
|
+
return getCompat(model).sendSessionAffinityHeaders !== true;
|
|
3960
|
+
}
|
|
3961
|
+
|
|
3946
3962
|
/**
|
|
3947
3963
|
* Detect router / channel profiles from a PiModel and return diagnostic notes.
|
|
3948
3964
|
*
|
|
@@ -4140,7 +4156,7 @@ function getCompatCheckNotApplicableLines(model: PiModel): string[] {
|
|
|
4140
4156
|
return ["ℹ️ Compat check not applicable for this model."];
|
|
4141
4157
|
}
|
|
4142
4158
|
|
|
4143
|
-
function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400?: boolean; sessionAffinity403?: boolean } = {}): string {
|
|
4159
|
+
function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400?: boolean; sessionAffinity403?: boolean; openAISdkHeader403?: boolean } = {}): string {
|
|
4144
4160
|
const lines: string[] = [];
|
|
4145
4161
|
lines.push(`Provider: ${model.provider}`);
|
|
4146
4162
|
lines.push(`Model: ${model.id}`);
|
|
@@ -4216,6 +4232,20 @@ function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400
|
|
|
4216
4232
|
lines.push(" (session_id, x-client-request-id, x-session-affinity) and return 403. If you");
|
|
4217
4233
|
lines.push(" see 403 errors, run /cache-optimizer fix to set sendSessionAffinityHeaders: false.");
|
|
4218
4234
|
}
|
|
4235
|
+
} else if (isOpenAISdkHeader403Applicable(model)) {
|
|
4236
|
+
lines.push("");
|
|
4237
|
+
if (options.openAISdkHeader403) {
|
|
4238
|
+
lines.push("⚠️ A 403 response was observed while sendSessionAffinityHeaders is not enabled.");
|
|
4239
|
+
lines.push(" The proxy/CDN may be blocking the OpenAI JS SDK request fingerprint");
|
|
4240
|
+
lines.push(" (for example User-Agent: OpenAI/JS ... or X-Stainless-* headers). This");
|
|
4241
|
+
lines.push(" is provider/WAF-specific; /cache-optimizer fix will not auto-write headers.");
|
|
4242
|
+
lines.push(` Manual workaround: add a provider-level headers.User-Agent override in ${getModelsJsonDisplayPath()}`);
|
|
4243
|
+
lines.push(" only after testing the value with the affected provider.");
|
|
4244
|
+
} else {
|
|
4245
|
+
lines.push("ℹ️ If 403 persists after disabling sendSessionAffinityHeaders, some CDNs/WAFs");
|
|
4246
|
+
lines.push(" may block the OpenAI JS SDK User-Agent / X-Stainless-* headers. Test the");
|
|
4247
|
+
lines.push(" provider manually before adding a provider-level headers.User-Agent override.");
|
|
4248
|
+
}
|
|
4219
4249
|
}
|
|
4220
4250
|
|
|
4221
4251
|
// ── Router/channel diagnostics ──
|
|
@@ -4408,12 +4438,19 @@ function buildCompatDiagnosis(model: PiModel): string | undefined {
|
|
|
4408
4438
|
if (isPromptCacheRetention400Applicable(model)) {
|
|
4409
4439
|
lines.push(getPromptCacheRetentionUnsupportedHint());
|
|
4410
4440
|
}
|
|
4411
|
-
// Advisory for 403 session-affinity header blocking (only when enabled)
|
|
4441
|
+
// Advisory for 403 session-affinity header blocking (only when enabled),
|
|
4442
|
+
// or OpenAI SDK header/User-Agent blocking after session affinity is disabled.
|
|
4412
4443
|
if (isSessionAffinity403Applicable(model)) {
|
|
4413
4444
|
lines.push(
|
|
4414
4445
|
"ℹ️ Session affinity headers are enabled. If you see 403 \"blocked\" errors,",
|
|
4415
4446
|
" the proxy/CDN may be blocking Pi's custom headers. Set sendSessionAffinityHeaders: false.",
|
|
4416
4447
|
);
|
|
4448
|
+
} else if (isOpenAISdkHeader403Applicable(model)) {
|
|
4449
|
+
lines.push(
|
|
4450
|
+
"ℹ️ If 403 persists with sendSessionAffinityHeaders disabled, the proxy/CDN may",
|
|
4451
|
+
" be blocking the OpenAI JS SDK User-Agent / X-Stainless-* headers. Test a",
|
|
4452
|
+
" provider-level headers.User-Agent override manually; /fix does not auto-write it.",
|
|
4453
|
+
);
|
|
4417
4454
|
}
|
|
4418
4455
|
appendOptionalOpenAIProxyCompatAdviceLines(lines, optionalOpenAIProxyCompat);
|
|
4419
4456
|
} else {
|
|
@@ -5692,6 +5729,7 @@ export const __internals_for_tests = {
|
|
|
5692
5729
|
isCompatCheckApplicable,
|
|
5693
5730
|
isPromptCacheRetention400Applicable,
|
|
5694
5731
|
isSessionAffinity403Applicable,
|
|
5732
|
+
isOpenAISdkHeader403Applicable,
|
|
5695
5733
|
hasPromptCacheRetentionUnsupportedSignal,
|
|
5696
5734
|
// Non-GPT OpenAI-compatible model detection
|
|
5697
5735
|
isKimiLikeModel,
|
|
@@ -5910,6 +5948,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
5910
5948
|
const warnedPromptCacheRetention400Models = new Set<string>();
|
|
5911
5949
|
const sendSessionAffinityHeaders403Models = new Set<string>();
|
|
5912
5950
|
const warnedSendSessionAffinityHeaders403Models = new Set<string>();
|
|
5951
|
+
const openAISdkHeader403Models = new Set<string>();
|
|
5952
|
+
const warnedOpenAISdkHeader403Models = new Set<string>();
|
|
5913
5953
|
let cacheStatsByModel: Record<string, CacheStats> = {};
|
|
5914
5954
|
let cacheStatsTotalsByModel: Record<string, CacheStats> = {};
|
|
5915
5955
|
let cacheStatsLegacyFamily: Partial<Record<CacheProviderId, CacheStats>> = emptyAllCacheStats();
|
|
@@ -6576,28 +6616,42 @@ export default function (pi: ExtensionAPI) {
|
|
|
6576
6616
|
return;
|
|
6577
6617
|
}
|
|
6578
6618
|
|
|
6579
|
-
// ── 403:
|
|
6580
|
-
//
|
|
6581
|
-
// Pi's openai-completions/responses adapters send three custom HTTP
|
|
6582
|
-
// headers (session_id, x-client-request-id, x-session-affinity) when
|
|
6583
|
-
// sendSessionAffinityHeaders is enabled. Some third-party proxies /
|
|
6584
|
-
// CDNs / WAFs block these custom headers and return 403. We record a
|
|
6585
|
-
// one-time per-session notification and surface it in doctor/fix so the
|
|
6586
|
-
// user can disable the flag for the blocked model.
|
|
6619
|
+
// ── 403: proxy/CDN/WAF blocking ──
|
|
6587
6620
|
if (event.status === 403) {
|
|
6588
|
-
if (!isSessionAffinity403Applicable(model)) return;
|
|
6589
|
-
|
|
6590
6621
|
const key403 = modelKey(model);
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6622
|
+
|
|
6623
|
+
// Case 1: Pi's custom session-affinity headers are enabled. Offer the
|
|
6624
|
+
// existing safe compat fix (`sendSessionAffinityHeaders: false`).
|
|
6625
|
+
if (isSessionAffinity403Applicable(model)) {
|
|
6626
|
+
sendSessionAffinityHeaders403Models.add(key403);
|
|
6627
|
+
if (warnedSendSessionAffinityHeaders403Models.has(key403)) return;
|
|
6628
|
+
warnedSendSessionAffinityHeaders403Models.add(key403);
|
|
6629
|
+
ctx.ui.notify(
|
|
6630
|
+
`⚠️ ${LOG_PREFIX}: ${key403} returned HTTP 403 while sendSessionAffinityHeaders is enabled. ` +
|
|
6631
|
+
`The proxy/CDN may be blocking Pi's custom session-affinity headers (session_id, x-client-request-id, x-session-affinity). ` +
|
|
6632
|
+
`Run /cache-optimizer doctor for details and /cache-optimizer fix to set sendSessionAffinityHeaders: false.`,
|
|
6633
|
+
"warning",
|
|
6634
|
+
);
|
|
6635
|
+
return;
|
|
6636
|
+
}
|
|
6637
|
+
|
|
6638
|
+
// Case 2: session-affinity headers are already absent/disabled, but the
|
|
6639
|
+
// provider still returns 403. Some CDNs/WAFs block the OpenAI JS SDK
|
|
6640
|
+
// default request fingerprint (User-Agent: OpenAI/JS ... or
|
|
6641
|
+
// X-Stainless-* headers). This is provider-specific; do NOT auto-fix by
|
|
6642
|
+
// writing a User-Agent because the right value depends on the endpoint.
|
|
6643
|
+
if (isOpenAISdkHeader403Applicable(model)) {
|
|
6644
|
+
openAISdkHeader403Models.add(key403);
|
|
6645
|
+
if (warnedOpenAISdkHeader403Models.has(key403)) return;
|
|
6646
|
+
warnedOpenAISdkHeader403Models.add(key403);
|
|
6647
|
+
ctx.ui.notify(
|
|
6648
|
+
`⚠️ ${LOG_PREFIX}: ${key403} returned HTTP 403 even though sendSessionAffinityHeaders is not enabled. ` +
|
|
6649
|
+
`The proxy/CDN may be blocking the OpenAI JS SDK User-Agent / X-Stainless-* headers. ` +
|
|
6650
|
+
`Run /cache-optimizer doctor for manual diagnostic guidance; /cache-optimizer fix will not auto-write User-Agent headers.`,
|
|
6651
|
+
"warning",
|
|
6652
|
+
);
|
|
6653
|
+
return;
|
|
6654
|
+
}
|
|
6601
6655
|
}
|
|
6602
6656
|
});
|
|
6603
6657
|
|
|
@@ -6720,7 +6774,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6720
6774
|
cmdCtx.ui.notify("No active model selected. Select a model first with /model or pi --model.", "warning");
|
|
6721
6775
|
return;
|
|
6722
6776
|
}
|
|
6723
|
-
const diagnosis = buildDoctorDiagnosis(model, { promptCacheRetention400: promptCacheRetention400Models.has(modelKey(model)), sessionAffinity403: sendSessionAffinityHeaders403Models.has(modelKey(model)) });
|
|
6777
|
+
const diagnosis = buildDoctorDiagnosis(model, { promptCacheRetention400: promptCacheRetention400Models.has(modelKey(model)), sessionAffinity403: sendSessionAffinityHeaders403Models.has(modelKey(model)), openAISdkHeader403: openAISdkHeader403Models.has(modelKey(model)) });
|
|
6724
6778
|
const adapter = selectAdapterForModel(model);
|
|
6725
6779
|
const sk = model ? sessionModelKey(model) : undefined;
|
|
6726
6780
|
const statsState = model ? cacheStatsTotalsByModel[modelKey(model)] : undefined;
|
|
@@ -7141,7 +7195,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
7141
7195
|
if (!model) {
|
|
7142
7196
|
cmdCtx.ui.notify("No active model selected. Select a model first with /model or pi --model.", "warning");
|
|
7143
7197
|
} else {
|
|
7144
|
-
const diagnosis = buildDoctorDiagnosis(model, { promptCacheRetention400: promptCacheRetention400Models.has(modelKey(model)), sessionAffinity403: sendSessionAffinityHeaders403Models.has(modelKey(model)) });
|
|
7198
|
+
const diagnosis = buildDoctorDiagnosis(model, { promptCacheRetention400: promptCacheRetention400Models.has(modelKey(model)), sessionAffinity403: sendSessionAffinityHeaders403Models.has(modelKey(model)), openAISdkHeader403: openAISdkHeader403Models.has(modelKey(model)) });
|
|
7145
7199
|
const adapter = selectAdapterForModel(model);
|
|
7146
7200
|
const sk = model ? sessionModelKey(model) : undefined;
|
|
7147
7201
|
const statsState = model ? cacheStatsTotalsByModel[modelKey(model)] : undefined;
|
package/package.json
CHANGED