braintrust 0.0.180 → 0.0.182

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.
@@ -521,6 +521,32 @@ declare class Attachment {
521
521
  private initUploader;
522
522
  private initData;
523
523
  }
524
+ declare const attachmentMetadataSchema: z.ZodObject<{
525
+ downloadUrl: z.ZodString;
526
+ status: z.ZodObject<{
527
+ upload_status: z.ZodEnum<["uploading", "done", "error"]>;
528
+ error_message: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
529
+ }, "strip", z.ZodTypeAny, {
530
+ upload_status: "error" | "done" | "uploading";
531
+ error_message?: string | undefined;
532
+ }, {
533
+ upload_status: "error" | "done" | "uploading";
534
+ error_message?: string | null | undefined;
535
+ }>;
536
+ }, "strip", z.ZodTypeAny, {
537
+ status: {
538
+ upload_status: "error" | "done" | "uploading";
539
+ error_message?: string | undefined;
540
+ };
541
+ downloadUrl: string;
542
+ }, {
543
+ status: {
544
+ upload_status: "error" | "done" | "uploading";
545
+ error_message?: string | null | undefined;
546
+ };
547
+ downloadUrl: string;
548
+ }>;
549
+ type AttachmentMetadata = z.infer<typeof attachmentMetadataSchema>;
524
550
  /**
525
551
  * A readonly alternative to `Attachment`, which can be used for fetching
526
552
  * already-uploaded Attachments.
@@ -546,13 +572,17 @@ declare class ReadonlyAttachment {
546
572
  * contents from the object store on first access.
547
573
  */
548
574
  data(): Promise<Blob>;
575
+ /**
576
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
577
+ * This will re-fetch the status each time in case it changes over time.
578
+ */
579
+ metadata(): Promise<AttachmentMetadata>;
549
580
  /**
550
581
  * Fetch the attachment upload status. This will re-fetch the status each time
551
582
  * in case it changes over time.
552
583
  */
553
584
  status(): Promise<AttachmentStatus>;
554
585
  private initDownloader;
555
- private fetchMetadata;
556
586
  }
557
587
  /**
558
588
  * Update a span using the output of `span.export()`. It is important that you only resume updating
@@ -1815,6 +1845,7 @@ interface ChatLike {
1815
1845
  interface OpenAILike {
1816
1846
  chat: ChatLike;
1817
1847
  embeddings: any;
1848
+ moderations: any;
1818
1849
  beta?: BetaLike;
1819
1850
  }
1820
1851
  declare global {
package/dist/browser.d.ts CHANGED
@@ -521,6 +521,32 @@ declare class Attachment {
521
521
  private initUploader;
522
522
  private initData;
523
523
  }
524
+ declare const attachmentMetadataSchema: z.ZodObject<{
525
+ downloadUrl: z.ZodString;
526
+ status: z.ZodObject<{
527
+ upload_status: z.ZodEnum<["uploading", "done", "error"]>;
528
+ error_message: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
529
+ }, "strip", z.ZodTypeAny, {
530
+ upload_status: "error" | "done" | "uploading";
531
+ error_message?: string | undefined;
532
+ }, {
533
+ upload_status: "error" | "done" | "uploading";
534
+ error_message?: string | null | undefined;
535
+ }>;
536
+ }, "strip", z.ZodTypeAny, {
537
+ status: {
538
+ upload_status: "error" | "done" | "uploading";
539
+ error_message?: string | undefined;
540
+ };
541
+ downloadUrl: string;
542
+ }, {
543
+ status: {
544
+ upload_status: "error" | "done" | "uploading";
545
+ error_message?: string | null | undefined;
546
+ };
547
+ downloadUrl: string;
548
+ }>;
549
+ type AttachmentMetadata = z.infer<typeof attachmentMetadataSchema>;
524
550
  /**
525
551
  * A readonly alternative to `Attachment`, which can be used for fetching
526
552
  * already-uploaded Attachments.
@@ -546,13 +572,17 @@ declare class ReadonlyAttachment {
546
572
  * contents from the object store on first access.
547
573
  */
548
574
  data(): Promise<Blob>;
575
+ /**
576
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
577
+ * This will re-fetch the status each time in case it changes over time.
578
+ */
579
+ metadata(): Promise<AttachmentMetadata>;
549
580
  /**
550
581
  * Fetch the attachment upload status. This will re-fetch the status each time
551
582
  * in case it changes over time.
552
583
  */
553
584
  status(): Promise<AttachmentStatus>;
554
585
  private initDownloader;
555
- private fetchMetadata;
556
586
  }
557
587
  /**
558
588
  * Update a span using the output of `span.export()`. It is important that you only resume updating
@@ -1815,6 +1845,7 @@ interface ChatLike {
1815
1845
  interface OpenAILike {
1816
1846
  chat: ChatLike;
1817
1847
  embeddings: any;
1848
+ moderations: any;
1818
1849
  beta?: BetaLike;
1819
1850
  }
1820
1851
  declare global {
package/dist/browser.js CHANGED
@@ -1189,16 +1189,35 @@ var ReadonlyAttachment = class {
1189
1189
  async data() {
1190
1190
  return this._data.get();
1191
1191
  }
1192
+ /**
1193
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
1194
+ * This will re-fetch the status each time in case it changes over time.
1195
+ */
1196
+ async metadata() {
1197
+ const state = this.state ?? _globalState;
1198
+ await state.login({});
1199
+ const resp = await state.apiConn().get("/attachment", {
1200
+ key: this.reference.key,
1201
+ filename: this.reference.filename,
1202
+ content_type: this.reference.content_type,
1203
+ org_id: state.orgId || ""
1204
+ });
1205
+ if (!resp.ok) {
1206
+ const errorStr = JSON.stringify(resp);
1207
+ throw new Error(`Invalid response from API server: ${errorStr}`);
1208
+ }
1209
+ return attachmentMetadataSchema.parse(await resp.json());
1210
+ }
1192
1211
  /**
1193
1212
  * Fetch the attachment upload status. This will re-fetch the status each time
1194
1213
  * in case it changes over time.
1195
1214
  */
1196
1215
  async status() {
1197
- return (await this.fetchMetadata()).status;
1216
+ return (await this.metadata()).status;
1198
1217
  }
