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) { 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 { } else {
switch (outboundApi) { switch (outboundApi) {
// If we are translating between API formats we may need to select a model // 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> { export interface KeyProvider<T extends Key = Key> {
readonly service: LLMService; readonly service: LLMService;
init(): void; init(): void;
get(model: string): T; get(model: string, streaming?: boolean): T;
list(): Omit<T, "key">[]; list(): Omit<T, "key">[];
disable(key: T): void; disable(key: T): void;
update(hash: string, update: Partial<T>): void; update(hash: string, update: Partial<T>): void;
+2 -2
View File
@@ -53,7 +53,7 @@ export class KeyPool {
this.scheduleRecheck(); 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 // hack for some claude requests needing keys with particular permissions
// even though they use the same models as the non-multimodal requests // even though they use the same models as the non-multimodal requests
if (multimodal) { if (multimodal) {
@@ -61,7 +61,7 @@ export class KeyPool {
} }
const queryService = service || this.getServiceForModel(model); const queryService = service || this.getServiceForModel(model);
return this.getKeyProvider(queryService).get(model); return this.getKeyProvider(queryService).get(model, streaming);
} }
public list(): Omit<Key, "key">[] { public list(): Omit<Key, "key">[] {
+39 -1
View File
@@ -137,13 +137,17 @@ export class OpenAIKeyProvider implements KeyProvider<OpenAIKey> {
return this.keys.map((key) => Object.freeze({ ...key, key: undefined })); return this.keys.map((key) => Object.freeze({ ...key, key: undefined }));
} }
public get(requestModel: string) { public get(requestModel: string, streaming?: boolean) {
let model = requestModel; let model = requestModel;
const neededFamily = getOpenAIModelFamily(model); const neededFamily = getOpenAIModelFamily(model);
const excludeTrials = model === "text-embedding-ada-002"; const excludeTrials = model === "text-embedding-ada-002";
const isGptImageRequest = neededFamily === "gpt-image"; 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 // First, filter keys based on basic criteria
let availableKeys = this.keys.filter( let availableKeys = this.keys.filter(
(key) => (key) =>
@@ -188,7 +192,41 @@ 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) { 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( throw new PaymentRequiredError(
`No OpenAI keys available for model ${model}` `No OpenAI keys available for model ${model}`
); );