pi-cache-optimizer 2.6.14 → 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 +85 -25
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1992,10 +1992,16 @@ function describeMissingOpenAICompatibleProxyCompat(model: PiModel): string[] {
|
|
|
1992
1992
|
if (!isOpenAICompatibleProxyApi(model.api)) return missing;
|
|
1993
1993
|
if (isOfficialOpenAIBaseUrl(model)) return missing;
|
|
1994
1994
|
|
|
1995
|
-
if (compat.sendSessionAffinityHeaders
|
|
1995
|
+
if (compat.sendSessionAffinityHeaders === undefined) {
|
|
1996
1996
|
missing.push("sendSessionAffinityHeaders");
|
|
1997
1997
|
}
|
|
1998
1998
|
|
|
1999
|
+
// Explicit `sendSessionAffinityHeaders: false` is a valid safe opt-out for
|
|
2000
|
+
// proxies/CDNs/WAFs that block Pi's custom affinity headers with HTTP 403.
|
|
2001
|
+
// Treat only a missing/undefined value as missing compat; do not mark an
|
|
2002
|
+
// intentional false override as ⚠️ compat or let /cache-optimizer fix turn it
|
|
2003
|
+
// back to true.
|
|
2004
|
+
//
|
|
1999
2005
|
// NOTE: supportsLongCacheRetention is intentionally NOT checked here.
|
|
2000
2006
|
// Per spec, it is optional/risky advisory text only and must NOT trigger
|
|
2001
2007
|
// the ⚠️ compat marker. The before_provider_request hook proactively
|
|
@@ -3937,6 +3943,22 @@ function isSessionAffinity403Applicable(model: PiModel): boolean {
|
|
|
3937
3943
|
return getCompat(model).sendSessionAffinityHeaders === true;
|
|
3938
3944
|
}
|
|
3939
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
|
+
|
|
3940
3962
|
/**
|
|
3941
3963
|
* Detect router / channel profiles from a PiModel and return diagnostic notes.
|
|
3942
3964
|
*
|
|
@@ -4134,7 +4156,7 @@ function getCompatCheckNotApplicableLines(model: PiModel): string[] {
|
|
|
4134
4156
|
return ["ℹ️ Compat check not applicable for this model."];
|
|
4135
4157
|
}
|
|
4136
4158
|
|
|
4137
|
-
function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400?: boolean; sessionAffinity403?: boolean } = {}): string {
|
|
4159
|
+
function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400?: boolean; sessionAffinity403?: boolean; openAISdkHeader403?: boolean } = {}): string {
|
|
4138
4160
|
const lines: string[] = [];
|
|
4139
4161
|
lines.push(`Provider: ${model.provider}`);
|
|
4140
4162
|
lines.push(`Model: ${model.id}`);
|
|
@@ -4210,6 +4232,20 @@ function buildDoctorDiagnosis(model: PiModel, options: { promptCacheRetention400
|
|
|
4210
4232
|
lines.push(" (session_id, x-client-request-id, x-session-affinity) and return 403. If you");
|
|
4211
4233
|
lines.push(" see 403 errors, run /cache-optimizer fix to set sendSessionAffinityHeaders: false.");
|
|
4212
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
|
+
}
|
|
4213
4249
|
}
|
|
4214
4250
|
|
|
4215
4251
|
// ── Router/channel diagnostics ──
|
|
@@ -4402,12 +4438,19 @@ function buildCompatDiagnosis(model: PiModel): string | undefined {
|
|
|
4402
4438
|
if (isPromptCacheRetention400Applicable(model)) {
|
|
4403
4439
|
lines.push(getPromptCacheRetentionUnsupportedHint());
|
|
4404
4440
|
}
|
|
4405
|
-
// 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.
|
|
4406
4443
|
if (isSessionAffinity403Applicable(model)) {
|
|
4407
4444
|
lines.push(
|
|
4408
4445
|
"ℹ️ Session affinity headers are enabled. If you see 403 \"blocked\" errors,",
|
|
4409
4446
|
" the proxy/CDN may be blocking Pi's custom headers. Set sendSessionAffinityHeaders: false.",
|
|
4410
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
|
+
);
|
|
4411
4454
|
}
|
|
4412
4455
|
appendOptionalOpenAIProxyCompatAdviceLines(lines, optionalOpenAIProxyCompat);
|
|
4413
4456
|
} else {
|
|
@@ -5686,6 +5729,7 @@ export const __internals_for_tests = {
|
|
|
5686
5729
|
isCompatCheckApplicable,
|
|
5687
5730
|
isPromptCacheRetention400Applicable,
|
|
5688
5731
|
isSessionAffinity403Applicable,
|
|
5732
|
+
isOpenAISdkHeader403Applicable,
|
|
5689
5733
|
hasPromptCacheRetentionUnsupportedSignal,
|
|
5690
5734
|
// Non-GPT OpenAI-compatible model detection
|
|
5691
5735
|
isKimiLikeModel,
|
|
@@ -5904,6 +5948,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
5904
5948
|
const warnedPromptCacheRetention400Models = new Set<string>();
|
|
5905
5949
|
const sendSessionAffinityHeaders403Models = new Set<string>();
|
|
5906
5950
|
const warnedSendSessionAffinityHeaders403Models = new Set<string>();
|
|
5951
|
+
const openAISdkHeader403Models = new Set<string>();
|
|
5952
|
+
const warnedOpenAISdkHeader403Models = new Set<string>();
|
|
5907
5953
|
let cacheStatsByModel: Record<string, CacheStats> = {};
|
|
5908
5954
|
let cacheStatsTotalsByModel: Record<string, CacheStats> = {};
|
|
5909
5955
|
let cacheStatsLegacyFamily: Partial<Record<CacheProviderId, CacheStats>> = emptyAllCacheStats();
|
|
@@ -6570,28 +6616,42 @@ export default function (pi: ExtensionAPI) {
|
|
|
6570
6616
|
return;
|
|
6571
6617
|
}
|
|
6572
6618
|
|
|
6573
|
-
// ── 403:
|
|
6574
|
-
//
|
|
6575
|
-
// Pi's openai-completions/responses adapters send three custom HTTP
|
|
6576
|
-
// headers (session_id, x-client-request-id, x-session-affinity) when
|
|
6577
|
-
// sendSessionAffinityHeaders is enabled. Some third-party proxies /
|
|
6578
|
-
// CDNs / WAFs block these custom headers and return 403. We record a
|
|
6579
|
-
// one-time per-session notification and surface it in doctor/fix so the
|
|
6580
|
-
// user can disable the flag for the blocked model.
|
|
6619
|
+
// ── 403: proxy/CDN/WAF blocking ──
|
|
6581
6620
|
if (event.status === 403) {
|
|
6582
|
-
if (!isSessionAffinity403Applicable(model)) return;
|
|
6583
|
-
|
|
6584
6621
|
const key403 = modelKey(model);
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
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
|
+
}
|
|
6595
6655
|
}
|
|
6596
6656
|
});
|
|
6597
6657
|
|
|
@@ -6714,7 +6774,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
6714
6774
|
cmdCtx.ui.notify("No active model selected. Select a model first with /model or pi --model.", "warning");
|
|
6715
6775
|
return;
|
|
6716
6776
|
}
|
|
6717
|
-
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)) });
|
|
6718
6778
|
const adapter = selectAdapterForModel(model);
|
|
6719
6779
|
const sk = model ? sessionModelKey(model) : undefined;
|
|
6720
6780
|
const statsState = model ? cacheStatsTotalsByModel[modelKey(model)] : undefined;
|
|
@@ -7135,7 +7195,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
7135
7195
|
if (!model) {
|
|
7136
7196
|
cmdCtx.ui.notify("No active model selected. Select a model first with /model or pi --model.", "warning");
|
|
7137
7197
|
} else {
|
|
7138
|
-
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)) });
|
|
7139
7199
|
const adapter = selectAdapterForModel(model);
|
|
7140
7200
|
const sk = model ? sessionModelKey(model) : undefined;
|
|
7141
7201
|
const statsState = model ? cacheStatsTotalsByModel[modelKey(model)] : undefined;
|
package/package.json
CHANGED