1199
1218
  initDownloader() {
1200
1219
  const download = async () => {
1201
- const { downloadUrl, status } = await this.fetchMetadata();
1220
+ const { downloadUrl, status } = await this.metadata();
1202
1221
  if (status.upload_status !== "done") {
1203
1222
  throw new Error(
1204
1223
  `Expected attachment status "done", got "${status.upload_status}"`
@@ -1213,21 +1232,6 @@ var ReadonlyAttachment = class {
1213
1232
  };
1214
1233
  return new LazyValue(download);
1215
1234
  }
1216
- async fetchMetadata() {
1217
- const state = this.state ?? _globalState;
1218
- await state.login({});
1219
- const resp = await state.apiConn().get("/attachment", {
1220
- key: this.reference.key,
1221
- filename: this.reference.filename,
1222
- content_type: this.reference.content_type,
1223
- org_id: state.orgId || ""
1224
- });
1225
- if (!resp.ok) {
1226
- const errorStr = JSON.stringify(resp);
1227
- throw new Error(`Invalid response from API server: ${errorStr}`);
1228
- }
1229
- return attachmentMetadataSchema.parse(await resp.json());
1230
- }
1231
1235
  };
1232
1236
  function logFeedbackImpl(state, parentObjectType, parentObjectId, {
1233
1237
  id,
@@ -3986,16 +3990,11 @@ function wrapOpenAI(openai) {
3986
3990
  }
3987
3991
  globalThis.__inherited_braintrust_wrap_openai = wrapOpenAI;
3988
3992
  function wrapOpenAIv4(openai) {
3989
- let completionProxy = new Proxy(openai.chat.completions, {
3990
- get(target, name, receiver) {
3991
- const baseVal = Reflect.get(target, name, receiver);
3992
- if (name === "create") {
3993
- return wrapChatCompletion(baseVal.bind(target));
3994
- }
3995
- return baseVal;
3996
- }
3997
- });
3998
- let chatProxy = new Proxy(openai.chat, {
3993
+ const completionProxy = createEndpointProxy(
3994
+ openai.chat.completions,
3995
+ wrapChatCompletion
3996
+ );
3997
+ const chatProxy = new Proxy(openai.chat, {
3999
3998
  get(target, name, receiver) {
4000
3999
  if (name === "completions") {
4001
4000
  return completionProxy;
@@ -4003,18 +4002,11 @@ function wrapOpenAIv4(openai) {
4003
4002
  return Reflect.get(target, name, receiver);
4004
4003
  }
4005
4004
  });
4006
- let embeddingProxy = new Proxy(openai.embeddings, {
4007
- get(target, name, receiver) {
4008
- const baseVal = Reflect.get(target, name, receiver);
4009
- if (name === "create") {
4010
- return wrapEmbeddings(baseVal.bind(target));
4011
- }
4012
- return baseVal;
4013
- }
4014
- });
4005
+ const embeddingProxy = createEndpointProxy(openai.embeddings, wrapEmbeddings);
4006
+ const moderationProxy = createEndpointProxy(openai.moderations, wrapModerations);
4015
4007
  let betaProxy;
4016
4008
  if (openai.beta?.chat?.completions?.stream) {
4017
- let betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
4009
+ const betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
4018
4010
  get(target, name, receiver) {
4019
4011
  const baseVal = Reflect.get(target, name, receiver);
4020
4012
  if (name === "parse") {
@@ -4025,7 +4017,7 @@ function wrapOpenAIv4(openai) {
4025
4017
  return baseVal;
4026
4018
  }
4027
4019
  });
4028
- let betaChatProxy = new Proxy(openai.beta.chat, {
4020
+ const betaChatProxy = new Proxy(openai.beta.chat, {
4029
4021
  get(target, name, receiver) {
4030
4022
  if (name === "completions") {
4031
4023
  return betaChatCompletionProxy;
@@ -4042,7 +4034,7 @@ function wrapOpenAIv4(openai) {
4042
4034
  }
4043
4035
  });
4044
4036
  }
4045
- let proxy = new Proxy(openai, {
4037
+ return new Proxy(openai, {
4046
4038
  get(target, name, receiver) {
4047
4039
  if (name === "chat") {
4048
4040
  return chatProxy;
@@ -4050,13 +4042,15 @@ function wrapOpenAIv4(openai) {
4050
4042
  if (name === "embeddings") {
4051
4043
  return embeddingProxy;
4052
4044
  }
4045
+ if (name === "moderations") {
4046
+ return moderationProxy;
4047
+ }
4053
4048
  if (name === "beta" && betaProxy) {
4054
4049
  return betaProxy;
4055
4050
  }
4056
4051
  return Reflect.get(target, name, receiver);
4057
4052
  }
4058
4053
  });
4059
- return proxy;
4060
4054
  }
4061
4055
  function logCompletionResponse(startTime, response, span) {
4062
4056
  span.log({
@@ -4205,7 +4199,7 @@ function wrapChatCompletion(completion) {
4205
4199
  }
4206
4200
  };
4207
4201
  }
4208
- function parseChatCompletionParams(allParams) {
4202
+ function parseBaseParams(allParams, inputField) {
4209
4203
  const { span_info, ...params } = allParams;
4210
4204
  const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
4211
4205
  let ret = {
@@ -4214,10 +4208,12 @@ function parseChatCompletionParams(allParams) {
4214
4208
  metadata: spanInfoMetadata
4215
4209
  }
4216
4210
  };
4217
- const { messages, ...paramsRest } = params;
4218
- return (0, import_core3.mergeDicts)(ret, { event: { input: messages, metadata: paramsRest } });
4211
+ const input = params[inputField];
4212
+ const paramsRest = { ...params };
4213
+ delete paramsRest[inputField];
4214
+ return (0, import_core3.mergeDicts)(ret, { event: { input, metadata: paramsRest } });
4219
4215
  }
4220
- function wrapEmbeddings(create) {
4216
+ function createApiWrapper(name, create, processResponse, parseParams) {
4221
4217
  return async (allParams, options) => {
4222
4218
  const { span_info: _, ...params } = allParams;
4223
4219
  return traced(
@@ -4227,42 +4223,61 @@ function wrapEmbeddings(create) {
4227
4223
  options
4228
4224
  ).withResponse();
4229
4225
  logHeaders(response, span);
4230
- const embedding_length = result.data[0].embedding.length;
4231
- span.log({
4232
- // TODO: Add a flag to control whether to log the full embedding vector,
4233
- // possibly w/ JSON compression.
4234
- output: { embedding_length },
4235
- metrics: {
4236
- tokens: result.usage?.total_tokens,
4237
- prompt_tokens: result.usage?.prompt_tokens
4238
- }
4239
- });
4226
+ processResponse(result, span);
4240
4227
  return result;
4241
4228
  },
4242
4229
  (0, import_core3.mergeDicts)(
4243
4230
  {
4244
- name: "Embedding",
4231
+ name,
4245
4232
  spanAttributes: {
4246
4233
  type: import_core2.SpanTypeAttribute.LLM
4247
4234
  }
4248
4235
  },
4249
- parseEmbeddingParams(allParams)
4236
+ parseParams(allParams)
4250
4237
  )
4251
4238
  );
4252
4239
  };
4253
4240
  }
4254
- function parseEmbeddingParams(allParams) {
4255
- const { span_info, ...params } = allParams;
4256
- const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
4257
- let ret = {
4258
- ...spanInfoRest,
4259
- event: {
4260
- metadata: spanInfoMetadata
4241
+ function createEndpointProxy(target, wrapperFn) {
4242
+ return new Proxy(target, {
4243
+ get(target2, name, receiver) {
4244
+ const baseVal = Reflect.get(target2, name, receiver);
4245
+ if (name === "create") {
4246
+ return wrapperFn(baseVal.bind(target2));
4247
+ }
4248
+ return baseVal;
4261
4249
  }
4262
- };
4263
- const { input, ...paramsRest } = params;
4264
- return (0, import_core3.mergeDicts)(ret, { event: { input, metadata: paramsRest } });
4250
+ });
4251
+ }
4252
+ function parseChatCompletionParams(params) {
4253
+ return parseBaseParams(params, "messages");
4254
+ }
4255
+ function processEmbeddingResponse(result, span) {
4256
+ span.log({
4257
+ output: { embedding_length: result.data[0].embedding.length },
4258
+ metrics: {
4259
+ tokens: result.usage?.total_tokens,
4260
+ prompt_tokens: result.usage?.prompt_tokens
4261
+ }
4262
+ });
4263
+ }
4264
+ function processModerationResponse(result, span) {
4265
+ span.log({
4266
+ output: result.results
4267
+ });
4265
4268
  }
4269
+ var wrapEmbeddings = (create) => createApiWrapper(
4270
+ "Embedding",
4271
+ create,
4272
+ processEmbeddingResponse,
4273
+ (params) => parseBaseParams(params, "input")
4274
+ );
4275
+ var wrapModerations = (create) => createApiWrapper(
4276
+ "Moderation",
4277
+ create,
4278
+ processModerationResponse,
4279
+ (params) => parseBaseParams(params, "input")
4280
+ );
4266
4281
  function postprocessStreamingResults(allResults) {
4267
4282
  let role = void 0;
4268
4283
  let content = void 0;
package/dist/browser.mjs CHANGED
@@ -1137,16 +1137,35 @@ var ReadonlyAttachment = class {
1137
1137
  async data() {
1138
1138
  return this._data.get();
1139
1139
  }
1140
+ /**
1141
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
1142
+ * This will re-fetch the status each time in case it changes over time.
1143
+ */
1144
+ async metadata() {
1145
+ const state = this.state ?? _globalState;
1146
+ await state.login({});
1147
+ const resp = await state.apiConn().get("/attachment", {
1148
+ key: this.reference.key,
1149
+ filename: this.reference.filename,
1150
+ content_type: this.reference.content_type,
1151
+ org_id: state.orgId || ""
1152
+ });
1153
+ if (!resp.ok) {
1154
+ const errorStr = JSON.stringify(resp);
1155
+ throw new Error(`Invalid response from API server: ${errorStr}`);
1156
+ }
1157
+ return attachmentMetadataSchema.parse(await resp.json());
1158
+ }
1140
1159
  /**
1141
1160
  * Fetch the attachment upload status. This will re-fetch the status each time
1142
1161
  * in case it changes over time.
1143
1162
  */
1144
1163
  async status() {
1145
- return (await this.fetchMetadata()).status;
1164
+ return (await this.metadata()).status;
1146
1165
  }
1147
1166
  initDownloader() {
1148
1167
  const download = async () => {
1149
- const { downloadUrl, status } = await this.fetchMetadata();
1168
+ const { downloadUrl, status } = await this.metadata();
1150
1169
  if (status.upload_status !== "done") {
1151
1170
  throw new Error(
1152
1171
  `Expected attachment status "done", got "${status.upload_status}"`
@@ -1161,21 +1180,6 @@ var ReadonlyAttachment = class {
1161
1180
  };
1162
1181
  return new LazyValue(download);
1163
1182
  }
1164
- async fetchMetadata() {
1165
- const state = this.state ?? _globalState;
1166
- await state.login({});
1167
- const resp = await state.apiConn().get("/attachment", {
1168
- key: this.reference.key,
1169
- filename: this.reference.filename,
1170
- content_type: this.reference.content_type,
1171
- org_id: state.orgId || ""
1172
- });
1173
- if (!resp.ok) {
1174
- const errorStr = JSON.stringify(resp);
1175
- throw new Error(`Invalid response from API server: ${errorStr}`);
1176
- }
1177
- return attachmentMetadataSchema.parse(await resp.json());
1178
- }
1179
1183
  };
1180
1184
  function logFeedbackImpl(state, parentObjectType, parentObjectId, {
1181
1185
  id,
@@ -3936,16 +3940,11 @@ function wrapOpenAI(openai) {
3936
3940
  }
3937
3941
  globalThis.__inherited_braintrust_wrap_openai = wrapOpenAI;
3938
3942
  function wrapOpenAIv4(openai) {
3939
- let completionProxy = new Proxy(openai.chat.completions, {
3940
- get(target, name, receiver) {
3941
- const baseVal = Reflect.get(target, name, receiver);
3942
- if (name === "create") {
3943
- return wrapChatCompletion(baseVal.bind(target));
3944
- }
3945
- return baseVal;
3946
- }
3947
- });
3948
- let chatProxy = new Proxy(openai.chat, {
3943
+ const completionProxy = createEndpointProxy(
3944
+ openai.chat.completions,
3945
+ wrapChatCompletion
3946
+ );
3947
+ const chatProxy = new Proxy(openai.chat, {
3949
3948
  get(target, name, receiver) {
3950
3949
  if (name === "completions") {
3951
3950
  return completionProxy;
@@ -3953,18 +3952,11 @@ function wrapOpenAIv4(openai) {
3953
3952
  return Reflect.get(target, name, receiver);
3954
3953
  }
3955
3954
  });
3956
- let embeddingProxy = new Proxy(openai.embeddings, {
3957
- get(target, name, receiver) {
3958
- const baseVal = Reflect.get(target, name, receiver);
3959
- if (name === "create") {
3960
- return wrapEmbeddings(baseVal.bind(target));
3961
- }
3962
- return baseVal;
3963
- }
3964
- });
3955
+ const embeddingProxy = createEndpointProxy(openai.embeddings, wrapEmbeddings);
3956
+ const moderationProxy = createEndpointProxy(openai.moderations, wrapModerations);
3965
3957
  let betaProxy;
3966
3958
  if (openai.beta?.chat?.completions?.stream) {
3967
- let betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
3959
+ const betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
3968
3960
  get(target, name, receiver) {
3969
3961
  const baseVal = Reflect.get(target, name, receiver);
3970
3962
  if (name === "parse") {
@@ -3975,7 +3967,7 @@ function wrapOpenAIv4(openai) {
3975
3967
  return baseVal;
3976
3968
  }
3977
3969
  });
3978
- let betaChatProxy = new Proxy(openai.beta.chat, {
3970
+ const betaChatProxy = new Proxy(openai.beta.chat, {
3979
3971
  get(target, name, receiver) {
3980
3972
  if (name === "completions") {
3981
3973
  return betaChatCompletionProxy;
@@ -3992,7 +3984,7 @@ function wrapOpenAIv4(openai) {
3992
3984
  }
3993
3985
  });
3994
3986
  }
3995
- let proxy = new Proxy(openai, {
3987
+ return new Proxy(openai, {
3996
3988
  get(target, name, receiver) {
3997
3989
  if (name === "chat") {
3998
3990
  return chatProxy;
@@ -4000,13 +3992,15 @@ function wrapOpenAIv4(openai) {
4000
3992
  if (name === "embeddings") {
4001
3993
  return embeddingProxy;
4002
3994
  }
3995
+ if (name === "moderations") {
3996
+ return moderationProxy;
3997
+ }
4003
3998
  if (name === "beta" && betaProxy) {
4004
3999
  return betaProxy;
4005
4000
  }
4006
4001
  return Reflect.get(target, name, receiver);
4007
4002
  }
4008
4003
  });
4009
- return proxy;
4010
4004
  }
4011
4005
  function logCompletionResponse(startTime, response, span) {
4012
4006
  span.log({
@@ -4155,7 +4149,7 @@ function wrapChatCompletion(completion) {
4155
4149
  }
4156
4150
  };
4157
4151
  }
4158
- function parseChatCompletionParams(allParams) {
4152
+ function parseBaseParams(allParams, inputField) {
4159
4153
  const { span_info, ...params } = allParams;
4160
4154
  const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
4161
4155
  let ret = {
@@ -4164,10 +4158,12 @@ function parseChatCompletionParams(allParams) {
4164
4158
  metadata: spanInfoMetadata
4165
4159
  }
4166
4160
  };
4167
- const { messages, ...paramsRest } = params;
4168
- return mergeDicts2(ret, { event: { input: messages, metadata: paramsRest } });
4161
+ const input = params[inputField];
4162
+ const paramsRest = { ...params };
4163
+ delete paramsRest[inputField];
4164
+ return mergeDicts2(ret, { event: { input, metadata: paramsRest } });
4169
4165
  }
4170
- function wrapEmbeddings(create) {
4166
+ function createApiWrapper(name, create, processResponse, parseParams) {
4171
4167
  return async (allParams, options) => {
4172
4168
  const { span_info: _, ...params } = allParams;
4173
4169
  return traced(
@@ -4177,42 +4173,61 @@ function wrapEmbeddings(create) {
4177
4173
  options
4178
4174
  ).withResponse();
4179
4175
  logHeaders(response, span);
4180
- const embedding_length = result.data[0].embedding.length;
4181
- span.log({
4182
- // TODO: Add a flag to control whether to log the full embedding vector,
4183
- // possibly w/ JSON compression.
4184
- output: { embedding_length },
4185
- metrics: {
4186
- tokens: result.usage?.total_tokens,
4187
- prompt_tokens: result.usage?.prompt_tokens
4188
- }
4189
- });
4176
+ processResponse(result, span);
4190
4177
  return result;
4191
4178
  },
4192
4179
  mergeDicts2(
4193
4180
  {
4194
- name: "Embedding",
4181
+ name,
4195
4182
  spanAttributes: {
4196
4183
  type: SpanTypeAttribute2.LLM
4197
4184
  }
4198
4185
  },
4199
- parseEmbeddingParams(allParams)
4186
+ parseParams(allParams)
4200
4187
  )
4201
4188
  );
4202
4189
  };
4203
4190
  }
4204
- function parseEmbeddingParams(allParams) {
4205
- const { span_info, ...params } = allParams;
4206
- const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
4207
- let ret = {
4208
- ...spanInfoRest,
4209
- event: {
4210
- metadata: spanInfoMetadata
4191
+ function createEndpointProxy(target, wrapperFn) {
4192
+ return new Proxy(target, {
4193
+ get(target2, name, receiver) {
4194
+ const baseVal = Reflect.get(target2, name, receiver);
4195
+ if (name === "create") {
4196
+ return wrapperFn(baseVal.bind(target2));
4197
+ }
4198
+ return baseVal;
4211
4199
  }
4212
- };
4213
- const { input, ...paramsRest } = params;
4214
- return mergeDicts2(ret, { event: { input, metadata: paramsRest } });
4200
+ });
4201
+ }
4202
+ function parseChatCompletionParams(params) {
4203
+ return parseBaseParams(params, "messages");
4204
+ }
4205
+ function processEmbeddingResponse(result, span) {
4206
+ span.log({
4207
+ output: { embedding_length: result.data[0].embedding.length },
4208
+ metrics: {
4209
+ tokens: result.usage?.total_tokens,
4210
+ prompt_tokens: result.usage?.prompt_tokens
4211
+ }
4212
+ });
4213
+ }
4214
+ function processModerationResponse(result, span) {
4215
+ span.log({
4216
+ output: result.results
4217
+ });
4215
4218
  }
4219
+ var wrapEmbeddings = (create) => createApiWrapper(
4220
+ "Embedding",
4221
+ create,
4222
+ processEmbeddingResponse,
4223
+ (params) => parseBaseParams(params, "input")
4224
+ );
4225
+ var wrapModerations = (create) => createApiWrapper(
4226
+ "Moderation",
4227
+ create,
4228
+ processModerationResponse,
4229
+ (params) => parseBaseParams(params, "input")
4230
+ );
4216
4231
  function postprocessStreamingResults(allResults) {
4217
4232
  let role = void 0;
4218
4233
  let content = void 0;
package/dist/cli.js CHANGED
@@ -1236,7 +1236,7 @@ var require_package = __commonJS({
1236
1236
  "package.json"(exports2, module2) {
1237
1237
  module2.exports = {
1238
1238
  name: "braintrust",
1239
- version: "0.0.180",
1239
+ version: "0.0.182",
1240
1240
  description: "SDK for integrating Braintrust",
1241
1241
  repository: {
1242
1242
  type: "git",
@@ -1311,7 +1311,7 @@ var require_package = __commonJS({
1311
1311
  },
1312
1312
  dependencies: {
1313
1313
  "@ai-sdk/provider": "^1.0.1",
1314
- "@braintrust/core": "0.0.74",
1314
+ "@braintrust/core": "0.0.76",
1315
1315
  "@next/env": "^14.2.3",
1316
1316
  "@vercel/functions": "^1.0.2",
1317
1317
  ai: "^3.2.16",
@@ -2457,16 +2457,35 @@ var ReadonlyAttachment = class {
2457
2457
  async data() {
2458
2458
  return this._data.get();
2459
2459
  }
2460
+ /**
2461
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
2462
+ * This will re-fetch the status each time in case it changes over time.
2463
+ */
2464
+ async metadata() {
2465
+ const state = this.state ?? _globalState;
2466
+ await state.login({});
2467
+ const resp = await state.apiConn().get("/attachment", {
2468
+ key: this.reference.key,
2469
+ filename: this.reference.filename,
2470
+ content_type: this.reference.content_type,
2471
+ org_id: state.orgId || ""
2472
+ });
2473
+ if (!resp.ok) {
2474
+ const errorStr = JSON.stringify(resp);
2475
+ throw new Error(`Invalid response from API server: ${errorStr}`);
2476
+ }
2477
+ return attachmentMetadataSchema.parse(await resp.json());
2478
+ }
2460
2479
  /**
2461
2480
  * Fetch the attachment upload status. This will re-fetch the status each time
2462
2481
  * in case it changes over time.
2463
2482
  */
2464
2483
  async status() {
2465
- return (await this.fetchMetadata()).status;
2484
+ return (await this.metadata()).status;
2466
2485
  }
2467
2486
  initDownloader() {
2468
2487
  const download = async () => {
2469
- const { downloadUrl, status } = await this.fetchMetadata();
2488
+ const { downloadUrl, status } = await this.metadata();
2470
2489
  if (status.upload_status !== "done") {
2471
2490
  throw new Error(
2472
2491
  `Expected attachment status "done", got "${status.upload_status}"`
@@ -2481,21 +2500,6 @@ var ReadonlyAttachment = class {
2481
2500
  };
2482
2501
  return new LazyValue(download);
2483
2502
  }
2484
- async fetchMetadata() {
2485
- const state = this.state ?? _globalState;
2486
- await state.login({});
2487
- const resp = await state.apiConn().get("/attachment", {
2488
- key: this.reference.key,
2489
- filename: this.reference.filename,
2490
- content_type: this.reference.content_type,
2491
- org_id: state.orgId || ""
2492
- });
2493
- if (!resp.ok) {
2494
- const errorStr = JSON.stringify(resp);
2495
- throw new Error(`Invalid response from API server: ${errorStr}`);
2496
- }
2497
- return attachmentMetadataSchema.parse(await resp.json());
2498
- }
2499
2503
  };
2500
2504
  function logFeedbackImpl(state, parentObjectType, parentObjectId, {
2501
2505
  id,
package/dist/index.d.mts CHANGED
@@ -523,6 +523,32 @@ declare class Attachment {
523
523
  private initUploader;
524
524
  private initData;
525
525
  }
526
+ declare const attachmentMetadataSchema: z.ZodObject<{
527
+ downloadUrl: z.ZodString;
528
+ status: z.ZodObject<{
529
+ upload_status: z.ZodEnum<["uploading", "done", "error"]>;
530
+ error_message: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
531
+ }, "strip", z.ZodTypeAny, {
532
+ upload_status: "error" | "done" | "uploading";
533
+ error_message?: string | undefined;
534
+ }, {
535
+ upload_status: "error" | "done" | "uploading";
536
+ error_message?: string | null | undefined;
537
+ }>;
538
+ }, "strip", z.ZodTypeAny, {
539
+ status: {
540
+ upload_status: "error" | "done" | "uploading";
541
+ error_message?: string | undefined;
542
+ };
543
+ downloadUrl: string;
544
+ }, {
545
+ status: {
546
+ upload_status: "error" | "done" | "uploading";
547
+ error_message?: string | null | undefined;
548
+ };
549
+ downloadUrl: string;
550
+ }>;
551
+ type AttachmentMetadata = z.infer<typeof attachmentMetadataSchema>;
526
552
  /**
527
553
  * A readonly alternative to `Attachment`, which can be used for fetching
528
554
  * already-uploaded Attachments.
@@ -548,13 +574,17 @@ declare class ReadonlyAttachment {
548
574
  * contents from the object store on first access.
549
575
  */
550
576
  data(): Promise<Blob>;
577
+ /**
578
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
579
+ * This will re-fetch the status each time in case it changes over time.
580
+ */
581
+ metadata(): Promise<AttachmentMetadata>;
551
582
  /**
552
583
  * Fetch the attachment upload status. This will re-fetch the status each time
553
584
  * in case it changes over time.
554
585
  */
555
586
  status(): Promise<AttachmentStatus>;
556
587
  private initDownloader;
557
- private fetchMetadata;
558
588
  }
559
589
  /**
560
590
  * Update a span using the output of `span.export()`. It is important that you only resume updating
@@ -2170,6 +2200,7 @@ interface ChatLike {
2170
2200
  interface OpenAILike {
2171
2201
  chat: ChatLike;
2172
2202
  embeddings: any;
2203
+ moderations: any;
2173
2204
  beta?: BetaLike;
2174
2205
  }
2175
2206
  declare global {
package/dist/index.d.ts CHANGED
@@ -523,6 +523,32 @@ declare class Attachment {
523
523
  private initUploader;
524
524
  private initData;
525
525
  }
526
+ declare const attachmentMetadataSchema: z.ZodObject<{
527
+ downloadUrl: z.ZodString;
528
+ status: z.ZodObject<{
529
+ upload_status: z.ZodEnum<["uploading", "done", "error"]>;
530
+ error_message: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
531
+ }, "strip", z.ZodTypeAny, {
532
+ upload_status: "error" | "done" | "uploading";
533
+ error_message?: string | undefined;
534
+ }, {
535
+ upload_status: "error" | "done" | "uploading";
536
+ error_message?: string | null | undefined;
537
+ }>;
538
+ }, "strip", z.ZodTypeAny, {
539
+ status: {
540
+ upload_status: "error" | "done" | "uploading";
541
+ error_message?: string | undefined;
542
+ };
543
+ downloadUrl: string;
544
+ }, {
545
+ status: {
546
+ upload_status: "error" | "done" | "uploading";
547
+ error_message?: string | null | undefined;
548
+ };
549
+ downloadUrl: string;
550
+ }>;
551
+ type AttachmentMetadata = z.infer<typeof attachmentMetadataSchema>;
526
552
  /**
527
553
  * A readonly alternative to `Attachment`, which can be used for fetching
528
554
  * already-uploaded Attachments.
@@ -548,13 +574,17 @@ declare class ReadonlyAttachment {
548
574
  * contents from the object store on first access.
549
575
  */
550
576
  data(): Promise<Blob>;
577
+ /**
578
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
579
+ * This will re-fetch the status each time in case it changes over time.
580
+ */
581
+ metadata(): Promise<AttachmentMetadata>;
551
582
  /**
552
583
  * Fetch the attachment upload status. This will re-fetch the status each time
553
584
  * in case it changes over time.
554
585
  */
555
586
  status(): Promise<AttachmentStatus>;
556
587
  private initDownloader;
557
- private fetchMetadata;
558
588
  }
559
589
  /**
560
590
  * Update a span using the output of `span.export()`. It is important that you only resume updating
@@ -2170,6 +2200,7 @@ interface ChatLike {
2170
2200
  interface OpenAILike {
2171
2201
  chat: ChatLike;
2172
2202
  embeddings: any;
2203
+ moderations: any;
2173
2204
  beta?: BetaLike;
2174
2205
  }
2175
2206
  declare global {
package/dist/index.js CHANGED
@@ -1425,16 +1425,35 @@ var ReadonlyAttachment = class {
1425
1425
  async data() {
1426
1426
  return this._data.get();
1427
1427
  }
1428
+ /**
1429
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
1430
+ * This will re-fetch the status each time in case it changes over time.
1431
+ */
1432
+ async metadata() {
1433
+ const state = this.state ?? _globalState;
1434
+ await state.login({});
1435
+ const resp = await state.apiConn().get("/attachment", {
1436
+ key: this.reference.key,
1437
+ filename: this.reference.filename,
1438
+ content_type: this.reference.content_type,
1439
+ org_id: state.orgId || ""
1440
+ });
1441
+ if (!resp.ok) {
1442
+ const errorStr = JSON.stringify(resp);
1443
+ throw new Error(`Invalid response from API server: ${errorStr}`);
1444
+ }
1445
+ return attachmentMetadataSchema.parse(await resp.json());
1446
+ }
1428
1447
  /**
1429
1448
  * Fetch the attachment upload status. This will re-fetch the status each time
1430
1449
  * in case it changes over time.
1431
1450
  */
1432
1451
  async status() {
1433
- return (await this.fetchMetadata()).status;
1452
+ return (await this.metadata()).status;
1434
1453
  }
1435
1454
  initDownloader() {
1436
1455
  const download = async () => {
1437
- const { downloadUrl, status } = await this.fetchMetadata();
1456
+ const { downloadUrl, status } = await this.metadata();
1438
1457
  if (status.upload_status !== "done") {
1439
1458
  throw new Error(
1440
1459
  `Expected attachment status "done", got "${status.upload_status}"`
@@ -1449,21 +1468,6 @@ var ReadonlyAttachment = class {
1449
1468
  };
1450
1469
  return new LazyValue(download);
1451
1470
  }
1452
- async fetchMetadata() {
1453
- const state = this.state ?? _globalState;
1454
- await state.login({});
1455
- const resp = await state.apiConn().get("/attachment", {
1456
- key: this.reference.key,
1457
- filename: this.reference.filename,
1458
- content_type: this.reference.content_type,
1459
- org_id: state.orgId || ""
1460
- });
1461
- if (!resp.ok) {
1462
- const errorStr = JSON.stringify(resp);
1463
- throw new Error(`Invalid response from API server: ${errorStr}`);
1464
- }
1465
- return attachmentMetadataSchema.parse(await resp.json());
1466
- }
1467
1471
  };
1468
1472
  function logFeedbackImpl(state, parentObjectType, parentObjectId, {
1469
1473
  id,
@@ -6186,16 +6190,11 @@ function wrapOpenAI(openai) {
6186
6190
  }
6187
6191
  globalThis.__inherited_braintrust_wrap_openai = wrapOpenAI;
6188
6192
  function wrapOpenAIv4(openai) {
6189
- let completionProxy = new Proxy(openai.chat.completions, {
6190
- get(target, name, receiver) {
6191
- const baseVal = Reflect.get(target, name, receiver);
6192
- if (name === "create") {
6193
- return wrapChatCompletion(baseVal.bind(target));
6194
- }
6195
- return baseVal;
6196
- }
6197
- });
6198
- let chatProxy = new Proxy(openai.chat, {
6193
+ const completionProxy = createEndpointProxy(
6194
+ openai.chat.completions,
6195
+ wrapChatCompletion
6196
+ );
6197
+ const chatProxy = new Proxy(openai.chat, {
6199
6198
  get(target, name, receiver) {
6200
6199
  if (name === "completions") {
6201
6200
  return completionProxy;
@@ -6203,18 +6202,11 @@ function wrapOpenAIv4(openai) {
6203
6202
  return Reflect.get(target, name, receiver);
6204
6203
  }
6205
6204
  });
6206
- let embeddingProxy = new Proxy(openai.embeddings, {
6207
- get(target, name, receiver) {
6208
- const baseVal = Reflect.get(target, name, receiver);
6209
- if (name === "create") {
6210
- return wrapEmbeddings(baseVal.bind(target));
6211
- }
6212
- return baseVal;
6213
- }
6214
- });
6205
+ const embeddingProxy = createEndpointProxy(openai.embeddings, wrapEmbeddings);
6206
+ const moderationProxy = createEndpointProxy(openai.moderations, wrapModerations);
6215
6207
  let betaProxy;
6216
6208
  if (openai.beta?.chat?.completions?.stream) {
6217
- let betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
6209
+ const betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
6218
6210
  get(target, name, receiver) {
6219
6211
  const baseVal = Reflect.get(target, name, receiver);
6220
6212
  if (name === "parse") {
@@ -6225,7 +6217,7 @@ function wrapOpenAIv4(openai) {
6225
6217
  return baseVal;
6226
6218
  }
6227
6219
  });
6228
- let betaChatProxy = new Proxy(openai.beta.chat, {
6220
+ const betaChatProxy = new Proxy(openai.beta.chat, {
6229
6221
  get(target, name, receiver) {
6230
6222
  if (name === "completions") {
6231
6223
  return betaChatCompletionProxy;
@@ -6242,7 +6234,7 @@ function wrapOpenAIv4(openai) {
6242
6234
  }
6243
6235
  });
6244
6236
  }
6245
- let proxy = new Proxy(openai, {
6237
+ return new Proxy(openai, {
6246
6238
  get(target, name, receiver) {
6247
6239
  if (name === "chat") {
6248
6240
  return chatProxy;
@@ -6250,13 +6242,15 @@ function wrapOpenAIv4(openai) {
6250
6242
  if (name === "embeddings") {
6251
6243
  return embeddingProxy;
6252
6244
  }
6245
+ if (name === "moderations") {
6246
+ return moderationProxy;
6247
+ }
6253
6248
  if (name === "beta" && betaProxy) {
6254
6249
  return betaProxy;
6255
6250
  }
6256
6251
  return Reflect.get(target, name, receiver);
6257
6252
  }
6258
6253
  });
6259
- return proxy;
6260
6254
  }
6261
6255
  function logCompletionResponse(startTime, response, span) {
6262
6256
  span.log({
@@ -6405,7 +6399,7 @@ function wrapChatCompletion(completion) {
6405
6399
  }
6406
6400
  };
6407
6401
  }
6408
- function parseChatCompletionParams(allParams) {
6402
+ function parseBaseParams(allParams, inputField) {
6409
6403
  const { span_info, ...params } = allParams;
6410
6404
  const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
6411
6405
  let ret = {
@@ -6414,10 +6408,12 @@ function parseChatCompletionParams(allParams) {
6414
6408
  metadata: spanInfoMetadata
6415
6409
  }
6416
6410
  };
6417
- const { messages, ...paramsRest } = params;
6418
- return (0, import_core4.mergeDicts)(ret, { event: { input: messages, metadata: paramsRest } });
6411
+ const input = params[inputField];
6412
+ const paramsRest = { ...params };
6413
+ delete paramsRest[inputField];
6414
+ return (0, import_core4.mergeDicts)(ret, { event: { input, metadata: paramsRest } });
6419
6415
  }
6420
- function wrapEmbeddings(create) {
6416
+ function createApiWrapper(name, create, processResponse, parseParams) {
6421
6417
  return async (allParams, options) => {
6422
6418
  const { span_info: _, ...params } = allParams;
6423
6419
  return traced(
@@ -6427,42 +6423,61 @@ function wrapEmbeddings(create) {
6427
6423
  options
6428
6424
  ).withResponse();
6429
6425
  logHeaders(response, span);
6430
- const embedding_length = result.data[0].embedding.length;
6431
- span.log({
6432
- // TODO: Add a flag to control whether to log the full embedding vector,
6433
- // possibly w/ JSON compression.
6434
- output: { embedding_length },
6435
- metrics: {
6436
- tokens: result.usage?.total_tokens,
6437
- prompt_tokens: result.usage?.prompt_tokens
6438
- }
6439
- });
6426
+ processResponse(result, span);
6440
6427
  return result;
6441
6428
  },
6442
6429
  (0, import_core4.mergeDicts)(
6443
6430
  {
6444
- name: "Embedding",
6431
+ name,
6445
6432
  spanAttributes: {
6446
6433
  type: import_core3.SpanTypeAttribute.LLM
6447
6434
  }
6448
6435
  },
6449
- parseEmbeddingParams(allParams)
6436
+ parseParams(allParams)
6450
6437
  )
6451
6438
  );
6452
6439
  };
6453
6440
  }
6454
- function parseEmbeddingParams(allParams) {
6455
- const { span_info, ...params } = allParams;
6456
- const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
6457
- let ret = {
6458
- ...spanInfoRest,
6459
- event: {
6460
- metadata: spanInfoMetadata
6441
+ function createEndpointProxy(target, wrapperFn) {
6442
+ return new Proxy(target, {
6443
+ get(target2, name, receiver) {
6444
+ const baseVal = Reflect.get(target2, name, receiver);
6445
+ if (name === "create") {
6446
+ return wrapperFn(baseVal.bind(target2));
6447
+ }
6448
+ return baseVal;
6461
6449
  }
6462
- };
6463
- const { input, ...paramsRest } = params;
6464
- return (0, import_core4.mergeDicts)(ret, { event: { input, metadata: paramsRest } });
6450
+ });
6451
+ }
6452
+ function parseChatCompletionParams(params) {
6453
+ return parseBaseParams(params, "messages");
6454
+ }
6455
+ function processEmbeddingResponse(result, span) {
6456
+ span.log({
6457
+ output: { embedding_length: result.data[0].embedding.length },
6458
+ metrics: {
6459
+ tokens: result.usage?.total_tokens,
6460
+ prompt_tokens: result.usage?.prompt_tokens
6461
+ }
6462
+ });
6463
+ }
6464
+ function processModerationResponse(result, span) {
6465
+ span.log({
6466
+ output: result.results
6467
+ });
6465
6468
  }
6469
+ var wrapEmbeddings = (create) => createApiWrapper(
6470
+ "Embedding",
6471
+ create,
6472
+ processEmbeddingResponse,
6473
+ (params) => parseBaseParams(params, "input")
6474
+ );
6475
+ var wrapModerations = (create) => createApiWrapper(
6476
+ "Moderation",
6477
+ create,
6478
+ processModerationResponse,
6479
+ (params) => parseBaseParams(params, "input")
6480
+ );
6466
6481
  function postprocessStreamingResults(allResults) {
6467
6482
  let role = void 0;
6468
6483
  let content = void 0;
package/dist/index.mjs CHANGED
@@ -1357,16 +1357,35 @@ var ReadonlyAttachment = class {
1357
1357
  async data() {
1358
1358
  return this._data.get();
1359
1359
  }
1360
+ /**
1361
+ * Fetch the attachment metadata, which includes a downloadUrl and a status.
1362
+ * This will re-fetch the status each time in case it changes over time.
1363
+ */
1364
+ async metadata() {
1365
+ const state = this.state ?? _globalState;
1366
+ await state.login({});
1367
+ const resp = await state.apiConn().get("/attachment", {
1368
+ key: this.reference.key,
1369
+ filename: this.reference.filename,
1370
+ content_type: this.reference.content_type,
1371
+ org_id: state.orgId || ""
1372
+ });
1373
+ if (!resp.ok) {
1374
+ const errorStr = JSON.stringify(resp);
1375
+ throw new Error(`Invalid response from API server: ${errorStr}`);
1376
+ }
1377
+ return attachmentMetadataSchema.parse(await resp.json());
1378
+ }
1360
1379
  /**
1361
1380
  * Fetch the attachment upload status. This will re-fetch the status each time
1362
1381
  * in case it changes over time.
1363
1382
  */
1364
1383
  async status() {
1365
- return (await this.fetchMetadata()).status;
1384
+ return (await this.metadata()).status;
1366
1385
  }
1367
1386
  initDownloader() {
1368
1387
  const download = async () => {
1369
- const { downloadUrl, status } = await this.fetchMetadata();
1388
+ const { downloadUrl, status } = await this.metadata();
1370
1389
  if (status.upload_status !== "done") {
1371
1390
  throw new Error(
1372
1391
  `Expected attachment status "done", got "${status.upload_status}"`
@@ -1381,21 +1400,6 @@ var ReadonlyAttachment = class {
1381
1400
  };
1382
1401
  return new LazyValue(download);
1383
1402
  }
1384
- async fetchMetadata() {
1385
- const state = this.state ?? _globalState;
1386
- await state.login({});
1387
- const resp = await state.apiConn().get("/attachment", {
1388
- key: this.reference.key,
1389
- filename: this.reference.filename,
1390
- content_type: this.reference.content_type,
1391
- org_id: state.orgId || ""
1392
- });
1393
- if (!resp.ok) {
1394
- const errorStr = JSON.stringify(resp);
1395
- throw new Error(`Invalid response from API server: ${errorStr}`);
1396
- }
1397
- return attachmentMetadataSchema.parse(await resp.json());
1398
- }
1399
1403
  };
1400
1404
  function logFeedbackImpl(state, parentObjectType, parentObjectId, {
1401
1405
  id,
@@ -6122,16 +6126,11 @@ function wrapOpenAI(openai) {
6122
6126
  }
6123
6127
  globalThis.__inherited_braintrust_wrap_openai = wrapOpenAI;
6124
6128
  function wrapOpenAIv4(openai) {
6125
- let completionProxy = new Proxy(openai.chat.completions, {
6126
- get(target, name, receiver) {
6127
- const baseVal = Reflect.get(target, name, receiver);
6128
- if (name === "create") {
6129
- return wrapChatCompletion(baseVal.bind(target));
6130
- }
6131
- return baseVal;
6132
- }
6133
- });
6134
- let chatProxy = new Proxy(openai.chat, {
6129
+ const completionProxy = createEndpointProxy(
6130
+ openai.chat.completions,
6131
+ wrapChatCompletion
6132
+ );
6133
+ const chatProxy = new Proxy(openai.chat, {
6135
6134
  get(target, name, receiver) {
6136
6135
  if (name === "completions") {
6137
6136
  return completionProxy;
@@ -6139,18 +6138,11 @@ function wrapOpenAIv4(openai) {
6139
6138
  return Reflect.get(target, name, receiver);
6140
6139
  }
6141
6140
  });
6142
- let embeddingProxy = new Proxy(openai.embeddings, {
6143
- get(target, name, receiver) {
6144
- const baseVal = Reflect.get(target, name, receiver);
6145
- if (name === "create") {
6146
- return wrapEmbeddings(baseVal.bind(target));
6147
- }
6148
- return baseVal;
6149
- }
6150
- });
6141
+ const embeddingProxy = createEndpointProxy(openai.embeddings, wrapEmbeddings);
6142
+ const moderationProxy = createEndpointProxy(openai.moderations, wrapModerations);
6151
6143
  let betaProxy;
6152
6144
  if (openai.beta?.chat?.completions?.stream) {
6153
- let betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
6145
+ const betaChatCompletionProxy = new Proxy(openai?.beta?.chat.completions, {
6154
6146
  get(target, name, receiver) {
6155
6147
  const baseVal = Reflect.get(target, name, receiver);
6156
6148
  if (name === "parse") {
@@ -6161,7 +6153,7 @@ function wrapOpenAIv4(openai) {
6161
6153
  return baseVal;
6162
6154
  }
6163
6155
  });
6164
- let betaChatProxy = new Proxy(openai.beta.chat, {
6156
+ const betaChatProxy = new Proxy(openai.beta.chat, {
6165
6157
  get(target, name, receiver) {
6166
6158
  if (name === "completions") {
6167
6159
  return betaChatCompletionProxy;
@@ -6178,7 +6170,7 @@ function wrapOpenAIv4(openai) {
6178
6170
  }
6179
6171
  });
6180
6172
  }
6181
- let proxy = new Proxy(openai, {
6173
+ return new Proxy(openai, {
6182
6174
  get(target, name, receiver) {
6183
6175
  if (name === "chat") {
6184
6176
  return chatProxy;
@@ -6186,13 +6178,15 @@ function wrapOpenAIv4(openai) {
6186
6178
  if (name === "embeddings") {
6187
6179
  return embeddingProxy;
6188
6180
  }
6181
+ if (name === "moderations") {
6182
+ return moderationProxy;
6183
+ }
6189
6184
  if (name === "beta" && betaProxy) {
6190
6185
  return betaProxy;
6191
6186
  }
6192
6187
  return Reflect.get(target, name, receiver);
6193
6188
  }
6194
6189
  });
6195
- return proxy;
6196
6190
  }
6197
6191
  function logCompletionResponse(startTime, response, span) {
6198
6192
  span.log({
@@ -6341,7 +6335,7 @@ function wrapChatCompletion(completion) {
6341
6335
  }
6342
6336
  };
6343
6337
  }
6344
- function parseChatCompletionParams(allParams) {
6338
+ function parseBaseParams(allParams, inputField) {
6345
6339
  const { span_info, ...params } = allParams;
6346
6340
  const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
6347
6341
  let ret = {
@@ -6350,10 +6344,12 @@ function parseChatCompletionParams(allParams) {
6350
6344
  metadata: spanInfoMetadata
6351
6345
  }
6352
6346
  };
6353
- const { messages, ...paramsRest } = params;
6354
- return mergeDicts3(ret, { event: { input: messages, metadata: paramsRest } });
6347
+ const input = params[inputField];
6348
+ const paramsRest = { ...params };
6349
+ delete paramsRest[inputField];
6350
+ return mergeDicts3(ret, { event: { input, metadata: paramsRest } });
6355
6351
  }
6356
- function wrapEmbeddings(create) {
6352
+ function createApiWrapper(name, create, processResponse, parseParams) {
6357
6353
  return async (allParams, options) => {
6358
6354
  const { span_info: _, ...params } = allParams;
6359
6355
  return traced(
@@ -6363,42 +6359,61 @@ function wrapEmbeddings(create) {
6363
6359
  options
6364
6360
  ).withResponse();
6365
6361
  logHeaders(response, span);
6366
- const embedding_length = result.data[0].embedding.length;
6367
- span.log({
6368
- // TODO: Add a flag to control whether to log the full embedding vector,
6369
- // possibly w/ JSON compression.
6370
- output: { embedding_length },
6371
- metrics: {
6372
- tokens: result.usage?.total_tokens,
6373
- prompt_tokens: result.usage?.prompt_tokens
6374
- }
6375
- });
6362
+ processResponse(result, span);
6376
6363
  return result;
6377
6364
  },
6378
6365
  mergeDicts3(
6379
6366
  {
6380
- name: "Embedding",
6367
+ name,
6381
6368
  spanAttributes: {
6382
6369
  type: SpanTypeAttribute3.LLM
6383
6370
  }
6384
6371
  },
6385
- parseEmbeddingParams(allParams)
6372
+ parseParams(allParams)
6386
6373
  )
6387
6374
  );
6388
6375
  };
6389
6376
  }
6390
- function parseEmbeddingParams(allParams) {
6391
- const { span_info, ...params } = allParams;
6392
- const { metadata: spanInfoMetadata, ...spanInfoRest } = span_info ?? {};
6393
- let ret = {
6394
- ...spanInfoRest,
6395
- event: {
6396
- metadata: spanInfoMetadata
6377
+ function createEndpointProxy(target, wrapperFn) {
6378
+ return new Proxy(target, {
6379
+ get(target2, name, receiver) {
6380
+ const baseVal = Reflect.get(target2, name, receiver);
6381
+ if (name === "create") {
6382
+ return wrapperFn(baseVal.bind(target2));
6383
+ }
6384
+ return baseVal;
6397
6385
  }
6398
- };
6399
- const { input, ...paramsRest } = params;
6400
- return mergeDicts3(ret, { event: { input, metadata: paramsRest } });
6386
+ });
6387
+ }
6388
+ function parseChatCompletionParams(params) {
6389
+ return parseBaseParams(params, "messages");
6390
+ }
6391
+ function processEmbeddingResponse(result, span) {
6392
+ span.log({
6393
+ output: { embedding_length: result.data[0].embedding.length },
6394
+ metrics: {
6395
+ tokens: result.usage?.total_tokens,
6396
+ prompt_tokens: result.usage?.prompt_tokens
6397
+ }
6398
+ });
6399
+ }
6400
+ function processModerationResponse(result, span) {
6401
+ span.log({
6402
+ output: result.results
6403
+ });
6401
6404
  }
6405
+ var wrapEmbeddings = (create) => createApiWrapper(
6406
+ "Embedding",
6407
+ create,
6408
+ processEmbeddingResponse,
6409
+ (params) => parseBaseParams(params, "input")
6410
+ );
6411
+ var wrapModerations = (create) => createApiWrapper(
6412
+ "Moderation",
6413
+ create,
6414
+ processModerationResponse,
6415
+ (params) => parseBaseParams(params, "input")
6416
+ );
6402
6417
  function postprocessStreamingResults(allResults) {
6403
6418
  let role = void 0;
6404
6419
  let content = void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braintrust",
3
- "version": "0.0.180",
3
+ "version": "0.0.182",
4
4
  "description": "SDK for integrating Braintrust",
5
5
  "repository": {
6
6
  "type": "git",
@@ -75,7 +75,7 @@
75
75
  },
76
76
  "dependencies": {
77
77
  "@ai-sdk/provider": "^1.0.1",
78
- "@braintrust/core": "0.0.74",
78
+ "@braintrust/core": "0.0.76",
79
79
  "@next/env": "^14.2.3",
80
80
  "@vercel/functions": "^1.0.2",
81
81
  "ai": "^3.2.16",