braintrust 1.0.3 → 1.1.0-rc.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.
@@ -7795,6 +7795,8 @@ declare abstract class IDGenerator {
7795
7795
  abstract shareRootSpanId(): boolean;
7796
7796
  }
7797
7797
 
7798
+ type TemplateFormat = "mustache" | "nunjucks" | "none";
7799
+
7798
7800
  interface IsoAsyncLocalStorage<T> {
7799
7801
  enterWith(store: T): void;
7800
7802
  run<R>(store: T | undefined, callback: () => R): R;
@@ -8805,6 +8807,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8805
8807
  flavor?: Flavor;
8806
8808
  messages?: ChatCompletionMessageParamType[];
8807
8809
  strict?: boolean;
8810
+ templateFormat?: TemplateFormat;
8808
8811
  }): CompiledPrompt<Flavor>;
8809
8812
  /**
8810
8813
  * This is a special build method that first resolves attachment references, and then
@@ -8818,6 +8821,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8818
8821
  messages?: ChatCompletionMessageParamType[];
8819
8822
  strict?: boolean;
8820
8823
  state?: BraintrustState;
8824
+ templateFormat?: TemplateFormat;
8821
8825
  }): Promise<CompiledPrompt<Flavor>>;
8822
8826
  private runBuild;
8823
8827
  static renderPrompt({ prompt, buildArgs, options, }: {
@@ -8826,6 +8830,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8826
8830
  options: {
8827
8831
  strict?: boolean;
8828
8832
  messages?: ChatCompletionMessageParamType[];
8833
+ templateFormat?: TemplateFormat;
8829
8834
  };
8830
8835
  }): PromptBlockDataType;
8831
8836
  private getParsedPromptData;
@@ -7795,6 +7795,8 @@ declare abstract class IDGenerator {
7795
7795
  abstract shareRootSpanId(): boolean;
7796
7796
  }
7797
7797
 
7798
+ type TemplateFormat = "mustache" | "nunjucks" | "none";
7799
+
7798
7800
  interface IsoAsyncLocalStorage<T> {
7799
7801
  enterWith(store: T): void;
7800
7802
  run<R>(store: T | undefined, callback: () => R): R;
@@ -8805,6 +8807,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8805
8807
  flavor?: Flavor;
8806
8808
  messages?: ChatCompletionMessageParamType[];
8807
8809
  strict?: boolean;
8810
+ templateFormat?: TemplateFormat;
8808
8811
  }): CompiledPrompt<Flavor>;
8809
8812
  /**
8810
8813
  * This is a special build method that first resolves attachment references, and then
@@ -8818,6 +8821,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8818
8821
  messages?: ChatCompletionMessageParamType[];
8819
8822
  strict?: boolean;
8820
8823
  state?: BraintrustState;
8824
+ templateFormat?: TemplateFormat;
8821
8825
  }): Promise<CompiledPrompt<Flavor>>;
8822
8826
  private runBuild;
8823
8827
  static renderPrompt({ prompt, buildArgs, options, }: {
@@ -8826,6 +8830,7 @@ declare class Prompt<HasId extends boolean = true, HasVersion extends boolean =
8826
8830
  options: {
8827
8831
  strict?: boolean;
8828
8832
  messages?: ChatCompletionMessageParamType[];
8833
+ templateFormat?: TemplateFormat;
8829
8834
  };
8830
8835
  }): PromptBlockDataType;
8831
8836
  private getParsedPromptData;
package/dev/dist/index.js CHANGED
@@ -2925,6 +2925,199 @@ var View = _v3.z.object({
2925
2925
  var _functions = require('@vercel/functions');
2926
2926
  var _mustache = require('mustache'); var _mustache2 = _interopRequireDefault(_mustache);
2927
2927
 
2928
+ // src/template/renderer.ts
2929
+
2930
+
2931
+ // src/template/mustache-utils.ts
2932
+
2933
+ function lintTemplate(template, context) {
2934
+ const variables = getMustacheVars(template);
2935
+ for (const variable of variables) {
2936
+ const arrPathsReplaced = variable[1].replaceAll(/\.\d+/g, ".0");
2937
+ const fieldExists = getObjValueByPath(context, arrPathsReplaced.split(".")) !== void 0;
2938
+ if (!fieldExists) {
2939
+ throw new Error(`Variable '${variable[1]}' does not exist.`);
2940
+ }
2941
+ }
2942
+ }
2943
+ function getMustacheVars(prompt) {
2944
+ try {
2945
+ return _mustache2.default.parse(prompt).filter(
2946
+ (span) => span[0] === "name" || span[0] === "&"
2947
+ );
2948
+ } catch (e8) {
2949
+ return [];
2950
+ }
2951
+ }
2952
+
2953
+ // src/template/nunjucks-utils.ts
2954
+ var _nunjucks = require('nunjucks'); var nunjucks = _interopRequireWildcard(_nunjucks); var nunjucksNodeModule = _interopRequireWildcard(_nunjucks);
2955
+ function lintTemplate2(template, context) {
2956
+ const env = new nunjucks.Environment(null, {
2957
+ autoescape: true,
2958
+ throwOnUndefined: true
2959
+ });
2960
+ env.renderString(template, context);
2961
+ }
2962
+
2963
+ // src/template/nunjucks.ts
2964
+
2965
+ var nunjucks2 = nunjucksNodeModule;
2966
+
2967
+ // src/util.ts
2968
+ var GLOBAL_PROJECT = "Global";
2969
+ function runCatchFinally(f, catchF, finallyF) {
2970
+ let runSyncCleanup = true;
2971
+ try {
2972
+ const ret = f();
2973
+ if (ret instanceof Promise) {
2974
+ runSyncCleanup = false;
2975
+ return ret.catch(catchF).finally(finallyF);
2976
+ } else {
2977
+ return ret;
2978
+ }
2979
+ } catch (e) {
2980
+ return catchF(e);
2981
+ } finally {
2982
+ if (runSyncCleanup) {
2983
+ finallyF();
2984
+ }
2985
+ }
2986
+ }
2987
+ function getCurrentUnixTimestamp() {
2988
+ return (/* @__PURE__ */ new Date()).getTime() / 1e3;
2989
+ }
2990
+ function isEmpty2(a) {
2991
+ return a === void 0 || a === null;
2992
+ }
2993
+ var LazyValue = (_class2 = class {
2994
+
2995
+ __init3() {this.resolvedValue = void 0}
2996
+ __init4() {this.value = {
2997
+ computedState: "uninitialized"
2998
+ }}
2999
+ constructor(callable) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
3000
+ this.callable = callable;
3001
+ }
3002
+ get() {
3003
+ if (this.value.computedState !== "uninitialized") {
3004
+ return this.value.val;
3005
+ }
3006
+ this.value = {
3007
+ computedState: "in_progress",
3008
+ val: this.callable().then((x) => {
3009
+ this.value.computedState = "succeeded";
3010
+ this.resolvedValue = x;
3011
+ return x;
3012
+ })
3013
+ };
3014
+ return this.value.val;
3015
+ }
3016
+ getSync() {
3017
+ return {
3018
+ resolved: this.value.computedState === "succeeded",
3019
+ value: this.resolvedValue
3020
+ };
3021
+ }
3022
+ // If this is true, the caller should be able to obtain the LazyValue without
3023
+ // it throwing.
3024
+ get hasSucceeded() {
3025
+ return this.value.computedState === "succeeded";
3026
+ }
3027
+ }, _class2);
3028
+ var SyncLazyValue = (_class3 = class {
3029
+
3030
+ __init5() {this.value = {
3031
+ computedState: "uninitialized"
3032
+ }}
3033
+ constructor(callable) {;_class3.prototype.__init5.call(this);
3034
+ this.callable = callable;
3035
+ }
3036
+ get() {
3037
+ if (this.value.computedState !== "uninitialized") {
3038
+ return this.value.val;
3039
+ }
3040
+ const result = this.callable();
3041
+ this.value = { computedState: "succeeded", val: result };
3042
+ return result;
3043
+ }
3044
+ // If this is true, the caller should be able to obtain the SyncLazyValue without
3045
+ // it throwing.
3046
+ get hasSucceeded() {
3047
+ return this.value.computedState === "succeeded";
3048
+ }
3049
+ }, _class3);
3050
+ function addAzureBlobHeaders(headers, url) {
3051
+ if (url.includes("blob.core.windows.net")) {
3052
+ headers["x-ms-blob-type"] = "BlockBlob";
3053
+ }
3054
+ }
3055
+ var InternalAbortError = class extends Error {
3056
+ constructor(message) {
3057
+ super(message);
3058
+ this.name = "InternalAbortError";
3059
+ }
3060
+ };
3061
+
3062
+ // src/template/nunjucks-env.ts
3063
+ var createNunjucksEnv = (throwOnUndefined) => {
3064
+ return new nunjucks2.Environment(null, {
3065
+ autoescape: true,
3066
+ throwOnUndefined
3067
+ });
3068
+ };
3069
+ var nunjucksEnv = new SyncLazyValue(
3070
+ () => createNunjucksEnv(false)
3071
+ );
3072
+ var nunjucksStrictEnv = new SyncLazyValue(
3073
+ () => createNunjucksEnv(true)
3074
+ );
3075
+ function getNunjucksEnv(strict = false) {
3076
+ return strict ? nunjucksStrictEnv.get() : nunjucksEnv.get();
3077
+ }
3078
+ function renderNunjucksString(template, variables, strict = false) {
3079
+ try {
3080
+ return getNunjucksEnv(strict).renderString(template, variables);
3081
+ } catch (error) {
3082
+ if (error instanceof Error && error.message.includes(
3083
+ "Code generation from strings disallowed for this context"
3084
+ )) {
3085
+ throw new Error(
3086
+ `String template rendering. Disallowed in this environment for security reasons. Try a different template renderer. Original error: ${error.message}`
3087
+ );
3088
+ }
3089
+ throw error;
3090
+ }
3091
+ }
3092
+
3093
+ // src/template/renderer.ts
3094
+ function isTemplateFormat(v) {
3095
+ return v === "mustache" || v === "nunjucks" || v === "none";
3096
+ }
3097
+ function parseTemplateFormat(value, defaultFormat = "mustache") {
3098
+ return isTemplateFormat(value) ? value : defaultFormat;
3099
+ }
3100
+ function renderTemplateContent(template, variables, escape, options) {
3101
+ const strict = !!options.strict;
3102
+ const templateFormat = parseTemplateFormat(options.templateFormat);
3103
+ if (templateFormat === "nunjucks") {
3104
+ if (strict) {
3105
+ lintTemplate2(template, variables);
3106
+ }
3107
+ return renderNunjucksString(template, variables, strict);
3108
+ } else if (templateFormat === "mustache") {
3109
+ if (strict) {
3110
+ lintTemplate(template, variables);
3111
+ }
3112
+ return _mustache2.default.render(template, variables, void 0, {
3113
+ escape
3114
+ });
3115
+ }
3116
+ return template;
3117
+ }
3118
+
3119
+ // src/logger.ts
3120
+
2928
3121
 
