braintrust 3.26.0 → 3.28.0
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.
- package/dev/dist/index.d.mts +519 -186
- package/dev/dist/index.d.ts +519 -186
- package/dev/dist/index.js +3727 -1526
- package/dev/dist/index.mjs +2815 -614
- package/dist/apply-auto-instrumentation.js +372 -261
- package/dist/apply-auto-instrumentation.mjs +171 -60
- package/dist/auto-instrumentations/bundler/esbuild.cjs +458 -61
- package/dist/auto-instrumentations/bundler/esbuild.mjs +5 -4
- package/dist/auto-instrumentations/bundler/next.cjs +460 -63
- package/dist/auto-instrumentations/bundler/next.mjs +6 -5
- package/dist/auto-instrumentations/bundler/rollup.cjs +458 -61
- package/dist/auto-instrumentations/bundler/rollup.mjs +5 -4
- package/dist/auto-instrumentations/bundler/vite.cjs +487 -62
- package/dist/auto-instrumentations/bundler/vite.mjs +34 -5
- package/dist/auto-instrumentations/bundler/webpack-loader.cjs +444 -61
- package/dist/auto-instrumentations/bundler/webpack.cjs +458 -61
- package/dist/auto-instrumentations/bundler/webpack.mjs +6 -5
- package/dist/auto-instrumentations/{chunk-6E22MYSW.mjs → chunk-26PKVUKB.mjs} +109 -5
- package/dist/auto-instrumentations/{chunk-AKKPLXTP.mjs → chunk-2AMDGD65.mjs} +160 -57
- package/dist/auto-instrumentations/{chunk-V5LEODRX.mjs → chunk-HD35AM3M.mjs} +1 -1
- package/dist/auto-instrumentations/{chunk-XYN63IG5.mjs → chunk-I55G56ZL.mjs} +21 -58
- package/dist/auto-instrumentations/{chunk-NRE4QUQR.mjs → chunk-JPUFNW7X.mjs} +140 -0
- package/dist/auto-instrumentations/{chunk-XZHHE4Y3.mjs → chunk-NP7V4XB2.mjs} +157 -3
- package/dist/auto-instrumentations/hook.mjs +396 -32
- package/dist/auto-instrumentations/index.cjs +298 -2
- package/dist/auto-instrumentations/index.d.mts +5 -1
- package/dist/auto-instrumentations/index.d.ts +5 -1
- package/dist/auto-instrumentations/index.mjs +6 -2
- package/dist/auto-instrumentations/loader/cjs-patch.cjs +105 -57
- package/dist/auto-instrumentations/loader/cjs-patch.mjs +2 -2
- package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
- package/dist/browser.d.mts +683 -56
- package/dist/browser.d.ts +683 -56
- package/dist/browser.js +4242 -655
- package/dist/browser.mjs +4242 -655
- package/dist/{chunk-VYNNEKSA.js → chunk-BBE7SNRV.js} +248 -10
- package/dist/{chunk-VRZZQPAA.js → chunk-OBBWQW6K.js} +3351 -1392
- package/dist/{chunk-XIZOM2HO.mjs → chunk-UPFNQCGB.mjs} +2419 -460
- package/dist/{chunk-PN7EWK66.mjs → chunk-ZHUHZWFY.mjs} +241 -3
- package/dist/cli.js +2867 -668
- package/dist/edge-light.d.mts +1 -1
- package/dist/edge-light.d.ts +1 -1
- package/dist/edge-light.js +4242 -655
- package/dist/edge-light.mjs +4242 -655
- package/dist/index.d.mts +1267 -640
- package/dist/index.d.ts +1267 -640
- package/dist/index.js +2107 -630
- package/dist/index.mjs +1649 -172
- package/dist/instrumentation/index.d.mts +198 -6
- package/dist/instrumentation/index.d.ts +198 -6
- package/dist/instrumentation/index.js +2661 -581
- package/dist/instrumentation/index.mjs +2661 -581
- package/dist/vitest-evals-reporter.js +45 -43
- package/dist/vitest-evals-reporter.mjs +5 -3
- package/dist/workerd.d.mts +1 -1
- package/dist/workerd.d.ts +1 -1
- package/dist/workerd.js +4242 -655
- package/dist/workerd.mjs +4242 -655
- package/package.json +2 -3
- package/util/dist/index.d.mts +1545 -100
- package/util/dist/index.d.ts +1545 -100
package/dist/index.mjs
CHANGED
|
@@ -55,14 +55,17 @@ import {
|
|
|
55
55
|
X_CACHED_HEADER,
|
|
56
56
|
_exportsForTestingOnly,
|
|
57
57
|
_internalGetGlobalState,
|
|
58
|
+
_internalResumeSpan,
|
|
58
59
|
_internalSetInitialState,
|
|
59
60
|
_internalStartSpanWithInitialMerge,
|
|
60
61
|
addAzureBlobHeaders,
|
|
62
|
+
base64ToUint8Array,
|
|
61
63
|
braintrustAISDKTelemetry,
|
|
62
64
|
braintrustFlueInstrumentation,
|
|
63
65
|
braintrustFlueObserver,
|
|
64
66
|
braintrustStreamChunkSchema,
|
|
65
67
|
buildBedrockRuntimeSpanInfo,
|
|
68
|
+
collectAnthropicSession,
|
|
66
69
|
configureInstrumentation,
|
|
67
70
|
configureNode,
|
|
68
71
|
constructLogs3OverflowRequest,
|
|
@@ -104,7 +107,6 @@ import {
|
|
|
104
107
|
loginToState,
|
|
105
108
|
logs3OverflowUploadSchema,
|
|
106
109
|
makeScorerPropagatedEvent,
|
|
107
|
-
mergeDicts,
|
|
108
110
|
newId,
|
|
109
111
|
parseCachedHeader,
|
|
110
112
|
parseTemplateFormat,
|
|
@@ -126,8 +128,10 @@ import {
|
|
|
126
128
|
summarize,
|
|
127
129
|
summarizeAndFlush,
|
|
128
130
|
templateRegistry,
|
|
131
|
+
toNumericMetrics,
|
|
129
132
|
traceable,
|
|
130
133
|
traced,
|
|
134
|
+
uint8ArrayToBase64,
|
|
131
135
|
updateSpan,
|
|
132
136
|
uploadLogs3OverflowPayload,
|
|
133
137
|
utf8ByteLength,
|
|
@@ -140,7 +144,7 @@ import {
|
|
|
140
144
|
wrapMastraAgent,
|
|
141
145
|
wrapTraced,
|
|
142
146
|
zodToJsonSchema
|
|
143
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-UPFNQCGB.mjs";
|
|
144
148
|
import {
|
|
145
149
|
INSTRUMENTATION_NAMES,
|
|
146
150
|
__export,
|
|
@@ -149,6 +153,7 @@ import {
|
|
|
149
153
|
bedrockRuntimeChannels,
|
|
150
154
|
claudeAgentSDKChannels,
|
|
151
155
|
cloudflareAgentsChannels,
|
|
156
|
+
cloudflareThinkChannels,
|
|
152
157
|
cohereChannels,
|
|
153
158
|
cursorSDKChannels,
|
|
154
159
|
genkitChannels,
|
|
@@ -163,14 +168,16 @@ import {
|
|
|
163
168
|
isomorph_default,
|
|
164
169
|
langSmithChannels,
|
|
165
170
|
mistralChannels,
|
|
171
|
+
ollamaChannels,
|
|
166
172
|
openAIChannels,
|
|
167
173
|
openAICodexChannels,
|
|
168
174
|
openRouterAgentChannels,
|
|
169
175
|
openRouterChannels,
|
|
170
176
|
piCodingAgentChannels,
|
|
171
177
|
strandsAgentSDKChannels,
|
|
178
|
+
voyageAIChannels,
|
|
172
179
|
withSpanInstrumentationName
|
|
173
|
-
} from "./chunk-
|
|
180
|
+
} from "./chunk-ZHUHZWFY.mjs";
|
|
174
181
|
|
|
175
182
|
// src/exports.ts
|
|
176
183
|
var exports_exports = {};
|
|
@@ -183,6 +190,8 @@ __export(exports_exports, {
|
|
|
183
190
|
BRAINTRUST_PARENT_KEY: () => BRAINTRUST_PARENT_KEY,
|
|
184
191
|
BaseAttachment: () => BaseAttachment,
|
|
185
192
|
BaseExperiment: () => BaseExperiment,
|
|
193
|
+
BatchScorer: () => BatchScorer,
|
|
194
|
+
BatchTask: () => BatchTask,
|
|
186
195
|
BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
|
|
187
196
|
BraintrustMiddleware: () => BraintrustMiddleware,
|
|
188
197
|
BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
|
|
@@ -196,6 +205,8 @@ __export(exports_exports, {
|
|
|
196
205
|
DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
|
|
197
206
|
Dataset: () => Dataset,
|
|
198
207
|
DatasetPipeline: () => DatasetPipeline,
|
|
208
|
+
DurableEvalMemoryStore: () => DurableEvalMemoryStore,
|
|
209
|
+
DurableEvalRedisStore: () => DurableEvalRedisStore,
|
|
199
210
|
ERR_PERMALINK: () => ERR_PERMALINK,
|
|
200
211
|
Eval: () => Eval,
|
|
201
212
|
EvalResultWithSummary: () => EvalResultWithSummary,
|
|
@@ -244,6 +255,7 @@ __export(exports_exports, {
|
|
|
244
255
|
braintrustFlueObserver: () => braintrustFlueObserver,
|
|
245
256
|
braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
|
|
246
257
|
buildLocalSummary: () => buildLocalSummary,
|
|
258
|
+
collectAnthropicSession: () => collectAnthropicSession,
|
|
247
259
|
configureInstrumentation: () => configureInstrumentation,
|
|
248
260
|
constructLogs3OverflowRequest: () => constructLogs3OverflowRequest,
|
|
249
261
|
createFinalValuePassThroughStream: () => createFinalValuePassThroughStream,
|
|
@@ -252,6 +264,7 @@ __export(exports_exports, {
|
|
|
252
264
|
currentSpan: () => currentSpan,
|
|
253
265
|
deepCopyEvent: () => deepCopyEvent,
|
|
254
266
|
defaultErrorScoreHandler: () => defaultErrorScoreHandler,
|
|
267
|
+
defineDurableEval: () => defineDurableEval,
|
|
255
268
|
deserializePlainStringAsJSON: () => deserializePlainStringAsJSON,
|
|
256
269
|
devNullWritableStream: () => devNullWritableStream,
|
|
257
270
|
evaluatorDefinitionSchema: () => evaluatorDefinitionSchema,
|
|
@@ -323,6 +336,7 @@ __export(exports_exports, {
|
|
|
323
336
|
wrapClaudeAgentSDK: () => wrapClaudeAgentSDK,
|
|
324
337
|
wrapCloudflareAIChat: () => wrapCloudflareAIChat,
|
|
325
338
|
wrapCloudflareAgent: () => wrapCloudflareAgent,
|
|
339
|
+
wrapCloudflareThink: () => wrapCloudflareThink,
|
|
326
340
|
wrapCohere: () => wrapCohere,
|
|
327
341
|
wrapCopilotClient: () => wrapCopilotClient,
|
|
328
342
|
wrapCursorSDK: () => wrapCursorSDK,
|
|
@@ -337,6 +351,7 @@ __export(exports_exports, {
|
|
|
337
351
|
wrapLangSmithTraceable: () => wrapLangSmithTraceable,
|
|
338
352
|
wrapMastraAgent: () => wrapMastraAgent,
|
|
339
353
|
wrapMistral: () => wrapMistral,
|
|
354
|
+
wrapOllama: () => wrapOllama,
|
|
340
355
|
wrapOpenAI: () => wrapOpenAI,
|
|
341
356
|
wrapOpenAICodexSDK: () => wrapOpenAICodexSDK,
|
|
342
357
|
wrapOpenAIv4: () => wrapOpenAIv4,
|
|
@@ -345,7 +360,8 @@ __export(exports_exports, {
|
|
|
345
360
|
wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
|
|
346
361
|
wrapStrandsAgentSDK: () => wrapStrandsAgentSDK,
|
|
347
362
|
wrapTraced: () => wrapTraced,
|
|
348
|
-
wrapVitest: () => wrapVitest
|
|
363
|
+
wrapVitest: () => wrapVitest,
|
|
364
|
+
wrapVoyageAI: () => wrapVoyageAI
|
|
349
365
|
});
|
|
350
366
|
|
|
351
367
|
// src/sandbox.ts
|
|
@@ -1606,7 +1622,7 @@ function normalizeUsageMetrics(usage, provider, providerMetadata) {
|
|
|
1606
1622
|
cacheCreationTokens
|
|
1607
1623
|
);
|
|
1608
1624
|
Object.assign(metrics, cacheTokens);
|
|
1609
|
-
|
|
1625
|
+
return toNumericMetrics(finalizeAnthropicTokens(metrics));
|
|
1610
1626
|
}
|
|
1611
1627
|
}
|
|
1612
1628
|
return metrics;
|
|
@@ -3541,6 +3557,66 @@ function betaProxy(beta, anthropic) {
|
|
|
3541
3557
|
if (prop === "messages") {
|
|
3542
3558
|
return betaMessagesProxy(target.messages, anthropic);
|
|
3543
3559
|
}
|
|
3560
|
+
if (prop === "sessions") {
|
|
3561
|
+
return target.sessions ? betaSessionsProxy(target.sessions) : target.sessions;
|
|
3562
|
+
}
|
|
3563
|
+
return Reflect.get(target, prop, receiver);
|
|
3564
|
+
}
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
function betaSessionsProxy(sessions) {
|
|
3568
|
+
return new Proxy(sessions, {
|
|
3569
|
+
get(target, prop, receiver) {
|
|
3570
|
+
if (prop === "events") {
|
|
3571
|
+
return betaSessionEventsProxy(target.events);
|
|
3572
|
+
}
|
|
3573
|
+
if (prop === "threads") {
|
|
3574
|
+
return target.threads ? betaSessionThreadsProxy(target.threads) : target.threads;
|
|
3575
|
+
}
|
|
3576
|
+
return Reflect.get(target, prop, receiver);
|
|
3577
|
+
}
|
|
3578
|
+
});
|
|
3579
|
+
}
|
|
3580
|
+
function betaSessionEventsProxy(events) {
|
|
3581
|
+
return new Proxy(events, {
|
|
3582
|
+
get(target, prop, receiver) {
|
|
3583
|
+
if (prop === "stream") {
|
|
3584
|
+
return new TypedApplyProxy(target.stream, {
|
|
3585
|
+
apply(stream, thisArg, argArray) {
|
|
3586
|
+
return anthropicChannels.betaSessionsEventsStream.tracePromise(
|
|
3587
|
+
() => Reflect.apply(stream, thisArg, argArray),
|
|
3588
|
+
{ arguments: argArray }
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
});
|
|
3592
|
+
}
|
|
3593
|
+
return Reflect.get(target, prop, receiver);
|
|
3594
|
+
}
|
|
3595
|
+
});
|
|
3596
|
+
}
|
|
3597
|
+
function betaSessionThreadsProxy(threads) {
|
|
3598
|
+
return new Proxy(threads, {
|
|
3599
|
+
get(target, prop, receiver) {
|
|
3600
|
+
if (prop === "events") {
|
|
3601
|
+
return betaSessionThreadEventsProxy(target.events);
|
|
3602
|
+
}
|
|
3603
|
+
return Reflect.get(target, prop, receiver);
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
}
|
|
3607
|
+
function betaSessionThreadEventsProxy(events) {
|
|
3608
|
+
return new Proxy(events, {
|
|
3609
|
+
get(target, prop, receiver) {
|
|
3610
|
+
if (prop === "stream") {
|
|
3611
|
+
return new TypedApplyProxy(target.stream, {
|
|
3612
|
+
apply(stream, thisArg, argArray) {
|
|
3613
|
+
return anthropicChannels.betaSessionsThreadsEventsStream.tracePromise(
|
|
3614
|
+
() => Reflect.apply(stream, thisArg, argArray),
|
|
3615
|
+
{ arguments: argArray }
|
|
3616
|
+
);
|
|
3617
|
+
}
|
|
3618
|
+
});
|
|
3619
|
+
}
|
|
3544
3620
|
return Reflect.get(target, prop, receiver);
|
|
3545
3621
|
}
|
|
3546
3622
|
});
|
|
@@ -3734,6 +3810,52 @@ function claudeAgentSDKProxy(sdk) {
|
|
|
3734
3810
|
});
|
|
3735
3811
|
}
|
|
3736
3812
|
|
|
3813
|
+
// src/wrappers/cloudflare-think.ts
|
|
3814
|
+
var WRAPPED_THINK = /* @__PURE__ */ Symbol.for("braintrust.cloudflare-think.wrapped");
|
|
3815
|
+
function wrapCloudflareThink(sdk) {
|
|
3816
|
+
if (!sdk || typeof sdk !== "object") {
|
|
3817
|
+
return sdk;
|
|
3818
|
+
}
|
|
3819
|
+
const thinkModule = sdk;
|
|
3820
|
+
if (typeof thinkModule.Think !== "function") {
|
|
3821
|
+
return sdk;
|
|
3822
|
+
}
|
|
3823
|
+
patchThinkClass(thinkModule.Think);
|
|
3824
|
+
return sdk;
|
|
3825
|
+
}
|
|
3826
|
+
function patchThinkClass(Think) {
|
|
3827
|
+
const prototype = Think.prototype;
|
|
3828
|
+
if (!prototype || prototype[WRAPPED_THINK]) {
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
const descriptor = Object.getOwnPropertyDescriptor(
|
|
3832
|
+
prototype,
|
|
3833
|
+
"_runInferenceLoop"
|
|
3834
|
+
);
|
|
3835
|
+
if (!descriptor || typeof descriptor.value !== "function") {
|
|
3836
|
+
return;
|
|
3837
|
+
}
|
|
3838
|
+
const original = descriptor.value;
|
|
3839
|
+
Object.defineProperty(prototype, "_runInferenceLoop", {
|
|
3840
|
+
...descriptor,
|
|
3841
|
+
value: function wrappedCloudflareThinkRunInferenceLoop(input) {
|
|
3842
|
+
const args = [input];
|
|
3843
|
+
return cloudflareThinkChannels.runInferenceLoop.tracePromise(
|
|
3844
|
+
() => Reflect.apply(original, this, args),
|
|
3845
|
+
{
|
|
3846
|
+
arguments: args,
|
|
3847
|
+
self: this
|
|
3848
|
+
}
|
|
3849
|
+
);
|
|
3850
|
+
}
|
|
3851
|
+
});
|
|
3852
|
+
Object.defineProperty(prototype, WRAPPED_THINK, {
|
|
3853
|
+
configurable: false,
|
|
3854
|
+
enumerable: false,
|
|
3855
|
+
value: true
|
|
3856
|
+
});
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3737
3859
|
// src/wrappers/openai-codex.ts
|
|
3738
3860
|
var WRAPPED_CLIENT = /* @__PURE__ */ Symbol.for("braintrust.openai-codex.wrapped-client");
|
|
3739
3861
|
var WRAPPED_THREAD = /* @__PURE__ */ Symbol.for("braintrust.openai-codex.wrapped-thread");
|
|
@@ -4026,14 +4148,9 @@ function patchAgentSessionClass(AgentSession) {
|
|
|
4026
4148
|
...descriptor,
|
|
4027
4149
|
value: function wrappedPiCodingAgentPrompt(text, options) {
|
|
4028
4150
|
const args = [text, options];
|
|
4029
|
-
return piCodingAgentChannels.prompt.
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
arguments: args,
|
|
4033
|
-
self: this,
|
|
4034
|
-
session: this
|
|
4035
|
-
}
|
|
4036
|
-
);
|
|
4151
|
+
return piCodingAgentChannels.prompt.invoke(originalPrompt, this, args, {
|
|
4152
|
+
session: this
|
|
4153
|
+
});
|
|
4037
4154
|
}
|
|
4038
4155
|
});
|
|
4039
4156
|
Object.defineProperty(prototype, WRAPPED_PROMPT, {
|
|
@@ -5473,6 +5590,83 @@ function wrapAgentsStream(stream) {
|
|
|
5473
5590
|
});
|
|
5474
5591
|
}
|
|
5475
5592
|
|
|
5593
|
+
// src/wrappers/ollama.ts
|
|
5594
|
+
function wrapOllama(ollama) {
|
|
5595
|
+
if (isSupportedOllamaClient(ollama)) {
|
|
5596
|
+
return ollamaProxy(ollama);
|
|
5597
|
+
}
|
|
5598
|
+
debugLogger.warn("Unsupported Ollama library. Not wrapping.");
|
|
5599
|
+
return ollama;
|
|
5600
|
+
}
|
|
5601
|
+
var ollamaProxyCache = /* @__PURE__ */ new WeakMap();
|
|
5602
|
+
function isSupportedOllamaClient(value) {
|
|
5603
|
+
return isObject(value) && ["chat", "generate", "embed"].some(
|
|
5604
|
+
(name) => typeof value[name] === "function"
|
|
5605
|
+
);
|
|
5606
|
+
}
|
|
5607
|
+
function ollamaProxy(ollama) {
|
|
5608
|
+
const cached = ollamaProxyCache.get(ollama);
|
|
5609
|
+
if (cached) {
|
|
5610
|
+
return cached;
|
|
5611
|
+
}
|
|
5612
|
+
let chatSource;
|
|
5613
|
+
let wrappedChat;
|
|
5614
|
+
let generateSource;
|
|
5615
|
+
let wrappedGenerate;
|
|
5616
|
+
let embedSource;
|
|
5617
|
+
let wrappedEmbed;
|
|
5618
|
+
const proxy = new Proxy(ollama, {
|
|
5619
|
+
get(target, prop, receiver) {
|
|
5620
|
+
switch (prop) {
|
|
5621
|
+
case "chat": {
|
|
5622
|
+
const source = target.chat;
|
|
5623
|
+
if (source !== chatSource) {
|
|
5624
|
+
chatSource = source;
|
|
5625
|
+
wrappedChat = typeof source === "function" ? wrapChat(source.bind(target)) : source;
|
|
5626
|
+
}
|
|
5627
|
+
return wrappedChat;
|
|
5628
|
+
}
|
|
5629
|
+
case "generate": {
|
|
5630
|
+
const source = target.generate;
|
|
5631
|
+
if (source !== generateSource) {
|
|
5632
|
+
generateSource = source;
|
|
5633
|
+
wrappedGenerate = typeof source === "function" ? wrapGenerate2(source.bind(target)) : source;
|
|
5634
|
+
}
|
|
5635
|
+
return wrappedGenerate;
|
|
5636
|
+
}
|
|
5637
|
+
case "embed": {
|
|
5638
|
+
const source = target.embed;
|
|
5639
|
+
if (source !== embedSource) {
|
|
5640
|
+
embedSource = source;
|
|
5641
|
+
wrappedEmbed = typeof source === "function" ? wrapEmbed3(source.bind(target)) : source;
|
|
5642
|
+
}
|
|
5643
|
+
return wrappedEmbed;
|
|
5644
|
+
}
|
|
5645
|
+
default:
|
|
5646
|
+
return Reflect.get(target, prop, receiver);
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
});
|
|
5650
|
+
ollamaProxyCache.set(ollama, proxy);
|
|
5651
|
+
ollamaProxyCache.set(proxy, proxy);
|
|
5652
|
+
return proxy;
|
|
5653
|
+
}
|
|
5654
|
+
function wrapChat(chat) {
|
|
5655
|
+
return (request) => ollamaChannels.chat.tracePromise(() => chat(request), {
|
|
5656
|
+
arguments: [request]
|
|
5657
|
+
});
|
|
5658
|
+
}
|
|
5659
|
+
function wrapGenerate2(generate) {
|
|
5660
|
+
return (request) => ollamaChannels.generate.tracePromise(() => generate(request), {
|
|
5661
|
+
arguments: [request]
|
|
5662
|
+
});
|
|
5663
|
+
}
|
|
5664
|
+
function wrapEmbed3(embed) {
|
|
5665
|
+
return (request) => ollamaChannels.embed.tracePromise(() => embed(request), {
|
|
5666
|
+
arguments: [request]
|
|
5667
|
+
});
|
|
5668
|
+
}
|
|
5669
|
+
|
|
5476
5670
|
// src/wrappers/cohere.ts
|
|
5477
5671
|
function wrapCohere(cohere) {
|
|
5478
5672
|
if (isSupportedCohereClient(cohere)) {
|
|
@@ -5503,11 +5697,11 @@ function cohereProxy(cohere) {
|
|
|
5503
5697
|
get(target, prop, receiver) {
|
|
5504
5698
|
switch (prop) {
|
|
5505
5699
|
case "chat":
|
|
5506
|
-
return typeof target.chat === "function" ?
|
|
5700
|
+
return typeof target.chat === "function" ? wrapChat2(target.chat.bind(target)) : target.chat;
|
|
5507
5701
|
case "chatStream":
|
|
5508
5702
|
return typeof target.chatStream === "function" ? wrapChatStream2(target.chatStream.bind(target)) : target.chatStream;
|
|
5509
5703
|
case "embed":
|
|
5510
|
-
return typeof target.embed === "function" ?
|
|
5704
|
+
return typeof target.embed === "function" ? wrapEmbed4(target.embed.bind(target)) : target.embed;
|
|
5511
5705
|
case "rerank":
|
|
5512
5706
|
return typeof target.rerank === "function" ? wrapRerank3(target.rerank.bind(target)) : target.rerank;
|
|
5513
5707
|
default: {
|
|
@@ -5520,7 +5714,7 @@ function cohereProxy(cohere) {
|
|
|
5520
5714
|
cohereProxyCache.set(cohere, proxy);
|
|
5521
5715
|
return proxy;
|
|
5522
5716
|
}
|
|
5523
|
-
function
|
|
5717
|
+
function wrapChat2(chat) {
|
|
5524
5718
|
return (request, options) => cohereChannels.chat.tracePromise(() => chat(request, options), {
|
|
5525
5719
|
arguments: [request]
|
|
5526
5720
|
});
|
|
@@ -5530,7 +5724,7 @@ function wrapChatStream2(chatStream) {
|
|
|
5530
5724
|
arguments: [request]
|
|
5531
5725
|
});
|
|
5532
5726
|
}
|
|
5533
|
-
function
|
|
5727
|
+
function wrapEmbed4(embed) {
|
|
5534
5728
|
return (request, options) => cohereChannels.embed.tracePromise(() => embed(request, options), {
|
|
5535
5729
|
arguments: [request]
|
|
5536
5730
|
});
|
|
@@ -5541,6 +5735,84 @@ function wrapRerank3(rerank) {
|
|
|
5541
5735
|
});
|
|
5542
5736
|
}
|
|
5543
5737
|
|
|
5738
|
+
// src/wrappers/voyageai.ts
|
|
5739
|
+
function wrapVoyageAI(client) {
|
|
5740
|
+
if (!isSupportedVoyageAIClient(client)) {
|
|
5741
|
+
console.warn("Unsupported Voyage AI library. Not wrapping.");
|
|
5742
|
+
return client;
|
|
5743
|
+
}
|
|
5744
|
+
return voyageAIProxy(client);
|
|
5745
|
+
}
|
|
5746
|
+
var voyageAIProxyCache = /* @__PURE__ */ new WeakMap();
|
|
5747
|
+
function isObject2(value) {
|
|
5748
|
+
return typeof value === "object" && value !== null;
|
|
5749
|
+
}
|
|
5750
|
+
function hasFunction5(value, name) {
|
|
5751
|
+
return typeof Reflect.get(value, name) === "function";
|
|
5752
|
+
}
|
|
5753
|
+
function isSupportedVoyageAIClient(value) {
|
|
5754
|
+
if (!isObject2(value)) {
|
|
5755
|
+
return false;
|
|
5756
|
+
}
|
|
5757
|
+
return hasFunction5(value, "embed") || hasFunction5(value, "multimodalEmbed") || hasFunction5(value, "rerank") || hasFunction5(value, "contextualizedEmbed");
|
|
5758
|
+
}
|
|
5759
|
+
function voyageAIProxy(client) {
|
|
5760
|
+
const cached = voyageAIProxyCache.get(client);
|
|
5761
|
+
if (cached) {
|
|
5762
|
+
return cached;
|
|
5763
|
+
}
|
|
5764
|
+
const proxy = new Proxy(client, {
|
|
5765
|
+
get(target, prop, receiver) {
|
|
5766
|
+
switch (prop) {
|
|
5767
|
+
case "embed":
|
|
5768
|
+
if (typeof target.embed !== "function") {
|
|
5769
|
+
return target.embed;
|
|
5770
|
+
}
|
|
5771
|
+
return (request, options) => voyageAIChannels.embed.invoke(
|
|
5772
|
+
target.embed,
|
|
5773
|
+
target,
|
|
5774
|
+
[request, options],
|
|
5775
|
+
{}
|
|
5776
|
+
);
|
|
5777
|
+
case "multimodalEmbed":
|
|
5778
|
+
if (typeof target.multimodalEmbed !== "function") {
|
|
5779
|
+
return target.multimodalEmbed;
|
|
5780
|
+
}
|
|
5781
|
+
return (request, options) => voyageAIChannels.multimodalEmbed.invoke(
|
|
5782
|
+
target.multimodalEmbed,
|
|
5783
|
+
target,
|
|
5784
|
+
[request, options],
|
|
5785
|
+
{}
|
|
5786
|
+
);
|
|
5787
|
+
case "rerank":
|
|
5788
|
+
if (typeof target.rerank !== "function") {
|
|
5789
|
+
return target.rerank;
|
|
5790
|
+
}
|
|
5791
|
+
return (request, options) => voyageAIChannels.rerank.invoke(
|
|
5792
|
+
target.rerank,
|
|
5793
|
+
target,
|
|
5794
|
+
[request, options],
|
|
5795
|
+
{}
|
|
5796
|
+
);
|
|
5797
|
+
case "contextualizedEmbed":
|
|
5798
|
+
if (typeof target.contextualizedEmbed !== "function") {
|
|
5799
|
+
return target.contextualizedEmbed;
|
|
5800
|
+
}
|
|
5801
|
+
return (request, options) => voyageAIChannels.contextualizedEmbed.invoke(
|
|
5802
|
+
target.contextualizedEmbed,
|
|
5803
|
+
target,
|
|
5804
|
+
[request, options],
|
|
5805
|
+
{}
|
|
5806
|
+
);
|
|
5807
|
+
default:
|
|
5808
|
+
return Reflect.get(target, prop, receiver);
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
});
|
|
5812
|
+
voyageAIProxyCache.set(client, proxy);
|
|
5813
|
+
return proxy;
|
|
5814
|
+
}
|
|
5815
|
+
|
|
5544
5816
|
// src/wrappers/groq.ts
|
|
5545
5817
|
function wrapGroq(groq) {
|
|
5546
5818
|
if (isSupportedGroqClient(groq)) {
|
|
@@ -5552,14 +5824,14 @@ function wrapGroq(groq) {
|
|
|
5552
5824
|
function isRecord4(value) {
|
|
5553
5825
|
return typeof value === "object" && value !== null;
|
|
5554
5826
|
}
|
|
5555
|
-
function
|
|
5827
|
+
function hasFunction6(value, methodName) {
|
|
5556
5828
|
return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
|
|
5557
5829
|
}
|
|
5558
5830
|
function hasChat2(value) {
|
|
5559
|
-
return isRecord4(value) && isRecord4(value.completions) &&
|
|
5831
|
+
return isRecord4(value) && isRecord4(value.completions) && hasFunction6(value.completions, "create");
|
|
5560
5832
|
}
|
|
5561
5833
|
function hasEmbeddings2(value) {
|
|
5562
|
-
return
|
|
5834
|
+
return hasFunction6(value, "create");
|
|
5563
5835
|
}
|
|
5564
5836
|
function isSupportedGroqClient(value) {
|
|
5565
5837
|
return isRecord4(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
|
|
@@ -6101,7 +6373,7 @@ async function flushExperimentWithSync(context, config) {
|
|
|
6101
6373
|
// src/wrappers/shared/scorers.ts
|
|
6102
6374
|
async function runScorers(args) {
|
|
6103
6375
|
const { scorers, output, expected, input, metadata, span } = args;
|
|
6104
|
-
const
|
|
6376
|
+
const scorerArgs2 = {
|
|
6105
6377
|
output,
|
|
6106
6378
|
expected,
|
|
6107
6379
|
input,
|
|
@@ -6110,7 +6382,7 @@ async function runScorers(args) {
|
|
|
6110
6382
|
await Promise.all(
|
|
6111
6383
|
scorers.map(async (scorer) => {
|
|
6112
6384
|
try {
|
|
6113
|
-
const result = await scorer(
|
|
6385
|
+
const result = await scorer(scorerArgs2);
|
|
6114
6386
|
const scores = normalizeScores(result);
|
|
6115
6387
|
if (scores.length > 0) {
|
|
6116
6388
|
const accScores = {};
|
|
@@ -8469,6 +8741,26 @@ async function getExperimentParametersRef(parameters) {
|
|
|
8469
8741
|
version: resolvedParameters.version
|
|
8470
8742
|
};
|
|
8471
8743
|
}
|
|
8744
|
+
async function _internalInitEvaluatorExperiment(projectName, evaluator, data, options = {}) {
|
|
8745
|
+
if (options.disabled) return null;
|
|
8746
|
+
const { baseExperiment } = callEvaluatorData(data);
|
|
8747
|
+
const parameters = await getExperimentParametersRef(evaluator.parameters);
|
|
8748
|
+
return initExperiment2(evaluator.state, {
|
|
8749
|
+
...evaluator.projectId ? { projectId: evaluator.projectId } : { project: projectName },
|
|
8750
|
+
experiment: options.experimentName ?? evaluator.experimentName,
|
|
8751
|
+
description: evaluator.description,
|
|
8752
|
+
metadata: evaluator.metadata,
|
|
8753
|
+
tags: evaluator.tags,
|
|
8754
|
+
isPublic: evaluator.isPublic,
|
|
8755
|
+
update: options.update ?? evaluator.update,
|
|
8756
|
+
baseExperiment: evaluator.baseExperimentName ?? baseExperiment,
|
|
8757
|
+
baseExperimentId: evaluator.baseExperimentId,
|
|
8758
|
+
gitMetadataSettings: evaluator.gitMetadataSettings,
|
|
8759
|
+
repoInfo: evaluator.repoInfo,
|
|
8760
|
+
dataset: Dataset.isDataset(data) ? data : void 0,
|
|
8761
|
+
parameters
|
|
8762
|
+
});
|
|
8763
|
+
}
|
|
8472
8764
|
function callEvaluatorData(data) {
|
|
8473
8765
|
const dataResult = typeof data === "function" ? data() : data;
|
|
8474
8766
|
let baseExperiment = void 0;
|
|
@@ -8486,6 +8778,48 @@ function isAsyncIterable2(value) {
|
|
|
8486
8778
|
function isIterable(value) {
|
|
8487
8779
|
return typeof value === "object" && value !== null && Symbol.iterator in value && typeof value[Symbol.iterator] === "function";
|
|
8488
8780
|
}
|
|
8781
|
+
async function _internalResolveEvaluatorData(evaluator, experiment) {
|
|
8782
|
+
if (typeof evaluator.data === "string") {
|
|
8783
|
+
throw new Error("Unimplemented: string data paths");
|
|
8784
|
+
}
|
|
8785
|
+
let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
|
|
8786
|
+
if ("_type" in dataResult) {
|
|
8787
|
+
if (dataResult._type !== "BaseExperiment") {
|
|
8788
|
+
throw new Error("Invalid _type");
|
|
8789
|
+
}
|
|
8790
|
+
if (!experiment) {
|
|
8791
|
+
throw new Error(
|
|
8792
|
+
"Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
|
|
8793
|
+
);
|
|
8794
|
+
}
|
|
8795
|
+
let name = dataResult.name;
|
|
8796
|
+
if (isEmpty(name)) {
|
|
8797
|
+
const baseExperiment = await experiment.fetchBaseExperiment();
|
|
8798
|
+
if (!baseExperiment) {
|
|
8799
|
+
throw new Error("BaseExperiment() failed to fetch base experiment");
|
|
8800
|
+
}
|
|
8801
|
+
name = baseExperiment.name;
|
|
8802
|
+
}
|
|
8803
|
+
dataResult = initExperiment2(evaluator.state, {
|
|
8804
|
+
...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
|
|
8805
|
+
experiment: name,
|
|
8806
|
+
open: true
|
|
8807
|
+
}).asDataset();
|
|
8808
|
+
}
|
|
8809
|
+
const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
|
|
8810
|
+
if (isAsyncIterable2(resolvedDataResult)) {
|
|
8811
|
+
return resolvedDataResult;
|
|
8812
|
+
}
|
|
8813
|
+
if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
|
|
8814
|
+
const iterable = resolvedDataResult;
|
|
8815
|
+
return (async function* () {
|
|
8816
|
+
for (const datum of iterable) yield datum;
|
|
8817
|
+
})();
|
|
8818
|
+
}
|
|
8819
|
+
throw new Error(
|
|
8820
|
+
"Evaluator data must be an array, iterable, or async iterable"
|
|
8821
|
+
);
|
|
8822
|
+
}
|
|
8489
8823
|
globalThis._evals = {
|
|
8490
8824
|
functions: [],
|
|
8491
8825
|
prompts: [],
|
|
@@ -8532,25 +8866,13 @@ async function Eval(name, evaluator, reporterOrOpts) {
|
|
|
8532
8866
|
}
|
|
8533
8867
|
const resolvedReporter = options.reporter || defaultReporter;
|
|
8534
8868
|
try {
|
|
8535
|
-
const { data
|
|
8536
|
-
|
|
8869
|
+
const { data } = callEvaluatorData(evaluator.data);
|
|
8870
|
+
const experiment = await _internalInitEvaluatorExperiment(
|
|
8871
|
+
name,
|
|
8872
|
+
evaluator,
|
|
8873
|
+
data,
|
|
8874
|
+
{ disabled: Boolean(options.parent || options.noSendLogs) }
|
|
8537
8875
|
);
|
|
8538
|
-
const parameters = await getExperimentParametersRef(evaluator.parameters);
|
|
8539
|
-
const experiment = options.parent || options.noSendLogs ? null : initExperiment2(evaluator.state, {
|
|
8540
|
-
...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
|
|
8541
|
-
experiment: evaluator.experimentName,
|
|
8542
|
-
description: evaluator.description,
|
|
8543
|
-
metadata: evaluator.metadata,
|
|
8544
|
-
tags: evaluator.tags,
|
|
8545
|
-
isPublic: evaluator.isPublic,
|
|
8546
|
-
update: evaluator.update,
|
|
8547
|
-
baseExperiment: evaluator.baseExperimentName ?? defaultBaseExperiment,
|
|
8548
|
-
baseExperimentId: evaluator.baseExperimentId,
|
|
8549
|
-
gitMetadataSettings: evaluator.gitMetadataSettings,
|
|
8550
|
-
repoInfo: evaluator.repoInfo,
|
|
8551
|
-
dataset: Dataset.isDataset(data) ? data : void 0,
|
|
8552
|
-
parameters
|
|
8553
|
-
});
|
|
8554
8876
|
if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
|
|
8555
8877
|
await experiment._waitForId();
|
|
8556
8878
|
}
|
|
@@ -8648,19 +8970,74 @@ function scorerName(scorer, scorer_idx) {
|
|
|
8648
8970
|
function classifierName(classifier, classifier_idx) {
|
|
8649
8971
|
return classifier.name || `classifier_${classifier_idx}`;
|
|
8650
8972
|
}
|
|
8973
|
+
async function _internalRunEvaluatorTask(task, datum, trialIndex, parameters, span, reportProgress = () => void 0) {
|
|
8974
|
+
const metadata = {
|
|
8975
|
+
..."metadata" in datum ? datum.metadata : {}
|
|
8976
|
+
};
|
|
8977
|
+
const hooks = {
|
|
8978
|
+
meta(value) {
|
|
8979
|
+
Object.assign(metadata, value);
|
|
8980
|
+
},
|
|
8981
|
+
metadata,
|
|
8982
|
+
expected: "expected" in datum ? datum.expected : void 0,
|
|
8983
|
+
span,
|
|
8984
|
+
parameters,
|
|
8985
|
+
reportProgress,
|
|
8986
|
+
trialIndex,
|
|
8987
|
+
tags: [...datum.tags ?? []]
|
|
8988
|
+
};
|
|
8989
|
+
const output = await task(datum.input, hooks);
|
|
8990
|
+
span.log({ output });
|
|
8991
|
+
return {
|
|
8992
|
+
output,
|
|
8993
|
+
metadata: hooks.metadata,
|
|
8994
|
+
tags: hooks.tags ?? []
|
|
8995
|
+
};
|
|
8996
|
+
}
|
|
8651
8997
|
function buildSpanMetadata(results) {
|
|
8652
|
-
return results.length === 1 ? results[0].metadata :
|
|
8653
|
-
(
|
|
8654
|
-
{}
|
|
8998
|
+
return results.length === 1 ? results[0].metadata : Object.fromEntries(
|
|
8999
|
+
results.map((result) => [result.name, result.metadata])
|
|
8655
9000
|
);
|
|
8656
9001
|
}
|
|
8657
9002
|
function buildSpanScores(results) {
|
|
8658
|
-
const scoresRecord =
|
|
8659
|
-
(
|
|
8660
|
-
{}
|
|
9003
|
+
const scoresRecord = Object.fromEntries(
|
|
9004
|
+
results.map((result) => [result.name, result.score])
|
|
8661
9005
|
);
|
|
8662
9006
|
return { resultMetadata: buildSpanMetadata(results), scoresRecord };
|
|
8663
9007
|
}
|
|
9008
|
+
function _internalPrepareEvaluatorScore(scoreValue, name) {
|
|
9009
|
+
if (scoreValue === null) return { results: null };
|
|
9010
|
+
if (Array.isArray(scoreValue)) {
|
|
9011
|
+
for (const score of scoreValue) {
|
|
9012
|
+
if (!(typeof score === "object" && !isEmpty(score))) {
|
|
9013
|
+
throw new Error(
|
|
9014
|
+
`When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
|
|
9015
|
+
);
|
|
9016
|
+
}
|
|
9017
|
+
}
|
|
9018
|
+
}
|
|
9019
|
+
let results;
|
|
9020
|
+
if (Array.isArray(scoreValue)) {
|
|
9021
|
+
results = scoreValue;
|
|
9022
|
+
} else if (typeof scoreValue === "object" && !isEmpty(scoreValue)) {
|
|
9023
|
+
results = [scoreValue];
|
|
9024
|
+
} else {
|
|
9025
|
+
results = [{ name, score: scoreValue }];
|
|
9026
|
+
}
|
|
9027
|
+
const { resultMetadata, scoresRecord } = buildSpanScores(results);
|
|
9028
|
+
const fields = (score) => {
|
|
9029
|
+
const { metadata: _metadata, name: _name, ...rest } = score;
|
|
9030
|
+
return rest;
|
|
9031
|
+
};
|
|
9032
|
+
return {
|
|
9033
|
+
results,
|
|
9034
|
+
output: results.length === 1 ? fields(results[0]) : Object.fromEntries(
|
|
9035
|
+
results.map((score) => [score.name ?? name, fields(score)])
|
|
9036
|
+
),
|
|
9037
|
+
metadata: resultMetadata,
|
|
9038
|
+
scores: scoresRecord
|
|
9039
|
+
};
|
|
9040
|
+
}
|
|
8664
9041
|
async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
|
|
8665
9042
|
try {
|
|
8666
9043
|
const value = await rootSpan.traced(fn, {
|
|
@@ -8705,6 +9082,27 @@ function toClassificationItem(c) {
|
|
|
8705
9082
|
...c.metadata !== void 0 ? { metadata: c.metadata } : {}
|
|
8706
9083
|
};
|
|
8707
9084
|
}
|
|
9085
|
+
function _internalPrepareEvaluatorClassification(value, name) {
|
|
9086
|
+
if (value === null) return { results: null };
|
|
9087
|
+
const results = (Array.isArray(value) ? value : [value]).map(
|
|
9088
|
+
(result) => validateClassificationResult(result, name)
|
|
9089
|
+
);
|
|
9090
|
+
const classifications = /* @__PURE__ */ Object.create(null);
|
|
9091
|
+
for (const result of results) {
|
|
9092
|
+
(classifications[result.name] ??= []).push(toClassificationItem(result));
|
|
9093
|
+
}
|
|
9094
|
+
return {
|
|
9095
|
+
results,
|
|
9096
|
+
output: results.length === 1 ? toClassificationItem(results[0]) : Object.fromEntries(
|
|
9097
|
+
results.map((result) => [
|
|
9098
|
+
result.name,
|
|
9099
|
+
toClassificationItem(result)
|
|
9100
|
+
])
|
|
9101
|
+
),
|
|
9102
|
+
metadata: buildSpanMetadata(results),
|
|
9103
|
+
classifications
|
|
9104
|
+
};
|
|
9105
|
+
}
|
|
8708
9106
|
function logScoringFailures(kind, failures, metadata, rootSpan, state) {
|
|
8709
9107
|
if (!failures.length) return [];
|
|
8710
9108
|
const errorMap = Object.fromEntries(
|
|
@@ -8752,54 +9150,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
8752
9150
|
(evaluator.state ?? _internalGetGlobalState())?.spanCache?.start();
|
|
8753
9151
|
}
|
|
8754
9152
|
try {
|
|
8755
|
-
if (typeof evaluator.data === "string") {
|
|
8756
|
-
throw new Error("Unimplemented: string data paths");
|
|
8757
|
-
}
|
|
8758
|
-
let dataResult = typeof evaluator.data === "function" ? evaluator.data() : evaluator.data;
|
|
8759
9153
|
parameters = await validateParameters(
|
|
8760
9154
|
parameters ?? {},
|
|
8761
9155
|
evaluator.parameters
|
|
8762
9156
|
);
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
if (!experiment) {
|
|
8768
|
-
throw new Error(
|
|
8769
|
-
"Cannot use BaseExperiment() without connecting to Braintrust (you most likely set --no-send-logs)"
|
|
8770
|
-
);
|
|
8771
|
-
}
|
|
8772
|
-
let name = dataResult.name;
|
|
8773
|
-
if (isEmpty(name)) {
|
|
8774
|
-
const baseExperiment = await experiment.fetchBaseExperiment();
|
|
8775
|
-
if (!baseExperiment) {
|
|
8776
|
-
throw new Error("BaseExperiment() failed to fetch base experiment");
|
|
8777
|
-
}
|
|
8778
|
-
name = baseExperiment.name;
|
|
8779
|
-
}
|
|
8780
|
-
dataResult = initExperiment2(evaluator.state, {
|
|
8781
|
-
...evaluator.projectId ? { projectId: evaluator.projectId } : { project: evaluator.projectName },
|
|
8782
|
-
experiment: name,
|
|
8783
|
-
open: true
|
|
8784
|
-
}).asDataset();
|
|
8785
|
-
}
|
|
8786
|
-
const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
|
|
8787
|
-
const dataIterable = (() => {
|
|
8788
|
-
if (isAsyncIterable2(resolvedDataResult)) {
|
|
8789
|
-
return resolvedDataResult;
|
|
8790
|
-
}
|
|
8791
|
-
if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
|
|
8792
|
-
const iterable = resolvedDataResult;
|
|
8793
|
-
return (async function* () {
|
|
8794
|
-
for (const datum of iterable) {
|
|
8795
|
-
yield datum;
|
|
8796
|
-
}
|
|
8797
|
-
})();
|
|
8798
|
-
}
|
|
8799
|
-
throw new Error(
|
|
8800
|
-
"Evaluator data must be an array, iterable, or async iterable"
|
|
8801
|
-
);
|
|
8802
|
-
})();
|
|
9157
|
+
const dataIterable = await _internalResolveEvaluatorData(
|
|
9158
|
+
evaluator,
|
|
9159
|
+
experiment
|
|
9160
|
+
);
|
|
8803
9161
|
progressReporter.start(evaluator.evalName, 0);
|
|
8804
9162
|
const experimentIdPromise = experiment ? (async () => {
|
|
8805
9163
|
try {
|
|
@@ -8868,57 +9226,45 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
8868
9226
|
ensureSpansFlushed,
|
|
8869
9227
|
state
|
|
8870
9228
|
}) : void 0;
|
|
8871
|
-
let metadata = {
|
|
8872
|
-
..."metadata" in datum ? datum.metadata : {}
|
|
8873
|
-
};
|
|
9229
|
+
let metadata = {};
|
|
8874
9230
|
const expected = "expected" in datum ? datum.expected : void 0;
|
|
8875
9231
|
let output = void 0;
|
|
8876
9232
|
let error = void 0;
|
|
8877
|
-
let tags = [
|
|
8878
|
-
const scores =
|
|
8879
|
-
const classifications =
|
|
9233
|
+
let tags = [];
|
|
9234
|
+
const scores = /* @__PURE__ */ Object.create(null);
|
|
9235
|
+
const classifications = /* @__PURE__ */ Object.create(null);
|
|
8880
9236
|
const scorerNames = (evaluator.scores ?? []).map(scorerName);
|
|
8881
9237
|
const classifierNames = (evaluator.classifiers ?? []).map(
|
|
8882
9238
|
classifierName
|
|
8883
9239
|
);
|
|
8884
9240
|
let unhandledScores = scorerNames;
|
|
8885
9241
|
try {
|
|
8886
|
-
const
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
object_type: "task"
|
|
8902
|
-
});
|
|
8903
|
-
},
|
|
8904
|
-
trialIndex,
|
|
8905
|
-
tags
|
|
8906
|
-
};
|
|
8907
|
-
const outputResult = evaluator.task(datum.input, hooksForTask);
|
|
8908
|
-
if (outputResult instanceof Promise) {
|
|
8909
|
-
output = await outputResult;
|
|
8910
|
-
} else {
|
|
8911
|
-
output = outputResult;
|
|
9242
|
+
const taskResult = await rootSpan.traced(
|
|
9243
|
+
(span) => _internalRunEvaluatorTask(
|
|
9244
|
+
evaluator.task,
|
|
9245
|
+
datum,
|
|
9246
|
+
trialIndex,
|
|
9247
|
+
parameters ?? {},
|
|
9248
|
+
span,
|
|
9249
|
+
(event) => {
|
|
9250
|
+
stream?.({
|
|
9251
|
+
...event,
|
|
9252
|
+
id: rootSpan.id,
|
|
9253
|
+
origin: baseEvent.event?.origin,
|
|
9254
|
+
name: evaluator.evalName,
|
|
9255
|
+
object_type: "task"
|
|
9256
|
+
});
|
|
8912
9257
|
}
|
|
8913
|
-
|
|
8914
|
-
span.log({ output });
|
|
8915
|
-
},
|
|
9258
|
+
),
|
|
8916
9259
|
{
|
|
8917
9260
|
name: "task",
|
|
8918
9261
|
spanAttributes: { type: "task" /* TASK */ },
|
|
8919
9262
|
event: { input: datum.input }
|
|
8920
9263
|
}
|
|
8921
9264
|
);
|
|
9265
|
+
output = taskResult.output;
|
|
9266
|
+
metadata = taskResult.metadata;
|
|
9267
|
+
tags = taskResult.tags;
|
|
8922
9268
|
if (tags.length) {
|
|
8923
9269
|
rootSpan.log({ output, metadata, expected, tags });
|
|
8924
9270
|
} else {
|
|
@@ -8928,20 +9274,18 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
8928
9274
|
await rootSpan.flush();
|
|
8929
9275
|
}
|
|
8930
9276
|
const scoringArgs = {
|
|
9277
|
+
id: datum.id,
|
|
8931
9278
|
input: datum.input,
|
|
8932
9279
|
expected: "expected" in datum ? datum.expected : void 0,
|
|
8933
9280
|
metadata,
|
|
8934
9281
|
output,
|
|
9282
|
+
tags,
|
|
8935
9283
|
trace
|
|
8936
9284
|
};
|
|
8937
9285
|
const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
|
|
8938
9286
|
const propagatedEvent = makeScorerPropagatedEvent(
|
|
8939
9287
|
await rootSpan.export()
|
|
8940
9288
|
);
|
|
8941
|
-
const getOtherFields = (s) => {
|
|
8942
|
-
const { metadata: _metadata, name: _name, ...rest } = s;
|
|
8943
|
-
return rest;
|
|
8944
|
-
};
|
|
8945
9289
|
const [scoreResults, classificationResults] = await Promise.all([
|
|
8946
9290
|
Promise.all(
|
|
8947
9291
|
(evaluator.scores ?? []).map(
|
|
@@ -8955,35 +9299,17 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
8955
9299
|
const scoreValue = await Promise.resolve(
|
|
8956
9300
|
score(scoringArgs)
|
|
8957
9301
|
);
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
if (!(typeof s === "object" && !isEmpty(s))) {
|
|
8962
|
-
throw new Error(
|
|
8963
|
-
`When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
|
|
8964
|
-
);
|
|
8965
|
-
}
|
|
8966
|
-
}
|
|
8967
|
-
}
|
|
8968
|
-
const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty(scoreValue) ? [scoreValue] : [
|
|
8969
|
-
{
|
|
8970
|
-
name: scorerNames[score_idx],
|
|
8971
|
-
score: scoreValue
|
|
8972
|
-
}
|
|
8973
|
-
];
|
|
8974
|
-
const { resultMetadata, scoresRecord } = buildSpanScores(results);
|
|
8975
|
-
const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
|
|
8976
|
-
(prev, s) => mergeDicts(prev, {
|
|
8977
|
-
[s.name]: getOtherFields(s)
|
|
8978
|
-
}),
|
|
8979
|
-
{}
|
|
9302
|
+
const prepared = _internalPrepareEvaluatorScore(
|
|
9303
|
+
scoreValue,
|
|
9304
|
+
scorerNames[score_idx]
|
|
8980
9305
|
);
|
|
9306
|
+
if (prepared.results === null) return null;
|
|
8981
9307
|
span.log({
|
|
8982
|
-
output:
|
|
8983
|
-
metadata:
|
|
8984
|
-
scores:
|
|
9308
|
+
output: prepared.output,
|
|
9309
|
+
metadata: prepared.metadata,
|
|
9310
|
+
scores: prepared.scores
|
|
8985
9311
|
});
|
|
8986
|
-
return results;
|
|
9312
|
+
return prepared.results;
|
|
8987
9313
|
}
|
|
8988
9314
|
)
|
|
8989
9315
|
)
|
|
@@ -9000,24 +9326,16 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
|
|
|
9000
9326
|
const classifierValue = await Promise.resolve(
|
|
9001
9327
|
classifier(scoringArgs)
|
|
9002
9328
|
);
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
result,
|
|
9007
|
-
classifierNames[idx]
|
|
9008
|
-
)
|
|
9009
|
-
);
|
|
9010
|
-
const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
|
|
9011
|
-
(prev, r) => mergeDicts(prev, {
|
|
9012
|
-
[r.name]: toClassificationItem(r)
|
|
9013
|
-
}),
|
|
9014
|
-
{}
|
|
9329
|
+
const prepared = _internalPrepareEvaluatorClassification(
|
|
9330
|
+
classifierValue,
|
|
9331
|
+
classifierNames[idx]
|
|
9015
9332
|
);
|
|
9333
|
+
if (prepared.results === null) return null;
|
|
9016
9334
|
span.log({
|
|
9017
|
-
output:
|
|
9018
|
-
metadata:
|
|
9335
|
+
output: prepared.output,
|
|
9336
|
+
metadata: prepared.metadata
|
|
9019
9337
|
});
|
|
9020
|
-
return
|
|
9338
|
+
return prepared.results;
|
|
9021
9339
|
}
|
|
9022
9340
|
)
|
|
9023
9341
|
)
|
|
@@ -9246,7 +9564,7 @@ function accumulateScores(accumulator, scores) {
|
|
|
9246
9564
|
}
|
|
9247
9565
|
}
|
|
9248
9566
|
function ensureScoreAccumulator(results) {
|
|
9249
|
-
const accumulator =
|
|
9567
|
+
const accumulator = /* @__PURE__ */ Object.create(null);
|
|
9250
9568
|
for (const result of results) {
|
|
9251
9569
|
accumulateScores(accumulator, result.scores);
|
|
9252
9570
|
}
|
|
@@ -9389,6 +9707,1156 @@ var defaultReporter = {
|
|
|
9389
9707
|
}
|
|
9390
9708
|
};
|
|
9391
9709
|
|
|
9710
|
+
// src/durable-eval.ts
|
|
9711
|
+
var encoder = new TextEncoder();
|
|
9712
|
+
var decoder = new TextDecoder();
|
|
9713
|
+
var BATCH_TASK_KIND = "braintrust.durable.batch-task";
|
|
9714
|
+
var BATCH_SCORER_KIND = "braintrust.durable.batch-scorer";
|
|
9715
|
+
var DEFAULT_BATCH_SIZE = 1e3;
|
|
9716
|
+
var DurableEvalMemoryStore = class {
|
|
9717
|
+
values = /* @__PURE__ */ new Map();
|
|
9718
|
+
async read(key) {
|
|
9719
|
+
return this.values.get(key)?.slice();
|
|
9720
|
+
}
|
|
9721
|
+
async write(key, value) {
|
|
9722
|
+
this.values.set(key, value.slice());
|
|
9723
|
+
}
|
|
9724
|
+
async getOrSet(key, value) {
|
|
9725
|
+
const existing = this.values.get(key);
|
|
9726
|
+
if (existing) return { value: existing.slice(), created: false };
|
|
9727
|
+
this.values.set(key, value.slice());
|
|
9728
|
+
return { value: value.slice(), created: true };
|
|
9729
|
+
}
|
|
9730
|
+
};
|
|
9731
|
+
var DurableEvalRedisStore = class {
|
|
9732
|
+
client;
|
|
9733
|
+
keyPrefix;
|
|
9734
|
+
ttlMs;
|
|
9735
|
+
constructor(options) {
|
|
9736
|
+
this.client = options.client;
|
|
9737
|
+
this.keyPrefix = options.keyPrefix ?? "braintrust-eval:";
|
|
9738
|
+
this.ttlMs = options.ttlMs ?? 1e3 * 60 * 60 * 24 * 7;
|
|
9739
|
+
if (!Number.isInteger(this.ttlMs) || this.ttlMs < 1) {
|
|
9740
|
+
throw new Error("DurableEvalRedisStore ttlMs must be a positive integer");
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
async read(key) {
|
|
9744
|
+
const value = await this.client.get(`${this.keyPrefix}${key}`);
|
|
9745
|
+
if (value == null) return void 0;
|
|
9746
|
+
if (typeof value !== "string") {
|
|
9747
|
+
throw new Error("DurableEvalRedisStore expected GET to return a string");
|
|
9748
|
+
}
|
|
9749
|
+
return base64ToUint8Array(value);
|
|
9750
|
+
}
|
|
9751
|
+
async write(key, value) {
|
|
9752
|
+
const client = this.client;
|
|
9753
|
+
const set = client.set;
|
|
9754
|
+
const redisKey = `${this.keyPrefix}${key}`;
|
|
9755
|
+
const encoded = uint8ArrayToBase64(value);
|
|
9756
|
+
if (typeof client.defineCommand === "function") {
|
|
9757
|
+
await set.call(client, redisKey, encoded, "PX", this.ttlMs);
|
|
9758
|
+
} else if (typeof client.sendCommand === "function") {
|
|
9759
|
+
await set.call(client, redisKey, encoded, { PX: this.ttlMs });
|
|
9760
|
+
} else if (typeof client.createScript === "function") {
|
|
9761
|
+
await set.call(client, redisKey, encoded, { px: this.ttlMs });
|
|
9762
|
+
} else {
|
|
9763
|
+
throw new Error(
|
|
9764
|
+
"DurableEvalRedisStore requires a node-redis, ioredis, or @upstash/redis client"
|
|
9765
|
+
);
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9768
|
+
async getOrSet(key, value) {
|
|
9769
|
+
const redisKey = `${this.keyPrefix}${key}`;
|
|
9770
|
+
const encoded = uint8ArrayToBase64(value);
|
|
9771
|
+
const client = this.client;
|
|
9772
|
+
const set = client.set;
|
|
9773
|
+
let setOptions;
|
|
9774
|
+
if (typeof client.defineCommand === "function") {
|
|
9775
|
+
setOptions = ["PX", this.ttlMs, "NX", "GET"];
|
|
9776
|
+
} else if (typeof client.sendCommand === "function") {
|
|
9777
|
+
setOptions = [{ PX: this.ttlMs, NX: true, GET: true }];
|
|
9778
|
+
} else if (typeof client.createScript === "function") {
|
|
9779
|
+
setOptions = [{ px: this.ttlMs, nx: true, get: true }];
|
|
9780
|
+
} else {
|
|
9781
|
+
throw new Error(
|
|
9782
|
+
"DurableEvalRedisStore getOrSet requires a node-redis, ioredis, or @upstash/redis client"
|
|
9783
|
+
);
|
|
9784
|
+
}
|
|
9785
|
+
const existing = await set.call(client, redisKey, encoded, ...setOptions);
|
|
9786
|
+
if (existing === null) return { value: value.slice(), created: true };
|
|
9787
|
+
if (typeof existing !== "string") {
|
|
9788
|
+
throw new Error(
|
|
9789
|
+
"DurableEvalRedisStore expected atomic SET to return a string or null"
|
|
9790
|
+
);
|
|
9791
|
+
}
|
|
9792
|
+
return { value: base64ToUint8Array(existing), created: false };
|
|
9793
|
+
}
|
|
9794
|
+
};
|
|
9795
|
+
var BatchTask = class {
|
|
9796
|
+
constructor(processor) {
|
|
9797
|
+
this.processor = processor;
|
|
9798
|
+
}
|
|
9799
|
+
processor;
|
|
9800
|
+
kind = BATCH_TASK_KIND;
|
|
9801
|
+
};
|
|
9802
|
+
var BatchScorer = class {
|
|
9803
|
+
constructor(processor) {
|
|
9804
|
+
this.processor = processor;
|
|
9805
|
+
this.name = processor.name;
|
|
9806
|
+
}
|
|
9807
|
+
processor;
|
|
9808
|
+
kind = BATCH_SCORER_KIND;
|
|
9809
|
+
name;
|
|
9810
|
+
};
|
|
9811
|
+
function defineDurableEval(projectName, evaluator) {
|
|
9812
|
+
const definition = {
|
|
9813
|
+
projectName,
|
|
9814
|
+
evalName: evaluator.experimentName ?? projectName,
|
|
9815
|
+
evaluator
|
|
9816
|
+
};
|
|
9817
|
+
return {
|
|
9818
|
+
start: (options = {}) => startDurableEval(definition, options),
|
|
9819
|
+
status: (options) => getDurableEvalStatus(definition, options),
|
|
9820
|
+
poll: (options) => pollDurableEval(definition, options),
|
|
9821
|
+
processBatchResult: (result) => processDurableBatchResult(definition, result)
|
|
9822
|
+
};
|
|
9823
|
+
}
|
|
9824
|
+
async function startDurableEval(definition, options) {
|
|
9825
|
+
const store = definition.evaluator.store;
|
|
9826
|
+
const runId = newId();
|
|
9827
|
+
const key = runKey(definition.projectName, definition.evalName, runId);
|
|
9828
|
+
const { data } = callEvaluatorData(definition.evaluator.data);
|
|
9829
|
+
const parameters = await validateParameters(
|
|
9830
|
+
options.parameters ?? {},
|
|
9831
|
+
definition.evaluator.parameters
|
|
9832
|
+
);
|
|
9833
|
+
const experimentName = definition.evaluator.experimentName ?? `${definition.evalName}-${runId}`;
|
|
9834
|
+
const experiment = await _internalInitEvaluatorExperiment(
|
|
9835
|
+
definition.projectName,
|
|
9836
|
+
{ ...definition.evaluator, data },
|
|
9837
|
+
data,
|
|
9838
|
+
{
|
|
9839
|
+
disabled: options.noSendLogs ?? false,
|
|
9840
|
+
experimentName,
|
|
9841
|
+
update: true
|
|
9842
|
+
}
|
|
9843
|
+
);
|
|
9844
|
+
if (!isBatchTask(definition.evaluator.task) && !(definition.evaluator.scores ?? []).some(isBatchScorer)) {
|
|
9845
|
+
const result = await runEvaluator(
|
|
9846
|
+
experiment,
|
|
9847
|
+
{
|
|
9848
|
+
...definition.evaluator,
|
|
9849
|
+
projectName: definition.projectName,
|
|
9850
|
+
evalName: definition.evalName,
|
|
9851
|
+
data
|
|
9852
|
+
},
|
|
9853
|
+
{
|
|
9854
|
+
start: () => void 0,
|
|
9855
|
+
stop: () => void 0,
|
|
9856
|
+
increment: () => void 0
|
|
9857
|
+
},
|
|
9858
|
+
[],
|
|
9859
|
+
void 0,
|
|
9860
|
+
parameters,
|
|
9861
|
+
true,
|
|
9862
|
+
true
|
|
9863
|
+
);
|
|
9864
|
+
const state2 = {
|
|
9865
|
+
runId,
|
|
9866
|
+
experimentName,
|
|
9867
|
+
noSendLogs: options.noSendLogs ?? false,
|
|
9868
|
+
parameters: assertJsonValue(parameters, "eval parameters"),
|
|
9869
|
+
status: "completed",
|
|
9870
|
+
summary: result.summary,
|
|
9871
|
+
cases: [],
|
|
9872
|
+
batches: []
|
|
9873
|
+
};
|
|
9874
|
+
await experiment?.flush();
|
|
9875
|
+
await writeRunRecord(store, key, state2);
|
|
9876
|
+
return currentStatus(definition, state2);
|
|
9877
|
+
}
|
|
9878
|
+
const state = {
|
|
9879
|
+
runId,
|
|
9880
|
+
experimentName,
|
|
9881
|
+
noSendLogs: options.noSendLogs ?? false,
|
|
9882
|
+
parameters: assertJsonValue(parameters, "eval parameters"),
|
|
9883
|
+
status: "running",
|
|
9884
|
+
cases: await materializeCases(definition, data, experiment),
|
|
9885
|
+
batches: []
|
|
9886
|
+
};
|
|
9887
|
+
await writeCaseBaseRecords(store, key, state.cases);
|
|
9888
|
+
await writeRunRecord(store, key, state);
|
|
9889
|
+
return advanceDurableEval(definition, state, store, key, experiment);
|
|
9890
|
+
}
|
|
9891
|
+
async function getDurableEvalStatus(definition, options) {
|
|
9892
|
+
const store = definition.evaluator.store;
|
|
9893
|
+
const state = await readRunState(
|
|
9894
|
+
definition,
|
|
9895
|
+
store,
|
|
9896
|
+
runKey(definition.projectName, definition.evalName, options.runId)
|
|
9897
|
+
);
|
|
9898
|
+
if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
|
|
9899
|
+
return currentStatus(definition, state);
|
|
9900
|
+
}
|
|
9901
|
+
async function processDurableBatchResult(definition, result) {
|
|
9902
|
+
if (!result.batchId && !result.externalId) {
|
|
9903
|
+
throw new Error("Batch results require batchId or externalId");
|
|
9904
|
+
}
|
|
9905
|
+
const store = definition.evaluator.store;
|
|
9906
|
+
const key = runKey(definition.projectName, definition.evalName, result.runId);
|
|
9907
|
+
const state = await readRunState(definition, store, key);
|
|
9908
|
+
if (!state) throw new Error(`Durable eval run ${result.runId} is missing`);
|
|
9909
|
+
const byBatch = result.batchId ? state.batches.find((candidate) => candidate.id === result.batchId) : void 0;
|
|
9910
|
+
const byExternal = result.externalId ? state.batches.find(
|
|
9911
|
+
(candidate) => candidate.externalId === result.externalId
|
|
9912
|
+
) : void 0;
|
|
9913
|
+
if (byBatch && byExternal && byBatch.id !== byExternal.id) {
|
|
9914
|
+
throw new Error("batchId and externalId identify different batches");
|
|
9915
|
+
}
|
|
9916
|
+
const batch = byBatch ?? byExternal;
|
|
9917
|
+
if (!batch) throw new Error("No submitted batch matches this result");
|
|
9918
|
+
if (batch.status !== "complete") {
|
|
9919
|
+
const records = await collectBatch(definition, state, batch);
|
|
9920
|
+
batch.status = "complete";
|
|
9921
|
+
await writeCaseRecords(store, key, records);
|
|
9922
|
+
await writeBatchRecords(store, key, [batch]);
|
|
9923
|
+
}
|
|
9924
|
+
return advanceDurableEval(
|
|
9925
|
+
definition,
|
|
9926
|
+
await readRunState(definition, store, key),
|
|
9927
|
+
store,
|
|
9928
|
+
key
|
|
9929
|
+
);
|
|
9930
|
+
}
|
|
9931
|
+
async function pollDurableEval(definition, options) {
|
|
9932
|
+
const store = definition.evaluator.store;
|
|
9933
|
+
const key = runKey(
|
|
9934
|
+
definition.projectName,
|
|
9935
|
+
definition.evalName,
|
|
9936
|
+
options.runId
|
|
9937
|
+
);
|
|
9938
|
+
const state = await readRunState(definition, store, key);
|
|
9939
|
+
if (!state) throw new Error(`Durable eval run ${options.runId} is missing`);
|
|
9940
|
+
const batches = state.batches.filter((batch) => {
|
|
9941
|
+
if (batch.status === "complete") return false;
|
|
9942
|
+
return processorForStage(definition, batch.kind, batch.scorerName).completion.mode === "poll";
|
|
9943
|
+
});
|
|
9944
|
+
const results = await Promise.all(
|
|
9945
|
+
batches.map(async (batch) => ({
|
|
9946
|
+
batch,
|
|
9947
|
+
result: await processorForStage(definition, batch.kind, batch.scorerName).completion.poll(batch.submissionData, {
|
|
9948
|
+
runId: state.runId,
|
|
9949
|
+
batchId: batch.id
|
|
9950
|
+
})
|
|
9951
|
+
}))
|
|
9952
|
+
);
|
|
9953
|
+
const changedCases = /* @__PURE__ */ new Map();
|
|
9954
|
+
const changedBatches = [];
|
|
9955
|
+
for (const { batch, result } of results) {
|
|
9956
|
+
if (result.status === "failed") throw asError(result.error);
|
|
9957
|
+
if (result.status !== "complete") continue;
|
|
9958
|
+
for (const record of await collectBatch(definition, state, batch)) {
|
|
9959
|
+
changedCases.set(record.id, record);
|
|
9960
|
+
}
|
|
9961
|
+
batch.status = "complete";
|
|
9962
|
+
changedBatches.push(batch);
|
|
9963
|
+
}
|
|
9964
|
+
if (changedBatches.length > 0) {
|
|
9965
|
+
await writeCaseRecords(store, key, [...changedCases.values()]);
|
|
9966
|
+
await writeBatchRecords(store, key, changedBatches);
|
|
9967
|
+
}
|
|
9968
|
+
const currentState = changedBatches.length > 0 ? await readRunState(definition, store, key) : state;
|
|
9969
|
+
return advanceDurableEval(definition, currentState, store, key);
|
|
9970
|
+
}
|
|
9971
|
+
async function openDurableExperiment(definition, state) {
|
|
9972
|
+
const data = [];
|
|
9973
|
+
return await _internalInitEvaluatorExperiment(
|
|
9974
|
+
definition.projectName,
|
|
9975
|
+
{ ...definition.evaluator, data },
|
|
9976
|
+
data,
|
|
9977
|
+
{
|
|
9978
|
+
disabled: state.noSendLogs,
|
|
9979
|
+
experimentName: state.experimentName,
|
|
9980
|
+
update: true
|
|
9981
|
+
}
|
|
9982
|
+
);
|
|
9983
|
+
}
|
|
9984
|
+
async function advanceDurableEval(definition, state, store, key, existingExperiment) {
|
|
9985
|
+
if (state.status === "completed") return currentStatus(definition, state);
|
|
9986
|
+
const experiment = existingExperiment === void 0 ? await openDurableExperiment(definition, state) : existingExperiment;
|
|
9987
|
+
await runTaskStage(definition, state, store, key, experiment);
|
|
9988
|
+
await logCompletedTasks(definition, state, store, key, experiment);
|
|
9989
|
+
state = await readRunState(definition, store, key) ?? state;
|
|
9990
|
+
if (state.cases.some((record) => !record.taskComplete || !record.taskLogged)) {
|
|
9991
|
+
return currentStatus(definition, state);
|
|
9992
|
+
}
|
|
9993
|
+
await runScoreStages(definition, state, store, key, experiment);
|
|
9994
|
+
state = await readRunState(definition, store, key) ?? state;
|
|
9995
|
+
const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
|
|
9996
|
+
({ name }) => name
|
|
9997
|
+
);
|
|
9998
|
+
const classifierNames = (definition.evaluator.classifiers ?? []).map(
|
|
9999
|
+
classifierName
|
|
10000
|
+
);
|
|
10001
|
+
if (state.cases.some(
|
|
10002
|
+
(record) => scorerNames.some(
|
|
10003
|
+
(name) => !Object.hasOwn(record.scores, name) || !Object.hasOwn(record.loggedScores, name)
|
|
10004
|
+
) || classifierNames.some(
|
|
10005
|
+
(name) => !Object.hasOwn(record.loggedClassifications, name)
|
|
10006
|
+
)
|
|
10007
|
+
)) {
|
|
10008
|
+
return currentStatus(definition, state);
|
|
10009
|
+
}
|
|
10010
|
+
if (!await claimAction(store, key, "finish")) {
|
|
10011
|
+
const latest = await readRunState(definition, store, key);
|
|
10012
|
+
return currentStatus(definition, latest ?? state);
|
|
10013
|
+
}
|
|
10014
|
+
state.summary = await finishExperiment(definition, state, experiment);
|
|
10015
|
+
state.status = "completed";
|
|
10016
|
+
await writeRunRecord(store, key, state);
|
|
10017
|
+
return currentStatus(definition, state);
|
|
10018
|
+
}
|
|
10019
|
+
function currentStatus(definition, state) {
|
|
10020
|
+
if (state.status === "completed") {
|
|
10021
|
+
if (!state.summary) {
|
|
10022
|
+
throw new Error(`Durable eval run ${state.runId} has no saved summary`);
|
|
10023
|
+
}
|
|
10024
|
+
return {
|
|
10025
|
+
status: "completed",
|
|
10026
|
+
runId: state.runId,
|
|
10027
|
+
pending: { poll: 0, webhook: 0 },
|
|
10028
|
+
summary: state.summary
|
|
10029
|
+
};
|
|
10030
|
+
}
|
|
10031
|
+
const pending = { poll: 0, webhook: 0 };
|
|
10032
|
+
for (const batch of state.batches) {
|
|
10033
|
+
if (batch.status === "complete") continue;
|
|
10034
|
+
pending[processorForStage(definition, batch.kind, batch.scorerName).completion.mode]++;
|
|
10035
|
+
}
|
|
10036
|
+
return { status: "waiting", runId: state.runId, pending };
|
|
10037
|
+
}
|
|
10038
|
+
async function startCaseRoot(definition, state, record, experiment) {
|
|
10039
|
+
if (!experiment) return NOOP_SPAN;
|
|
10040
|
+
const datum = record.datum;
|
|
10041
|
+
return _internalStartSpanWithInitialMerge({
|
|
10042
|
+
...definition.evaluator.state ? { state: definition.evaluator.state } : {},
|
|
10043
|
+
parent: await experiment.export(),
|
|
10044
|
+
name: "eval",
|
|
10045
|
+
spanId: deterministicId(`${state.runId}:${record.id}:span`),
|
|
10046
|
+
spanAttributes: { type: "eval" /* EVAL */ },
|
|
10047
|
+
event: {
|
|
10048
|
+
id: deterministicId(`${state.runId}:${record.id}:row`),
|
|
10049
|
+
input: datum.input,
|
|
10050
|
+
expected: "expected" in datum ? datum.expected : void 0,
|
|
10051
|
+
tags: datum.tags,
|
|
10052
|
+
origin: datum.origin
|
|
10053
|
+
}
|
|
10054
|
+
});
|
|
10055
|
+
}
|
|
10056
|
+
async function logTaskResult(definition, state, record, experiment, task) {
|
|
10057
|
+
const datum = record.datum;
|
|
10058
|
+
const root = await startCaseRoot(definition, state, record, experiment);
|
|
10059
|
+
try {
|
|
10060
|
+
if (task) {
|
|
10061
|
+
const result = await root.traced(
|
|
10062
|
+
(span) => _internalRunEvaluatorTask(
|
|
10063
|
+
task,
|
|
10064
|
+
datum,
|
|
10065
|
+
record.trialIndex,
|
|
10066
|
+
state.parameters,
|
|
10067
|
+
span
|
|
10068
|
+
),
|
|
10069
|
+
{
|
|
10070
|
+
name: "task",
|
|
10071
|
+
spanId: deterministicId(`${state.runId}:${record.id}:task`),
|
|
10072
|
+
spanAttributes: { type: "task" /* TASK */ },
|
|
10073
|
+
event: { input: datum.input }
|
|
10074
|
+
}
|
|
10075
|
+
);
|
|
10076
|
+
record.output = assertJsonValue(
|
|
10077
|
+
result.output,
|
|
10078
|
+
`task output for ${record.caseId}`
|
|
10079
|
+
);
|
|
10080
|
+
record.metadata = assertJsonValue(result.metadata, "task metadata");
|
|
10081
|
+
record.tags = result.tags;
|
|
10082
|
+
record.taskComplete = true;
|
|
10083
|
+
} else {
|
|
10084
|
+
await root.traced((span) => span.log({ output: record.output }), {
|
|
10085
|
+
name: "task",
|
|
10086
|
+
spanId: deterministicId(`${state.runId}:${record.id}:task`),
|
|
10087
|
+
spanAttributes: { type: "task" /* TASK */ },
|
|
10088
|
+
event: { input: datum.input }
|
|
10089
|
+
});
|
|
10090
|
+
}
|
|
10091
|
+
root.log({
|
|
10092
|
+
output: record.output,
|
|
10093
|
+
expected: "expected" in datum ? datum.expected : void 0,
|
|
10094
|
+
metadata: {
|
|
10095
|
+
...record.metadata,
|
|
10096
|
+
durable_eval: {
|
|
10097
|
+
run_id: state.runId,
|
|
10098
|
+
case_id: record.caseId,
|
|
10099
|
+
trial_index: record.trialIndex
|
|
10100
|
+
}
|
|
10101
|
+
},
|
|
10102
|
+
tags: record.tags
|
|
10103
|
+
});
|
|
10104
|
+
record.rootSpan = await root.export();
|
|
10105
|
+
record.taskLogged = true;
|
|
10106
|
+
} catch (error) {
|
|
10107
|
+
logError(root, error);
|
|
10108
|
+
throw error;
|
|
10109
|
+
} finally {
|
|
10110
|
+
root.end();
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
async function logCompletedTasks(definition, state, store, key, experiment) {
|
|
10114
|
+
const changed = [];
|
|
10115
|
+
for (const record of state.cases) {
|
|
10116
|
+
if (!record.taskComplete || record.taskLogged) continue;
|
|
10117
|
+
if (!await claimAction(store, key, "task-log", record.id)) continue;
|
|
10118
|
+
await logTaskResult(definition, state, record, experiment);
|
|
10119
|
+
changed.push(record);
|
|
10120
|
+
}
|
|
10121
|
+
if (changed.length > 0) {
|
|
10122
|
+
await experiment?.flush();
|
|
10123
|
+
await writeCaseRecords(store, key, changed);
|
|
10124
|
+
}
|
|
10125
|
+
}
|
|
10126
|
+
async function runTaskStage(definition, state, store, key, experiment) {
|
|
10127
|
+
if (isBatchTask(definition.evaluator.task)) {
|
|
10128
|
+
await ensureBatches(definition, state, store, key, "task");
|
|
10129
|
+
return;
|
|
10130
|
+
}
|
|
10131
|
+
const task = definition.evaluator.task;
|
|
10132
|
+
const changed = [];
|
|
10133
|
+
for (const record of state.cases) {
|
|
10134
|
+
if (record.taskComplete) continue;
|
|
10135
|
+
if (!await claimAction(store, key, "task", record.id)) continue;
|
|
10136
|
+
await logTaskResult(definition, state, record, experiment, task);
|
|
10137
|
+
changed.push(record);
|
|
10138
|
+
}
|
|
10139
|
+
if (changed.length > 0) {
|
|
10140
|
+
await experiment?.flush();
|
|
10141
|
+
await writeCaseRecords(store, key, changed);
|
|
10142
|
+
}
|
|
10143
|
+
}
|
|
10144
|
+
async function runScoreStages(definition, state, store, key, experiment) {
|
|
10145
|
+
const scorers = resolveScorers(definition.evaluator.scores ?? []);
|
|
10146
|
+
const changed = /* @__PURE__ */ new Map();
|
|
10147
|
+
const persistChangedCases = async () => {
|
|
10148
|
+
if (changed.size === 0) return;
|
|
10149
|
+
await experiment?.flush();
|
|
10150
|
+
await writeCaseRecords(store, key, [...changed.values()]);
|
|
10151
|
+
changed.clear();
|
|
10152
|
+
};
|
|
10153
|
+
for (const { name, scorer } of scorers) {
|
|
10154
|
+
if (isBatchScorer(scorer)) {
|
|
10155
|
+
for (const record of state.cases) {
|
|
10156
|
+
if (Object.hasOwn(record.scores, name) && !Object.hasOwn(record.loggedScores, name)) {
|
|
10157
|
+
if (!await claimAction(store, key, "score-log", record.id, name)) {
|
|
10158
|
+
continue;
|
|
10159
|
+
}
|
|
10160
|
+
await evaluateAndLogScore(
|
|
10161
|
+
definition,
|
|
10162
|
+
state,
|
|
10163
|
+
record,
|
|
10164
|
+
name,
|
|
10165
|
+
experiment
|
|
10166
|
+
);
|
|
10167
|
+
changed.set(record.id, record);
|
|
10168
|
+
}
|
|
10169
|
+
}
|
|
10170
|
+
await persistChangedCases();
|
|
10171
|
+
await ensureBatches(definition, state, store, key, "score", name);
|
|
10172
|
+
continue;
|
|
10173
|
+
}
|
|
10174
|
+
for (const record of state.cases) {
|
|
10175
|
+
if (Object.hasOwn(record.loggedScores, name)) continue;
|
|
10176
|
+
if (!await claimAction(store, key, "score", record.id, name)) continue;
|
|
10177
|
+
await evaluateAndLogScore(
|
|
10178
|
+
definition,
|
|
10179
|
+
state,
|
|
10180
|
+
record,
|
|
10181
|
+
name,
|
|
10182
|
+
experiment,
|
|
10183
|
+
scorer
|
|
10184
|
+
);
|
|
10185
|
+
changed.set(record.id, record);
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
10188
|
+
for (const [index, classifier] of (definition.evaluator.classifiers ?? []).entries()) {
|
|
10189
|
+
const name = classifierName(classifier, index);
|
|
10190
|
+
for (const record of state.cases) {
|
|
10191
|
+
if (Object.hasOwn(record.loggedClassifications, name)) continue;
|
|
10192
|
+
if (!await claimAction(store, key, "classification", record.id, name)) {
|
|
10193
|
+
continue;
|
|
10194
|
+
}
|
|
10195
|
+
await evaluateAndLogClassification(
|
|
10196
|
+
definition,
|
|
10197
|
+
state,
|
|
10198
|
+
record,
|
|
10199
|
+
name,
|
|
10200
|
+
classifier,
|
|
10201
|
+
experiment
|
|
10202
|
+
);
|
|
10203
|
+
changed.set(record.id, record);
|
|
10204
|
+
}
|
|
10205
|
+
}
|
|
10206
|
+
await persistChangedCases();
|
|
10207
|
+
}
|
|
10208
|
+
function scorerArgs(record) {
|
|
10209
|
+
const datum = record.datum;
|
|
10210
|
+
return {
|
|
10211
|
+
...datum,
|
|
10212
|
+
metadata: record.metadata,
|
|
10213
|
+
output: record.output
|
|
10214
|
+
};
|
|
10215
|
+
}
|
|
10216
|
+
function resumeCaseRoot(definition, record, experiment) {
|
|
10217
|
+
if (!experiment) return NOOP_SPAN;
|
|
10218
|
+
if (!record.rootSpan) {
|
|
10219
|
+
throw new Error(`Durable eval case ${record.caseId} has no root span`);
|
|
10220
|
+
}
|
|
10221
|
+
return _internalResumeSpan({
|
|
10222
|
+
exported: record.rootSpan,
|
|
10223
|
+
state: definition.evaluator.state
|
|
10224
|
+
});
|
|
10225
|
+
}
|
|
10226
|
+
async function evaluateAndLogScore(definition, state, record, name, experiment, scorer) {
|
|
10227
|
+
const root = resumeCaseRoot(definition, record, experiment);
|
|
10228
|
+
try {
|
|
10229
|
+
const rootExport = await root.export();
|
|
10230
|
+
const prepared = await root.traced(
|
|
10231
|
+
async (span) => {
|
|
10232
|
+
const value = scorer ? await scorer(scorerArgs(record)) : record.scores[name];
|
|
10233
|
+
if (scorer) {
|
|
10234
|
+
record.scores[name] = assertJsonValue(value, `scorer ${name} output`);
|
|
10235
|
+
}
|
|
10236
|
+
const result = _internalPrepareEvaluatorScore(value, name);
|
|
10237
|
+
if (result.results !== null) {
|
|
10238
|
+
span.log({
|
|
10239
|
+
output: result.output,
|
|
10240
|
+
metadata: result.metadata,
|
|
10241
|
+
scores: result.scores
|
|
10242
|
+
});
|
|
10243
|
+
}
|
|
10244
|
+
return result;
|
|
10245
|
+
},
|
|
10246
|
+
{
|
|
10247
|
+
name,
|
|
10248
|
+
spanId: deterministicId(`${state.runId}:${record.id}:score:${name}`),
|
|
10249
|
+
spanAttributes: {
|
|
10250
|
+
type: "score" /* SCORE */,
|
|
10251
|
+
purpose: "scorer"
|
|
10252
|
+
},
|
|
10253
|
+
propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
|
|
10254
|
+
event: { input: scorerArgs(record) }
|
|
10255
|
+
}
|
|
10256
|
+
);
|
|
10257
|
+
if (prepared.scores) root.log({ scores: prepared.scores });
|
|
10258
|
+
record.loggedScores[name] = true;
|
|
10259
|
+
} catch (error) {
|
|
10260
|
+
logError(root, error);
|
|
10261
|
+
throw error;
|
|
10262
|
+
} finally {
|
|
10263
|
+
root.end();
|
|
10264
|
+
}
|
|
10265
|
+
}
|
|
10266
|
+
async function evaluateAndLogClassification(definition, state, record, name, classifier, experiment) {
|
|
10267
|
+
const root = resumeCaseRoot(definition, record, experiment);
|
|
10268
|
+
try {
|
|
10269
|
+
const rootExport = await root.export();
|
|
10270
|
+
const prepared = await root.traced(
|
|
10271
|
+
async (span) => {
|
|
10272
|
+
const value = await classifier(scorerArgs(record));
|
|
10273
|
+
record.classifications[name] = assertJsonValue(
|
|
10274
|
+
value,
|
|
10275
|
+
`classifier ${name} output`
|
|
10276
|
+
);
|
|
10277
|
+
const result = _internalPrepareEvaluatorClassification(value, name);
|
|
10278
|
+
if (result.results !== null) {
|
|
10279
|
+
span.log({ output: result.output, metadata: result.metadata });
|
|
10280
|
+
}
|
|
10281
|
+
return result;
|
|
10282
|
+
},
|
|
10283
|
+
{
|
|
10284
|
+
name,
|
|
10285
|
+
spanId: deterministicId(
|
|
10286
|
+
`${state.runId}:${record.id}:classification:${name}`
|
|
10287
|
+
),
|
|
10288
|
+
spanAttributes: {
|
|
10289
|
+
type: "classifier" /* CLASSIFIER */,
|
|
10290
|
+
purpose: "scorer"
|
|
10291
|
+
},
|
|
10292
|
+
propagatedEvent: makeScorerPropagatedEvent(rootExport || void 0),
|
|
10293
|
+
event: { input: scorerArgs(record) }
|
|
10294
|
+
}
|
|
10295
|
+
);
|
|
10296
|
+
if (prepared.classifications) {
|
|
10297
|
+
root.log({ classifications: prepared.classifications });
|
|
10298
|
+
}
|
|
10299
|
+
record.loggedClassifications[name] = true;
|
|
10300
|
+
} catch (error) {
|
|
10301
|
+
logError(root, error);
|
|
10302
|
+
throw error;
|
|
10303
|
+
} finally {
|
|
10304
|
+
root.end();
|
|
10305
|
+
}
|
|
10306
|
+
}
|
|
10307
|
+
async function ensureBatches(definition, state, store, key, kind, scorerName2) {
|
|
10308
|
+
const processor = processorForStage(definition, kind, scorerName2);
|
|
10309
|
+
const plans = plannedBatches(
|
|
10310
|
+
definition,
|
|
10311
|
+
state.runId,
|
|
10312
|
+
state.cases.map(({ id }) => id)
|
|
10313
|
+
);
|
|
10314
|
+
const casesById = new Map(state.cases.map((record) => [record.id, record]));
|
|
10315
|
+
for (const plan of plans) {
|
|
10316
|
+
if (plan.kind !== kind || plan.scorerName !== scorerName2) continue;
|
|
10317
|
+
if (state.batches.some(({ id }) => id === plan.id)) continue;
|
|
10318
|
+
const records = plan.itemIds.map((id) => casesById.get(id));
|
|
10319
|
+
const ready = records.every(
|
|
10320
|
+
(record) => kind === "task" ? !record.taskComplete : !Object.hasOwn(record.scores, scorerName2)
|
|
10321
|
+
);
|
|
10322
|
+
if (!ready) continue;
|
|
10323
|
+
const batchId = plan.id;
|
|
10324
|
+
const claim = await store.getOrSet(
|
|
10325
|
+
claimRecordKey(key, "batch", batchId),
|
|
10326
|
+
encoder.encode(batchId)
|
|
10327
|
+
);
|
|
10328
|
+
if (!claim.created) continue;
|
|
10329
|
+
const context = { runId: state.runId, batchId };
|
|
10330
|
+
const items = records.map(
|
|
10331
|
+
(record) => kind === "task" ? taskBatchItem(record, state.parameters) : scorerBatchItem(record)
|
|
10332
|
+
);
|
|
10333
|
+
const submissionData = assertJsonValue(
|
|
10334
|
+
await processor.submit(items, context),
|
|
10335
|
+
`submission data for batch ${batchId}`
|
|
10336
|
+
);
|
|
10337
|
+
const externalId = processor.completion.mode === "webhook" ? processor.completion.getExternalId(submissionData, context) : void 0;
|
|
10338
|
+
if (externalId !== void 0 && !externalId.trim()) {
|
|
10339
|
+
throw new Error(`Batch ${batchId} produced an empty externalId`);
|
|
10340
|
+
}
|
|
10341
|
+
const batch = {
|
|
10342
|
+
id: batchId,
|
|
10343
|
+
kind,
|
|
10344
|
+
scorerName: scorerName2,
|
|
10345
|
+
itemIds: records.map((record) => record.id),
|
|
10346
|
+
submissionData,
|
|
10347
|
+
externalId,
|
|
10348
|
+
status: "submitted"
|
|
10349
|
+
};
|
|
10350
|
+
state.batches.push(batch);
|
|
10351
|
+
await writeBatchRecords(store, key, [batch]);
|
|
10352
|
+
}
|
|
10353
|
+
}
|
|
10354
|
+
async function collectBatch(definition, state, batch) {
|
|
10355
|
+
const processor = processorForStage(definition, batch.kind, batch.scorerName);
|
|
10356
|
+
const context = { runId: state.runId, batchId: batch.id };
|
|
10357
|
+
const results = await processor.collect(batch.submissionData, context);
|
|
10358
|
+
if (!Array.isArray(results)) {
|
|
10359
|
+
throw new Error(`collect for batch ${batch.id} must return an array`);
|
|
10360
|
+
}
|
|
10361
|
+
const expectedIds = new Set(batch.itemIds);
|
|
10362
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10363
|
+
const records = [];
|
|
10364
|
+
for (const result of results) {
|
|
10365
|
+
const id = resultItemId(result);
|
|
10366
|
+
if (!expectedIds.has(id)) {
|
|
10367
|
+
throw new Error(`Batch ${batch.id} returned unknown item ${id}`);
|
|
10368
|
+
}
|
|
10369
|
+
if (seen.has(id)) {
|
|
10370
|
+
throw new Error(`Batch ${batch.id} returned item ${id} more than once`);
|
|
10371
|
+
}
|
|
10372
|
+
seen.add(id);
|
|
10373
|
+
const record = state.cases.find((candidate) => candidate.id === id);
|
|
10374
|
+
records.push(record);
|
|
10375
|
+
if (batch.kind === "task") {
|
|
10376
|
+
record.output = assertJsonValue(
|
|
10377
|
+
result.output,
|
|
10378
|
+
`task output for item ${id}`
|
|
10379
|
+
);
|
|
10380
|
+
if ("metadata" in result && result.metadata !== void 0) {
|
|
10381
|
+
record.metadata = assertJsonValue(
|
|
10382
|
+
{
|
|
10383
|
+
...record.metadata,
|
|
10384
|
+
...result.metadata
|
|
10385
|
+
},
|
|
10386
|
+
`metadata for ${id}`
|
|
10387
|
+
);
|
|
10388
|
+
}
|
|
10389
|
+
if ("tags" in result && result.tags !== void 0)
|
|
10390
|
+
record.tags = result.tags;
|
|
10391
|
+
record.taskComplete = true;
|
|
10392
|
+
} else {
|
|
10393
|
+
record.scores[batch.scorerName] = assertJsonValue(
|
|
10394
|
+
result.score,
|
|
10395
|
+
`score output for item ${id}`
|
|
10396
|
+
);
|
|
10397
|
+
}
|
|
10398
|
+
}
|
|
10399
|
+
const missing = batch.itemIds.filter((id) => !seen.has(id));
|
|
10400
|
+
if (missing.length > 0) {
|
|
10401
|
+
throw new Error(
|
|
10402
|
+
`Batch ${batch.id} did not return results for: ${missing.join(", ")}`
|
|
10403
|
+
);
|
|
10404
|
+
}
|
|
10405
|
+
return records;
|
|
10406
|
+
}
|
|
10407
|
+
function processorForStage(definition, kind, scorerName2) {
|
|
10408
|
+
if (kind === "task") {
|
|
10409
|
+
if (!isBatchTask(definition.evaluator.task)) {
|
|
10410
|
+
throw new Error("Definition no longer contains the batch task");
|
|
10411
|
+
}
|
|
10412
|
+
return definition.evaluator.task.processor;
|
|
10413
|
+
}
|
|
10414
|
+
const scorer = resolveScorers(definition.evaluator.scores ?? []).find(
|
|
10415
|
+
({ name }) => name === scorerName2
|
|
10416
|
+
)?.scorer;
|
|
10417
|
+
if (!isBatchScorer(scorer)) {
|
|
10418
|
+
throw new Error(`Definition no longer contains scorer ${scorerName2}`);
|
|
10419
|
+
}
|
|
10420
|
+
return scorer.processor;
|
|
10421
|
+
}
|
|
10422
|
+
async function materializeCases(definition, data, experiment) {
|
|
10423
|
+
const evaluator = definition.evaluator;
|
|
10424
|
+
const iterable = await _internalResolveEvaluatorData(
|
|
10425
|
+
{
|
|
10426
|
+
data,
|
|
10427
|
+
projectName: definition.projectName,
|
|
10428
|
+
projectId: evaluator.projectId,
|
|
10429
|
+
state: evaluator.state
|
|
10430
|
+
},
|
|
10431
|
+
experiment
|
|
10432
|
+
);
|
|
10433
|
+
const records = [];
|
|
10434
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10435
|
+
for await (const datum of iterable) {
|
|
10436
|
+
const caseId = datum.id ?? datum.upsert_id ?? (evaluator.caseId ? await evaluator.caseId(datum) : void 0);
|
|
10437
|
+
if (!caseId) {
|
|
10438
|
+
throw new Error(
|
|
10439
|
+
"Every durable eval case requires id, upsert_id, or caseId"
|
|
10440
|
+
);
|
|
10441
|
+
}
|
|
10442
|
+
if (seen.has(caseId))
|
|
10443
|
+
throw new Error(`Duplicate durable eval case id: ${caseId}`);
|
|
10444
|
+
seen.add(caseId);
|
|
10445
|
+
const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
|
|
10446
|
+
if (!Number.isInteger(trialCount) || trialCount < 1) {
|
|
10447
|
+
throw new Error(`Invalid trialCount for durable eval case ${caseId}`);
|
|
10448
|
+
}
|
|
10449
|
+
for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
|
|
10450
|
+
records.push({
|
|
10451
|
+
id: `${caseId}:trial:${trialIndex}`,
|
|
10452
|
+
caseId,
|
|
10453
|
+
trialIndex,
|
|
10454
|
+
datum: assertJsonValue(datum, `case ${caseId}`),
|
|
10455
|
+
metadata: assertJsonValue(
|
|
10456
|
+
"metadata" in datum ? datum.metadata : {},
|
|
10457
|
+
`metadata for ${caseId}`
|
|
10458
|
+
),
|
|
10459
|
+
tags: datum.tags,
|
|
10460
|
+
taskComplete: false,
|
|
10461
|
+
taskLogged: false,
|
|
10462
|
+
scores: /* @__PURE__ */ Object.create(null),
|
|
10463
|
+
loggedScores: /* @__PURE__ */ Object.create(null),
|
|
10464
|
+
classifications: /* @__PURE__ */ Object.create(null),
|
|
10465
|
+
loggedClassifications: /* @__PURE__ */ Object.create(null)
|
|
10466
|
+
});
|
|
10467
|
+
}
|
|
10468
|
+
}
|
|
10469
|
+
return records;
|
|
10470
|
+
}
|
|
10471
|
+
function taskBatchItem(record, parameters) {
|
|
10472
|
+
const datum = record.datum;
|
|
10473
|
+
return {
|
|
10474
|
+
id: record.id,
|
|
10475
|
+
input: datum.input,
|
|
10476
|
+
expected: "expected" in datum ? datum.expected : void 0,
|
|
10477
|
+
metadata: record.metadata,
|
|
10478
|
+
tags: record.tags,
|
|
10479
|
+
parameters,
|
|
10480
|
+
trialIndex: record.trialIndex
|
|
10481
|
+
};
|
|
10482
|
+
}
|
|
10483
|
+
function scorerBatchItem(record) {
|
|
10484
|
+
const datum = record.datum;
|
|
10485
|
+
return {
|
|
10486
|
+
id: record.id,
|
|
10487
|
+
input: datum.input,
|
|
10488
|
+
output: record.output,
|
|
10489
|
+
expected: "expected" in datum ? datum.expected : void 0,
|
|
10490
|
+
metadata: record.metadata,
|
|
10491
|
+
tags: record.tags,
|
|
10492
|
+
trialIndex: record.trialIndex
|
|
10493
|
+
};
|
|
10494
|
+
}
|
|
10495
|
+
async function finishExperiment(definition, state, experiment) {
|
|
10496
|
+
const scorerNames = resolveScorers(definition.evaluator.scores ?? []).map(
|
|
10497
|
+
({ name }) => name
|
|
10498
|
+
);
|
|
10499
|
+
const results = state.cases.map((record) => {
|
|
10500
|
+
const datum = record.datum;
|
|
10501
|
+
const scores = Object.fromEntries(
|
|
10502
|
+
scorerNames.flatMap(
|
|
10503
|
+
(name) => Object.entries(
|
|
10504
|
+
_internalPrepareEvaluatorScore(
|
|
10505
|
+
record.scores[name],
|
|
10506
|
+
name
|
|
10507
|
+
).scores ?? {}
|
|
10508
|
+
)
|
|
10509
|
+
)
|
|
10510
|
+
);
|
|
10511
|
+
const classifications = Object.fromEntries(
|
|
10512
|
+
Object.entries(record.classifications).flatMap(
|
|
10513
|
+
([name, value]) => Object.entries(
|
|
10514
|
+
_internalPrepareEvaluatorClassification(value, name).classifications ?? {}
|
|
10515
|
+
)
|
|
10516
|
+
)
|
|
10517
|
+
);
|
|
10518
|
+
return {
|
|
10519
|
+
...datum,
|
|
10520
|
+
output: record.output,
|
|
10521
|
+
metadata: record.metadata,
|
|
10522
|
+
tags: record.tags,
|
|
10523
|
+
scores,
|
|
10524
|
+
error: void 0,
|
|
10525
|
+
...Object.keys(classifications).length > 0 ? { classifications } : {}
|
|
10526
|
+
};
|
|
10527
|
+
});
|
|
10528
|
+
if (!experiment) {
|
|
10529
|
+
return buildLocalSummary(
|
|
10530
|
+
{
|
|
10531
|
+
...definition.evaluator,
|
|
10532
|
+
projectName: definition.projectName,
|
|
10533
|
+
evalName: state.experimentName
|
|
10534
|
+
},
|
|
10535
|
+
results
|
|
10536
|
+
);
|
|
10537
|
+
}
|
|
10538
|
+
await experiment.flush();
|
|
10539
|
+
let comparisonExperimentId = definition.evaluator.baseExperimentId;
|
|
10540
|
+
if (!comparisonExperimentId) {
|
|
10541
|
+
try {
|
|
10542
|
+
comparisonExperimentId = await experiment._getBaseExperimentId();
|
|
10543
|
+
} catch {
|
|
10544
|
+
comparisonExperimentId = void 0;
|
|
10545
|
+
}
|
|
10546
|
+
}
|
|
10547
|
+
return await experiment.summarize({
|
|
10548
|
+
summarizeScores: definition.evaluator.summarizeScores,
|
|
10549
|
+
...comparisonExperimentId ? { comparisonExperimentId } : {}
|
|
10550
|
+
});
|
|
10551
|
+
}
|
|
10552
|
+
function resolveScorers(scorers) {
|
|
10553
|
+
return scorers.map((scorer, index) => ({
|
|
10554
|
+
name: isBatchScorer(scorer) ? scorer.name : scorer.name || `scorer_${index}`,
|
|
10555
|
+
scorer
|
|
10556
|
+
}));
|
|
10557
|
+
}
|
|
10558
|
+
function runKey(projectName, evalName, runId) {
|
|
10559
|
+
return `durable-eval/v1/runs/${contentVersion(encoder.encode(`${projectName}\0${evalName}\0${runId}`))}`;
|
|
10560
|
+
}
|
|
10561
|
+
function encodedKeyPart(value) {
|
|
10562
|
+
return uint8ArrayToBase64(encoder.encode(value)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
10563
|
+
}
|
|
10564
|
+
function caseRecordKey(key, caseId, kind, ...names) {
|
|
10565
|
+
const suffix = names.map(encodedKeyPart).join("/");
|
|
10566
|
+
return `${key}/cases/${encodedKeyPart(caseId)}/${kind}${suffix ? `/${suffix}` : ""}`;
|
|
10567
|
+
}
|
|
10568
|
+
function batchRecordKey(key, batchId) {
|
|
10569
|
+
return `${key}/batches/${encodedKeyPart(batchId)}`;
|
|
10570
|
+
}
|
|
10571
|
+
function claimRecordKey(key, kind, ...parts) {
|
|
10572
|
+
const identity = stableStringify([kind, parts]);
|
|
10573
|
+
return `${key}/claims/${contentVersion(encoder.encode(identity))}`;
|
|
10574
|
+
}
|
|
10575
|
+
async function claimAction(store, key, kind, ...parts) {
|
|
10576
|
+
return (await store.getOrSet(
|
|
10577
|
+
claimRecordKey(key, kind, ...parts),
|
|
10578
|
+
encoder.encode("claimed")
|
|
10579
|
+
)).created;
|
|
10580
|
+
}
|
|
10581
|
+
function plannedBatches(definition, runId, caseIds) {
|
|
10582
|
+
const stages = [];
|
|
10583
|
+
if (isBatchTask(definition.evaluator.task)) stages.push({ kind: "task" });
|
|
10584
|
+
for (const { name, scorer } of resolveScorers(
|
|
10585
|
+
definition.evaluator.scores ?? []
|
|
10586
|
+
)) {
|
|
10587
|
+
if (isBatchScorer(scorer)) {
|
|
10588
|
+
stages.push({ kind: "score", scorerName: name });
|
|
10589
|
+
}
|
|
10590
|
+
}
|
|
10591
|
+
const plans = [];
|
|
10592
|
+
for (const { kind, scorerName: scorerName2 } of stages) {
|
|
10593
|
+
const batchSize = processorForStage(definition, kind, scorerName2).batchSize ?? DEFAULT_BATCH_SIZE;
|
|
10594
|
+
if (!Number.isInteger(batchSize) || batchSize < 1) {
|
|
10595
|
+
throw new Error(
|
|
10596
|
+
`Invalid batchSize for ${scorerName2 ?? "task"}: ${batchSize}`
|
|
10597
|
+
);
|
|
10598
|
+
}
|
|
10599
|
+
for (let offset = 0; offset < caseIds.length; offset += batchSize) {
|
|
10600
|
+
const itemIds = caseIds.slice(offset, offset + batchSize);
|
|
10601
|
+
plans.push({
|
|
10602
|
+
id: deterministicId(
|
|
10603
|
+
stableStringify([runId, kind, scorerName2, itemIds])
|
|
10604
|
+
),
|
|
10605
|
+
kind,
|
|
10606
|
+
scorerName: scorerName2,
|
|
10607
|
+
itemIds
|
|
10608
|
+
});
|
|
10609
|
+
}
|
|
10610
|
+
}
|
|
10611
|
+
return plans;
|
|
10612
|
+
}
|
|
10613
|
+
async function readCaseRecord(definition, store, key, id) {
|
|
10614
|
+
const scorers = resolveScorers(definition.evaluator.scores ?? []);
|
|
10615
|
+
const classifiers = (definition.evaluator.classifiers ?? []).map(
|
|
10616
|
+
classifierName
|
|
10617
|
+
);
|
|
10618
|
+
const [
|
|
10619
|
+
base,
|
|
10620
|
+
task,
|
|
10621
|
+
taskLog,
|
|
10622
|
+
scoreValues,
|
|
10623
|
+
scoreLogValues,
|
|
10624
|
+
classificationValues,
|
|
10625
|
+
classificationLogValues
|
|
10626
|
+
] = await Promise.all([
|
|
10627
|
+
readJson(store, caseRecordKey(key, id, "base")),
|
|
10628
|
+
readJson(store, caseRecordKey(key, id, "task")),
|
|
10629
|
+
readJson(store, caseRecordKey(key, id, "task-log")),
|
|
10630
|
+
Promise.all(
|
|
10631
|
+
scorers.map(async ({ name }) => ({
|
|
10632
|
+
name,
|
|
10633
|
+
value: await readJson(
|
|
10634
|
+
store,
|
|
10635
|
+
caseRecordKey(key, id, "score", name)
|
|
10636
|
+
)
|
|
10637
|
+
}))
|
|
10638
|
+
),
|
|
10639
|
+
Promise.all(
|
|
10640
|
+
scorers.map(async ({ name }) => ({
|
|
10641
|
+
name,
|
|
10642
|
+
value: await readJson(
|
|
10643
|
+
store,
|
|
10644
|
+
caseRecordKey(key, id, "score-log", name)
|
|
10645
|
+
)
|
|
10646
|
+
}))
|
|
10647
|
+
),
|
|
10648
|
+
Promise.all(
|
|
10649
|
+
classifiers.map(async (name) => ({
|
|
10650
|
+
name,
|
|
10651
|
+
value: await readJson(
|
|
10652
|
+
store,
|
|
10653
|
+
caseRecordKey(key, id, "classification", name)
|
|
10654
|
+
)
|
|
10655
|
+
}))
|
|
10656
|
+
),
|
|
10657
|
+
Promise.all(
|
|
10658
|
+
classifiers.map(async (name) => ({
|
|
10659
|
+
name,
|
|
10660
|
+
value: await readJson(
|
|
10661
|
+
store,
|
|
10662
|
+
caseRecordKey(key, id, "classification-log", name)
|
|
10663
|
+
)
|
|
10664
|
+
}))
|
|
10665
|
+
)
|
|
10666
|
+
]);
|
|
10667
|
+
if (!base) throw new Error(`Durable eval case ${id} is missing`);
|
|
10668
|
+
const scores = /* @__PURE__ */ Object.create(null);
|
|
10669
|
+
for (const { name, value } of scoreValues) {
|
|
10670
|
+
if (value !== void 0) scores[name] = value;
|
|
10671
|
+
}
|
|
10672
|
+
const loggedScores = /* @__PURE__ */ Object.create(null);
|
|
10673
|
+
for (const { name, value } of scoreLogValues) {
|
|
10674
|
+
if (value) loggedScores[name] = true;
|
|
10675
|
+
}
|
|
10676
|
+
const classifications = /* @__PURE__ */ Object.create(null);
|
|
10677
|
+
for (const { name, value } of classificationValues) {
|
|
10678
|
+
if (value !== void 0) classifications[name] = value;
|
|
10679
|
+
}
|
|
10680
|
+
const loggedClassifications = /* @__PURE__ */ Object.create(null);
|
|
10681
|
+
for (const { name, value } of classificationLogValues) {
|
|
10682
|
+
if (value) loggedClassifications[name] = true;
|
|
10683
|
+
}
|
|
10684
|
+
return {
|
|
10685
|
+
...base,
|
|
10686
|
+
metadata: task?.metadata ?? base.metadata,
|
|
10687
|
+
tags: task ? task.tags : base.tags,
|
|
10688
|
+
taskComplete: task !== void 0,
|
|
10689
|
+
taskLogged: taskLog !== void 0,
|
|
10690
|
+
output: task?.output,
|
|
10691
|
+
rootSpan: taskLog?.rootSpan,
|
|
10692
|
+
scores,
|
|
10693
|
+
loggedScores,
|
|
10694
|
+
classifications,
|
|
10695
|
+
loggedClassifications
|
|
10696
|
+
};
|
|
10697
|
+
}
|
|
10698
|
+
async function readRunState(definition, store, key) {
|
|
10699
|
+
const record = await readJson(store, key);
|
|
10700
|
+
if (!record) return void 0;
|
|
10701
|
+
const plans = plannedBatches(definition, record.runId, record.caseIds);
|
|
10702
|
+
const [cases, batchRecords] = await Promise.all([
|
|
10703
|
+
Promise.all(
|
|
10704
|
+
record.caseIds.map((id) => readCaseRecord(definition, store, key, id))
|
|
10705
|
+
),
|
|
10706
|
+
Promise.all(
|
|
10707
|
+
plans.map(async ({ id }) => {
|
|
10708
|
+
return readJson(store, batchRecordKey(key, id));
|
|
10709
|
+
})
|
|
10710
|
+
)
|
|
10711
|
+
]);
|
|
10712
|
+
const batches = batchRecords.filter(
|
|
10713
|
+
(value) => value !== void 0
|
|
10714
|
+
);
|
|
10715
|
+
const { caseIds: _caseIds, ...state } = record;
|
|
10716
|
+
return { ...state, cases, batches };
|
|
10717
|
+
}
|
|
10718
|
+
async function writeRunRecord(store, key, state) {
|
|
10719
|
+
const { cases, batches: _batches, ...record } = state;
|
|
10720
|
+
await writeJson(store, key, {
|
|
10721
|
+
...record,
|
|
10722
|
+
caseIds: cases.map(({ id }) => id)
|
|
10723
|
+
});
|
|
10724
|
+
}
|
|
10725
|
+
async function writeCaseBaseRecords(store, key, records) {
|
|
10726
|
+
await Promise.all(
|
|
10727
|
+
records.map(
|
|
10728
|
+
({ id, caseId, trialIndex, datum, metadata, tags }) => writeJson(store, caseRecordKey(key, id, "base"), {
|
|
10729
|
+
id,
|
|
10730
|
+
caseId,
|
|
10731
|
+
trialIndex,
|
|
10732
|
+
datum,
|
|
10733
|
+
metadata,
|
|
10734
|
+
tags
|
|
10735
|
+
})
|
|
10736
|
+
)
|
|
10737
|
+
);
|
|
10738
|
+
}
|
|
10739
|
+
async function writeCaseRecords(store, key, records) {
|
|
10740
|
+
const writes = [];
|
|
10741
|
+
for (const record of records) {
|
|
10742
|
+
if (record.taskComplete) {
|
|
10743
|
+
writes.push(
|
|
10744
|
+
writeJson(store, caseRecordKey(key, record.id, "task"), {
|
|
10745
|
+
output: record.output,
|
|
10746
|
+
metadata: record.metadata,
|
|
10747
|
+
tags: record.tags,
|
|
10748
|
+
taskComplete: true
|
|
10749
|
+
})
|
|
10750
|
+
);
|
|
10751
|
+
}
|
|
10752
|
+
if (record.taskLogged) {
|
|
10753
|
+
writes.push(
|
|
10754
|
+
writeJson(store, caseRecordKey(key, record.id, "task-log"), {
|
|
10755
|
+
rootSpan: record.rootSpan,
|
|
10756
|
+
taskLogged: true
|
|
10757
|
+
})
|
|
10758
|
+
);
|
|
10759
|
+
}
|
|
10760
|
+
for (const [name, value] of Object.entries(record.scores)) {
|
|
10761
|
+
writes.push(
|
|
10762
|
+
writeJson(store, caseRecordKey(key, record.id, "score", name), value)
|
|
10763
|
+
);
|
|
10764
|
+
}
|
|
10765
|
+
for (const name of Object.keys(record.loggedScores)) {
|
|
10766
|
+
writes.push(
|
|
10767
|
+
writeJson(
|
|
10768
|
+
store,
|
|
10769
|
+
caseRecordKey(key, record.id, "score-log", name),
|
|
10770
|
+
true
|
|
10771
|
+
)
|
|
10772
|
+
);
|
|
10773
|
+
}
|
|
10774
|
+
for (const [name, value] of Object.entries(record.classifications)) {
|
|
10775
|
+
writes.push(
|
|
10776
|
+
writeJson(
|
|
10777
|
+
store,
|
|
10778
|
+
caseRecordKey(key, record.id, "classification", name),
|
|
10779
|
+
value
|
|
10780
|
+
)
|
|
10781
|
+
);
|
|
10782
|
+
}
|
|
10783
|
+
for (const name of Object.keys(record.loggedClassifications)) {
|
|
10784
|
+
writes.push(
|
|
10785
|
+
writeJson(
|
|
10786
|
+
store,
|
|
10787
|
+
caseRecordKey(key, record.id, "classification-log", name),
|
|
10788
|
+
true
|
|
10789
|
+
)
|
|
10790
|
+
);
|
|
10791
|
+
}
|
|
10792
|
+
}
|
|
10793
|
+
await Promise.all(writes);
|
|
10794
|
+
}
|
|
10795
|
+
async function writeBatchRecords(store, key, records) {
|
|
10796
|
+
await Promise.all(
|
|
10797
|
+
records.map(
|
|
10798
|
+
(record) => writeJson(store, batchRecordKey(key, record.id), record)
|
|
10799
|
+
)
|
|
10800
|
+
);
|
|
10801
|
+
}
|
|
10802
|
+
function deterministicId(value) {
|
|
10803
|
+
const hex = contentVersion(encoder.encode(value)).padEnd(32, "0").slice(0, 32);
|
|
10804
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-a${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
|
|
10805
|
+
}
|
|
10806
|
+
function contentVersion(value) {
|
|
10807
|
+
if (isomorph_default.hash) return isomorph_default.hash(decoder.decode(value));
|
|
10808
|
+
let hash = 2166136261;
|
|
10809
|
+
for (const byte of value) {
|
|
10810
|
+
hash ^= byte;
|
|
10811
|
+
hash = Math.imul(hash, 16777619);
|
|
10812
|
+
}
|
|
10813
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
10814
|
+
}
|
|
10815
|
+
async function readJson(store, key) {
|
|
10816
|
+
const value = await store.read(key);
|
|
10817
|
+
return value ? JSON.parse(decoder.decode(value)) : void 0;
|
|
10818
|
+
}
|
|
10819
|
+
async function writeJson(store, key, value) {
|
|
10820
|
+
await store.write(key, encoder.encode(stableStringify(value)));
|
|
10821
|
+
}
|
|
10822
|
+
function stableStringify(value) {
|
|
10823
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
10824
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
10825
|
+
return Object.fromEntries(
|
|
10826
|
+
Object.entries(nested).sort(
|
|
10827
|
+
([left], [right]) => left.localeCompare(right)
|
|
10828
|
+
)
|
|
10829
|
+
);
|
|
10830
|
+
}
|
|
10831
|
+
return nested;
|
|
10832
|
+
});
|
|
10833
|
+
}
|
|
10834
|
+
function assertJsonValue(value, label) {
|
|
10835
|
+
try {
|
|
10836
|
+
const serialized = JSON.stringify(value);
|
|
10837
|
+
if (serialized === void 0)
|
|
10838
|
+
throw new Error("value serializes to undefined");
|
|
10839
|
+
return JSON.parse(serialized);
|
|
10840
|
+
} catch (error) {
|
|
10841
|
+
throw new Error(`${label} must be JSON serializable`, { cause: error });
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10844
|
+
function resultItemId(value) {
|
|
10845
|
+
if (typeof value !== "object" || value === null || !("id" in value) || typeof value.id !== "string") {
|
|
10846
|
+
throw new Error("Batch results must contain a string id");
|
|
10847
|
+
}
|
|
10848
|
+
return value.id;
|
|
10849
|
+
}
|
|
10850
|
+
function isBatchTask(value) {
|
|
10851
|
+
return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_TASK_KIND;
|
|
10852
|
+
}
|
|
10853
|
+
function isBatchScorer(value) {
|
|
10854
|
+
return typeof value === "object" && value !== null && "kind" in value && value.kind === BATCH_SCORER_KIND;
|
|
10855
|
+
}
|
|
10856
|
+
function asError(error) {
|
|
10857
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
10858
|
+
}
|
|
10859
|
+
|
|
9392
10860
|
// src/agent-assertions.ts
|
|
9393
10861
|
function agentAssertionScorer(callback, options = {}) {
|
|
9394
10862
|
return async (args) => {
|
|
@@ -10321,6 +11789,8 @@ export {
|
|
|
10321
11789
|
BRAINTRUST_PARENT_KEY,
|
|
10322
11790
|
BaseAttachment,
|
|
10323
11791
|
BaseExperiment,
|
|
11792
|
+
BatchScorer,
|
|
11793
|
+
BatchTask,
|
|
10324
11794
|
BraintrustLangChainCallbackHandler,
|
|
10325
11795
|
BraintrustMiddleware,
|
|
10326
11796
|
BraintrustObservabilityExporter,
|
|
@@ -10334,6 +11804,8 @@ export {
|
|
|
10334
11804
|
DEFAULT_MAX_REQUEST_SIZE,
|
|
10335
11805
|
Dataset,
|
|
10336
11806
|
DatasetPipeline,
|
|
11807
|
+
DurableEvalMemoryStore,
|
|
11808
|
+
DurableEvalRedisStore,
|
|
10337
11809
|
ERR_PERMALINK,
|
|
10338
11810
|
Eval,
|
|
10339
11811
|
EvalResultWithSummary,
|
|
@@ -10382,6 +11854,7 @@ export {
|
|
|
10382
11854
|
braintrustFlueObserver,
|
|
10383
11855
|
braintrustStreamChunkSchema,
|
|
10384
11856
|
buildLocalSummary,
|
|
11857
|
+
collectAnthropicSession,
|
|
10385
11858
|
configureInstrumentation,
|
|
10386
11859
|
constructLogs3OverflowRequest,
|
|
10387
11860
|
createFinalValuePassThroughStream,
|
|
@@ -10391,6 +11864,7 @@ export {
|
|
|
10391
11864
|
deepCopyEvent,
|
|
10392
11865
|
exports_exports as default,
|
|
10393
11866
|
defaultErrorScoreHandler,
|
|
11867
|
+
defineDurableEval,
|
|
10394
11868
|
deserializePlainStringAsJSON,
|
|
10395
11869
|
devNullWritableStream,
|
|
10396
11870
|
evaluatorDefinitionSchema,
|
|
@@ -10462,6 +11936,7 @@ export {
|
|
|
10462
11936
|
wrapClaudeAgentSDK,
|
|
10463
11937
|
wrapCloudflareAIChat,
|
|
10464
11938
|
wrapCloudflareAgent,
|
|
11939
|
+
wrapCloudflareThink,
|
|
10465
11940
|
wrapCohere,
|
|
10466
11941
|
wrapCopilotClient,
|
|
10467
11942
|
wrapCursorSDK,
|
|
@@ -10476,6 +11951,7 @@ export {
|
|
|
10476
11951
|
wrapLangSmithTraceable,
|
|
10477
11952
|
wrapMastraAgent,
|
|
10478
11953
|
wrapMistral,
|
|
11954
|
+
wrapOllama,
|
|
10479
11955
|
wrapOpenAI,
|
|
10480
11956
|
wrapOpenAICodexSDK,
|
|
10481
11957
|
wrapOpenAIv4,
|
|
@@ -10484,5 +11960,6 @@ export {
|
|
|
10484
11960
|
wrapPiCodingAgentSDK,
|
|
10485
11961
|
wrapStrandsAgentSDK,
|
|
10486
11962
|
wrapTraced,
|
|
10487
|
-
wrapVitest
|
|
11963
|
+
wrapVitest,
|
|
11964
|
+
wrapVoyageAI
|
|
10488
11965
|
};
|