Skip to content

Commit b15dfb2

Browse files
committed
check via braintrust secret type
1 parent 7ead1f5 commit b15dfb2

4 files changed

Lines changed: 91 additions & 7 deletions

File tree

apis/cloudflare/src/billing.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,12 @@ import { type BillingEvent } from "@braintrust/proxy";
33
const DEFAULT_BILLING_TELEMETRY_URL =
44
"https://api.braintrust.dev/billing/telemetry/ingest";
55

6-
function isBrainModel(model: string): boolean {
7-
return model.startsWith("brain-");
8-
}
9-
106
function buildPayloadEvent(event: BillingEvent) {
117
if (!event.model) {
128
console.warn("billing event skipped: missing model");
139
return null;
1410
}
15-
// Skip non-brain models since braintrust only hosts brain models.
16-
if (!isBrainModel(event.model)) {
11+
if (!event.isNativeInference) {
1712
return null;
1813
}
1914

packages/proxy/src/proxy.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ import {
102102
flattenChunksArray,
103103
getRandomInt,
104104
isEmpty,
105+
isNativeInferenceSecret,
105106
isObject,
106107
ModelResponse,
107108
parseAuthHeader,
@@ -194,6 +195,7 @@ export type BillingEvent = {
194195
event_name: "NativeInferenceTokenUsageEvent";
195196
auth_token: string;
196197
org_id?: string;
198+
isNativeInference?: boolean;
197199
model?: string | null;
198200
resolved_model?: string | null;
199201
org_name?: string;
@@ -1151,6 +1153,7 @@ export async function proxyV1({
11511153
event_name: "NativeInferenceTokenUsageEvent",
11521154
auth_token: authToken,
11531155
org_id: billingOrgId,
1156+
isNativeInference: nativeInferenceSecret !== undefined,
11541157
model,
11551158
resolved_model: resolvedModel,
11561159
org_name: resolvedOrgName,
@@ -1330,6 +1333,10 @@ async function fetchModelLoop(
13301333
}
13311334

13321335
const initialIdx = getRandomInt(secrets.length);
1336+
const nativeInferenceSecret =
1337+
model === null || model === undefined
1338+
? undefined
1339+
: secrets.find((secret) => isNativeInferenceSecret(secret, model));
13331340
let proxyResponse: ModelResponse | null = null;
13341341
let secretName: string | null | undefined = null;
13351342
let lastException = null;

packages/proxy/src/util.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { describe, expect, test } from "vitest";
2-
import { parseFileMetadataFromUrl, _urljoin } from "./util";
2+
import { type APISecret } from "@schema";
3+
import {
4+
isNativeInferenceSecret,
5+
parseFileMetadataFromUrl,
6+
_urljoin,
7+
} from "./util";
38

49
describe("parseFileMetadataFromUrl", () => {
510
test("handles basic URLs", () => {
@@ -222,3 +227,58 @@ test("_urljoin", () => {
222227
expect(_urljoin()).toBe("");
223228
expect(_urljoin("a")).toBe("a");
224229
});
230+
231+
describe("isNativeInferenceSecret", () => {
232+
test("treats braintrust secrets without custom models as native inference", () => {
233+
const secret: APISecret = {
234+
type: "braintrust",
235+
secret: "test-secret",
236+
metadata: {
237+
api_base: "http://localhost:8001/native-inference-test",
238+
},
239+
};
240+
241+
expect(isNativeInferenceSecret(secret, "brain-test-native-1")).toBe(true);
242+
});
243+
244+
test("treats custom model secrets as native inference only for matching models", () => {
245+
const secret: APISecret = {
246+
type: "openai",
247+
secret: "test-secret",
248+
metadata: {
249+
customModels: {
250+
"brain-test-native-1": {
251+
format: "openai",
252+
flavor: "chat",
253+
},
254+
},
255+
},
256+
};
257+
258+
expect(isNativeInferenceSecret(secret, "brain-test-native-1")).toBe(true);
259+
expect(isNativeInferenceSecret(secret, "brain-test-native-2")).toBe(false);
260+
});
261+
262+
test("treats non-braintrust secrets without matching custom models as non-native", () => {
263+
const secret: APISecret = {
264+
type: "openai",
265+
secret: "test-secret",
266+
metadata: {
267+
api_base: "https://api.openai.com/v1",
268+
},
269+
};
270+
271+
expect(isNativeInferenceSecret(secret, "brain-test-native-1")).toBe(false);
272+
});
273+
274+
test("returns false when the model is missing", () => {
275+
const secret: APISecret = {
276+
type: "braintrust",
277+
secret: "test-secret",
278+
metadata: null,
279+
};
280+
281+
expect(isNativeInferenceSecret(secret, null)).toBe(false);
282+
expect(isNativeInferenceSecret(secret, undefined)).toBe(false);
283+
});
284+
});

packages/proxy/src/util.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import contentDisposition from "content-disposition";
2+
import { type APISecret } from "@schema";
23
export interface ModelResponse {
34
stream: ReadableStream<Uint8Array> | null;
45
response: Response;
@@ -79,6 +80,27 @@ export function isEmpty(a: any): a is null | undefined {
7980
return a === undefined || a === null;
8081
}
8182

83+
export function isNativeInferenceSecret(
84+
secret: APISecret,
85+
model: string | null | undefined,
86+
): boolean {
87+
if (model === null || model === undefined) {
88+
return false;
89+
}
90+
91+
const customModels = secret.metadata?.customModels;
92+
if (
93+
customModels === null ||
94+
customModels === undefined ||
95+
typeof customModels !== "object" ||
96+
Array.isArray(customModels)
97+
) {
98+
return secret.type === "braintrust";
99+
}
100+
101+
return Object.prototype.hasOwnProperty.call(customModels, model);
102+
}
103+
82104
export function getRandomInt(max: number) {
83105
return Math.floor(Math.random() * max);
84106
}

0 commit comments

Comments
 (0)