2929
3122
  // src/functions/stream.ts
2930
3123
 
@@ -3451,123 +3644,6 @@ var PromptCache = class {
3451
3644
  }
3452
3645
  };
3453
3646
 
3454
- // src/util.ts
3455
- var GLOBAL_PROJECT = "Global";
3456
- function runCatchFinally(f, catchF, finallyF) {
3457
- let runSyncCleanup = true;
3458
- try {
3459
- const ret = f();
3460
- if (ret instanceof Promise) {
3461
- runSyncCleanup = false;
3462
- return ret.catch(catchF).finally(finallyF);
3463
- } else {
3464
- return ret;
3465
- }
3466
- } catch (e) {
3467
- return catchF(e);
3468
- } finally {
3469
- if (runSyncCleanup) {
3470
- finallyF();
3471
- }
3472
- }
3473
- }
3474
- function getCurrentUnixTimestamp() {
3475
- return (/* @__PURE__ */ new Date()).getTime() / 1e3;
3476
- }
3477
- function isEmpty2(a) {
3478
- return a === void 0 || a === null;
3479
- }
3480
- var LazyValue = (_class2 = class {
3481
-
3482
- __init3() {this.resolvedValue = void 0}
3483
- __init4() {this.value = {
3484
- computedState: "uninitialized"
3485
- }}
3486
- constructor(callable) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
3487
- this.callable = callable;
3488
- }
3489
- get() {
3490
- if (this.value.computedState !== "uninitialized") {
3491
- return this.value.val;
3492
- }
3493
- this.value = {
3494
- computedState: "in_progress",
3495
- val: this.callable().then((x) => {
3496
- this.value.computedState = "succeeded";
3497
- this.resolvedValue = x;
3498
- return x;
3499
- })
3500
- };
3501
- return this.value.val;
3502
- }
3503
- getSync() {
3504
- return {
3505
- resolved: this.value.computedState === "succeeded",
3506
- value: this.resolvedValue
3507
- };
3508
- }
3509
- // If this is true, the caller should be able to obtain the LazyValue without
3510
- // it throwing.
3511
- get hasSucceeded() {
3512
- return this.value.computedState === "succeeded";
3513
- }
3514
- }, _class2);
3515
- var SyncLazyValue = (_class3 = class {
3516
-
3517
- __init5() {this.value = {
3518
- computedState: "uninitialized"
3519
- }}
3520
- constructor(callable) {;_class3.prototype.__init5.call(this);
3521
- this.callable = callable;
3522
- }
3523
- get() {
3524
- if (this.value.computedState !== "uninitialized") {
3525
- return this.value.val;
3526
- }
3527
- const result = this.callable();
3528
- this.value = { computedState: "succeeded", val: result };
3529
- return result;
3530
- }
3531
- // If this is true, the caller should be able to obtain the SyncLazyValue without
3532
- // it throwing.
3533
- get hasSucceeded() {
3534
- return this.value.computedState === "succeeded";
3535
- }
3536
- }, _class3);
3537
- function addAzureBlobHeaders(headers, url) {
3538
- if (url.includes("blob.core.windows.net")) {
3539
- headers["x-ms-blob-type"] = "BlockBlob";
3540
- }
3541
- }
3542
- var InternalAbortError = class extends Error {
3543
- constructor(message) {
3544
- super(message);
3545
- this.name = "InternalAbortError";
3546
- }
3547
- };
3548
-
3549
- // src/mustache-utils.ts
3550
-
3551
- function lintTemplate(template, context) {
3552
- const variables = getMustacheVars(template);
3553
- for (const variable of variables) {
3554
- const arrPathsReplaced = variable[1].replaceAll(/\.\d+/g, ".0");
3555
- const fieldExists = getObjValueByPath(context, arrPathsReplaced.split(".")) !== void 0;
3556
- if (!fieldExists) {
3557
- throw new Error(`Variable '${variable[1]}' does not exist.`);
3558
- }
3559
- }
3560
- }
3561
- function getMustacheVars(prompt) {
3562
- try {
3563
- return _mustache2.default.parse(prompt).filter(
3564
- (span) => span[0] === "name" || span[0] === "&"
3565
- );
3566
- } catch (e8) {
3567
- return [];
3568
- }
3569
- }
3570
-
3571
3647
  // src/logger.ts
