gpt5 streaming = use only verified orgs

This commit is contained in:
reanon
2025-08-07 22:51:38 +02:00
parent 253a2af13f
commit 20c9920199
4 changed files with 45 additions and 5 deletions
@@ -31,7 +31,9 @@ export const addKey: ProxyReqMutator = (manager) => {
}
if (inboundApi === outboundApi) {
assignedKey = keyPool.get(body.model, service, needsMultimodal);
// Pass streaming information for GPT-5 models that require verified keys for streaming
const isStreaming = body.stream === true;
assignedKey = keyPool.get(body.model, service, needsMultimodal, isStreaming);
} else {
switch (outboundApi) {
// If we are translating between API formats we may need to select a model
+1 -1
View File
@@ -61,7 +61,7 @@ for service-agnostic functionality.
export interface KeyProvider<T extends Key = Key> {
readonly service: LLMService;
init(): void;
get(model: string): T;
get(model: string, streaming?: boolean): T;
list(): Omit<T, "key">[];
disable(key: T): void;
update(hash: string, update: Partial<T>): void;
+2 -2
View File
@@ -53,7 +53,7 @@ export class KeyPool {
this.scheduleRecheck();
}
public get(model: string, service?: LLMService, multimodal?: boolean): Key {
public get(model: string, service?: LLMService, multimodal?: boolean, streaming?: boolean): Key {
// hack for some claude requests needing keys with particular permissions
// even though they use the same models as the non-multimodal requests
if (multimodal) {
@@ -61,7 +61,7 @@ export class KeyPool {
}
const queryService = service || this.getServiceForModel(model);
return this.getKeyProvider(queryService).get(model);
return this.getKeyProvider(queryService).get(model, streaming);
}
public list(): Omit<Key, "key">[] {
+39 -1
View File
@@ -137,12 +137,16 @@ export class OpenAIKeyProvider implements KeyProvider<OpenAIKey> {
return this.keys.map((key) => Object.freeze({ ...key, key: undefined }));
}
public get(requestModel: string) {
public get(requestModel: string, streaming?: boolean) {
let model = requestModel;
const neededFamily = getOpenAIModelFamily(model);
const excludeTrials = model === "text-embedding-ada-002";
const isGptImageRequest = neededFamily === "gpt-image";
// GPT-5 models (gpt-5, gpt-5-mini, gpt-5-nano) require verified keys for streaming
const isGpt5Model = /^gpt-5(-mini|-nano)?(-\d{4}-\d{2}-\d{2})?$/.test(model) || model === "gpt-5-chat-latest";
const isGpt5StreamingRequest = isGpt5Model && streaming;
// First, filter keys based on basic criteria
let availableKeys = this.keys.filter(
@@ -187,8 +191,42 @@ export class OpenAIKeyProvider implements KeyProvider<OpenAIKey> {
);
}
}
// For GPT-5 streaming requests, we need to use only verified keys
// GPT-5 models (gpt-5, gpt-5-mini, gpt-5-nano) require verified organizations for streaming
if (isGpt5StreamingRequest) {
this.log.debug(
{ model, keyCount: availableKeys.length, streaming },
"Filtering keys for GPT-5 streaming request to ensure verified organization status"
);
// Filter to only include keys from verified organizations
// We piggyback on the existing verification logic: verified keys still have gpt-image access
const verifiedKeys = availableKeys.filter(key => key.modelFamilies.includes("gpt-image"));
if (verifiedKeys.length > 0) {
this.log.info(
{ model, totalKeys: availableKeys.length, verifiedKeys: verifiedKeys.length, streaming },
"Using only verified organization keys for GPT-5 streaming request"
);
availableKeys = verifiedKeys;
} else {
this.log.warn(
{ model, totalKeys: availableKeys.length, streaming },
"No verified organization keys available for GPT-5 streaming request"
);
// Set availableKeys to empty array to trigger the error below
availableKeys = [];
}
}
if (availableKeys.length === 0) {
// Provide specific error message for GPT-5 streaming requests
if (isGpt5StreamingRequest) {
throw new PaymentRequiredError(
`No verified OpenAI keys available for streaming ${model}. GPT-5 models require verified organization keys for streaming. Please disable streaming.`
);
}
throw new PaymentRequiredError(
`No OpenAI keys available for model ${model}`
);