3572
3648
  var BRAINTRUST_ATTACHMENT = BraintrustAttachmentReference.shape.type.value;
3573
3649
  var EXTERNAL_ATTACHMENT = ExternalAttachmentReference.shape.type.value;
@@ -7054,18 +7130,28 @@ function deserializePlainStringAsJSON(s) {
7054
7130
  }
7055
7131
  function renderTemplatedObject(obj, args, options) {
7056
7132
  if (typeof obj === "string") {
7057
- if (options.strict) {
7058
- lintTemplate(obj, args);
7133
+ const strict = !!options.strict;
7134
+ if (options.templateFormat === "nunjucks") {
7135
+ if (strict) {
7136
+ lintTemplate2(obj, args);
7137
+ }
7138
+ return renderNunjucksString(obj, args, strict);
7059
7139
  }
7060
- return _mustache2.default.render(obj, args, void 0, {
7061
- escape: (value) => {
7062
- if (typeof value === "string") {
7063
- return value;
7064
- } else {
7065
- return JSON.stringify(value);
7066
- }
7140
+ if (options.templateFormat === "mustache") {
7141
+ if (strict) {
7142
+ lintTemplate(obj, args);
7067
7143
  }
7068
- });
7144
+ return _mustache2.default.render(obj, args, void 0, {
7145
+ escape: (value) => {
7146
+ if (typeof value === "string") {
7147
+ return value;
7148
+ } else {
7149
+ return JSON.stringify(value);
7150
+ }
7151
+ }
7152
+ });
7153
+ }
7154
+ return obj;
7069
7155
  } else if (isArray(obj)) {
7070
7156
  return obj.map((item) => renderTemplatedObject(item, args, options));
7071
7157
  } else if (isObject(obj)) {
@@ -7078,7 +7164,9 @@ function renderTemplatedObject(obj, args, options) {
7078
7164
  }
7079
7165
  return obj;
7080
7166
  }
7081
- function renderPromptParams(params, args, options) {
7167
+ function renderPromptParams(params, args, options = {}) {
7168
+ const templateFormat = parseTemplateFormat(options.templateFormat);
7169
+ const strict = !!options.strict;
7082
7170
  const schemaParsed = _v3.z.object({
7083
7171
  response_format: _v3.z.object({
7084
7172
  type: _v3.z.literal("json_schema"),
@@ -7089,7 +7177,10 @@ function renderPromptParams(params, args, options) {
7089
7177
  }).safeParse(params);
7090
7178
  if (schemaParsed.success) {
7091
7179
  const rawSchema = schemaParsed.data.response_format.json_schema.schema;
7092
- const templatedSchema = renderTemplatedObject(rawSchema, args, options);
7180
+ const templatedSchema = renderTemplatedObject(rawSchema, args, {
7181
+ strict,
7182
+ templateFormat
7183
+ });
7093
7184
  const parsedSchema = typeof templatedSchema === "string" ? deserializePlainStringAsJSON(templatedSchema).value : templatedSchema;
7094
7185
  return {
7095
7186
  ...params,
@@ -7148,7 +7239,8 @@ var Prompt2 = (_class12 = class _Prompt {
7148
7239
  return this.runBuild(buildArgs, {
7149
7240
  flavor: _nullishCoalesce(options.flavor, () => ( "chat")),
7150
7241
  messages: options.messages,
7151
- strict: options.strict
7242
+ strict: options.strict,
7243
+ templateFormat: options.templateFormat
7152
7244
  });
7153
7245
  }
7154
7246
  /**
@@ -7163,7 +7255,8 @@ var Prompt2 = (_class12 = class _Prompt {
7163
7255
  return this.runBuild(hydrated, {
7164
7256
  flavor: _nullishCoalesce(options.flavor, () => ( "chat")),
7165
7257
  messages: options.messages,
7166
- strict: options.strict
7258
+ strict: options.strict,
7259
+ templateFormat: options.templateFormat
7167
7260
  });
7168
7261
  }
7169
7262
  runBuild(buildArgs, options) {
@@ -7206,10 +7299,11 @@ var Prompt2 = (_class12 = class _Prompt {
7206
7299
  input: buildArgs,
7207
7300
  ...dictArgParsed.success ? dictArgParsed.data : {}
7208
7301
  };
7302
+ const resolvedTemplateFormat = parseTemplateFormat(options.templateFormat);
7209
7303
  const renderedPrompt = _Prompt.renderPrompt({
7210
7304
  prompt,
7211
7305
  buildArgs,
7212
- options
7306
+ options: { ...options, templateFormat: resolvedTemplateFormat }
7213
7307
  });
7214
7308
  if (flavor === "chat") {
7215
7309
  if (renderedPrompt.type !== "chat") {
@@ -7218,7 +7312,10 @@ var Prompt2 = (_class12 = class _Prompt {
7218
7312
  );
7219
7313
  }
7220
7314
  return {
7221
- ...renderPromptParams(params, variables, { strict: options.strict }),
7315
+ ...renderPromptParams(params, variables, {
7316
+ strict: options.strict,
7317
+ templateFormat: resolvedTemplateFormat
7318
+ }),
7222
7319
  ...spanInfo,
7223
7320
  messages: renderedPrompt.messages,
7224
7321
  ...renderedPrompt.tools ? {
@@ -7230,7 +7327,10 @@ var Prompt2 = (_class12 = class _Prompt {
7230
7327
  throw new Error(`Prompt is a chat prompt. Use flavor: 'chat' instead`);
7231
7328
  }
7232
7329
  return {
7233
- ...renderPromptParams(params, variables, { strict: options.strict }),
7330
+ ...renderPromptParams(params, variables, {
7331
+ strict: options.strict,
7332
+ templateFormat: resolvedTemplateFormat
7333
+ }),
7234
7334
  ...spanInfo,
7235
7335
  prompt: renderedPrompt.content
7236
7336
  };
@@ -7261,15 +7361,12 @@ var Prompt2 = (_class12 = class _Prompt {
7261
7361
  input: buildArgs,
7262
7362
  ...dictArgParsed.success ? dictArgParsed.data : {}
7263
7363
  };
7364
+ const templateFormat = parseTemplateFormat(options.templateFormat);
7264
7365
  if (prompt.type === "chat") {
7265
- const render = (template) => {
7266
- if (options.strict) {
7267
- lintTemplate(template, variables);
7268
- }
7269
- return _mustache2.default.render(template, variables, void 0, {
7270
- escape
7271
- });
7272
- };
7366
+ const render = (template) => renderTemplateContent(template, variables, escape, {
7367
+ strict: options.strict,
7368
+ templateFormat
7369
+ });
7273
7370
  const baseMessages = (prompt.messages || []).map(
7274
7371
  (m) => renderMessage(render, m)
7275
7372
  );
@@ -7293,14 +7390,13 @@ var Prompt2 = (_class12 = class _Prompt {
7293
7390
  "extra messages are not supported for completion prompts"
7294
7391
  );
7295
7392
  }
7296
- if (options.strict) {
7297
- lintTemplate(prompt.content, variables);
7298
- }
7393
+ const content = renderTemplateContent(prompt.content, variables, escape, {
7394
+ strict: options.strict,
7395
+ templateFormat
7396
+ });
7299
7397
  return {
7300
7398
  type: "completion",
7301
- content: _mustache2.default.render(prompt.content, variables, void 0, {
7302
- escape
7303
- })
7399
+ content
7304
7400
  };
7305
7401
  } else {
7306
7402
  const _ = prompt;