veryfront 0.1.528 → 0.1.531
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/esm/deno.js +1 -1
- package/esm/src/agent/testing/index.d.ts +1 -1
- package/esm/src/agent/testing/index.d.ts.map +1 -1
- package/esm/src/agent/testing/index.js +1 -1
- package/esm/src/agent/testing/live-evals/api-client.d.ts +78 -0
- package/esm/src/agent/testing/live-evals/api-client.d.ts.map +1 -0
- package/esm/src/agent/testing/live-evals/api-client.js +302 -0
- package/esm/src/agent/testing/live-evals/index.d.ts +1 -0
- package/esm/src/agent/testing/live-evals/index.d.ts.map +1 -1
- package/esm/src/agent/testing/live-evals/index.js +1 -0
- package/esm/src/integrations/_data.js +7 -7
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/deps/esm.sh/@types/react-dom@19.2.3/client.d.ts +1 -1
- package/src/deps/esm.sh/@types/{react@19.2.14 → react@19.2.3}/global.d.ts +0 -1
- package/src/deps/esm.sh/@types/{react@19.2.14 → react@19.2.3}/index.d.ts +24 -93
- package/src/deps/esm.sh/react-dom@19.2.4/client.d.ts +1 -1
- package/src/src/agent/testing/index.ts +24 -0
- package/src/src/agent/testing/live-evals/api-client.ts +568 -0
- package/src/src/agent/testing/live-evals/index.ts +26 -0
- package/src/src/integrations/_data.ts +7 -7
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
import * as dntShim from "../../../../_dnt.shims.js";
|
|
2
|
+
import { ensureBuiltinSchemaValidator } from "../../../extensions/builtin-extensions.js";
|
|
3
|
+
import type { InferSchema } from "../../../extensions/schema/index.js";
|
|
4
|
+
import { defineSchema } from "../../../schemas/index.js";
|
|
5
|
+
import type { LiveEvalProjectFile } from "./runner.js";
|
|
6
|
+
|
|
7
|
+
ensureBuiltinSchemaValidator();
|
|
8
|
+
|
|
9
|
+
export interface LiveEvalApiContext {
|
|
10
|
+
apiUrl: string;
|
|
11
|
+
authToken: string;
|
|
12
|
+
projectId: string | null;
|
|
13
|
+
fetch?: (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LiveEvalRequestTimeoutInput {
|
|
17
|
+
requestTimeoutMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LiveEvalCreateConversationInput extends LiveEvalRequestTimeoutInput {
|
|
21
|
+
title: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface LiveEvalConversationInput extends LiveEvalRequestTimeoutInput {
|
|
25
|
+
conversationId: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface LiveEvalProjectUploadFixtureInput extends LiveEvalRequestTimeoutInput {
|
|
29
|
+
filePath: string;
|
|
30
|
+
contentType: string;
|
|
31
|
+
body: BodyInit | Uint8Array;
|
|
32
|
+
size?: number;
|
|
33
|
+
pollIntervalMs?: number;
|
|
34
|
+
maxAttempts?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface LiveEvalProjectFileInput extends LiveEvalRequestTimeoutInput {
|
|
38
|
+
filePath: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface LiveEvalCreateReleaseInput extends LiveEvalRequestTimeoutInput {
|
|
42
|
+
description?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface LiveEvalWaitForOpenInputRequestInput extends LiveEvalConversationInput {
|
|
46
|
+
abortSignal: AbortSignal;
|
|
47
|
+
pollIntervalMs?: number;
|
|
48
|
+
timeoutMs?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface LiveEvalInputResponseValues {
|
|
52
|
+
[key: string]: string | boolean | number | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface LiveEvalSubmitInputResponseInput extends LiveEvalRequestTimeoutInput {
|
|
56
|
+
conversationId: string;
|
|
57
|
+
inputRequestId: string;
|
|
58
|
+
values: LiveEvalInputResponseValues;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface LiveEvalInputRequestInput extends LiveEvalRequestTimeoutInput {
|
|
62
|
+
conversationId: string;
|
|
63
|
+
inputRequestId: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const getLiveEvalIdResponseSchema = defineSchema((v) =>
|
|
67
|
+
v.object({
|
|
68
|
+
id: v.string().optional(),
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const getProjectUploadResponseSchema = defineSchema((v) =>
|
|
73
|
+
v.object({
|
|
74
|
+
file_upload_url: v.string().optional(),
|
|
75
|
+
required_headers: v.record(v.string(), v.string()).optional(),
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const getProjectUploadListResponseSchema = defineSchema((v) =>
|
|
80
|
+
v.object({
|
|
81
|
+
data: v.array(v.object({ path: v.string().optional() }).passthrough()).optional(),
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const getProjectFileResponseSchema = defineSchema((v) =>
|
|
86
|
+
v.object({
|
|
87
|
+
path: v.string().optional(),
|
|
88
|
+
content: v.string().optional(),
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const getInputRequestRecordSchema = defineSchema((v) =>
|
|
93
|
+
v.object({
|
|
94
|
+
id: v.string(),
|
|
95
|
+
status: v.string(),
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const getInputRequestListResponseSchema = defineSchema((v) =>
|
|
100
|
+
v.object({
|
|
101
|
+
data: v.array(v.unknown()).optional(),
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
export type LiveEvalInputRequestRecord = InferSchema<
|
|
106
|
+
ReturnType<typeof getInputRequestRecordSchema>
|
|
107
|
+
>;
|
|
108
|
+
|
|
109
|
+
export interface LiveEvalApiClient {
|
|
110
|
+
createConversation(input: LiveEvalCreateConversationInput): Promise<string>;
|
|
111
|
+
deleteConversation(input: LiveEvalConversationInput): Promise<void>;
|
|
112
|
+
createProjectUploadFixture(input: LiveEvalProjectUploadFixtureInput): Promise<string>;
|
|
113
|
+
getProjectFile(input: LiveEvalProjectFileInput): Promise<LiveEvalProjectFile | null>;
|
|
114
|
+
createRelease(input: LiveEvalCreateReleaseInput): Promise<string>;
|
|
115
|
+
deleteProjectFile(input: LiveEvalProjectFileInput): Promise<void>;
|
|
116
|
+
listOpenInputRequests(input: LiveEvalConversationInput): Promise<LiveEvalInputRequestRecord[]>;
|
|
117
|
+
waitForOpenInputRequest(input: LiveEvalWaitForOpenInputRequestInput): Promise<string>;
|
|
118
|
+
submitInputResponse(input: LiveEvalSubmitInputResponseInput): Promise<void>;
|
|
119
|
+
cancelInputRequest(input: LiveEvalInputRequestInput): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function createLiveEvalAuthHeaders(context: LiveEvalApiContext): Headers {
|
|
123
|
+
const headers = new Headers();
|
|
124
|
+
headers.set("Authorization", `Bearer ${context.authToken}`);
|
|
125
|
+
return headers;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createLiveEvalJsonHeaders(context: LiveEvalApiContext): Headers {
|
|
129
|
+
const headers = createLiveEvalAuthHeaders(context);
|
|
130
|
+
headers.set("Content-Type", "application/json");
|
|
131
|
+
return headers;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function requireLiveEvalProjectId(projectId: string | null, errorMessage: string): string {
|
|
135
|
+
if (!projectId) {
|
|
136
|
+
throw new Error(errorMessage);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return projectId;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function createFetch(context: LiveEvalApiContext) {
|
|
143
|
+
return context.fetch ?? fetch;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createApiUrl(context: LiveEvalApiContext, path: string): URL {
|
|
147
|
+
const baseHref = context.apiUrl.endsWith("/") ? context.apiUrl : `${context.apiUrl}/`;
|
|
148
|
+
const relativePath = path.startsWith("/") ? path.slice(1) : path;
|
|
149
|
+
return new URL(relativePath, baseHref);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function createProjectUploadHeaders(
|
|
153
|
+
requiredHeaders: Record<string, string> | undefined,
|
|
154
|
+
contentType: string,
|
|
155
|
+
): Headers {
|
|
156
|
+
const uploadHeaders = new Headers(requiredHeaders);
|
|
157
|
+
if (!uploadHeaders.has("Content-Type")) {
|
|
158
|
+
uploadHeaders.set("Content-Type", contentType);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return uploadHeaders;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getProjectUploadBodySize(
|
|
165
|
+
body: BodyInit | Uint8Array,
|
|
166
|
+
explicitSize: number | undefined,
|
|
167
|
+
): number {
|
|
168
|
+
if (typeof explicitSize === "number") {
|
|
169
|
+
return explicitSize;
|
|
170
|
+
}
|
|
171
|
+
if (typeof body === "string") {
|
|
172
|
+
return new TextEncoder().encode(body).byteLength;
|
|
173
|
+
}
|
|
174
|
+
if (body instanceof Blob) {
|
|
175
|
+
return body.size;
|
|
176
|
+
}
|
|
177
|
+
if (body instanceof URLSearchParams) {
|
|
178
|
+
return new TextEncoder().encode(body.toString()).byteLength;
|
|
179
|
+
}
|
|
180
|
+
if (body instanceof ArrayBuffer) {
|
|
181
|
+
return body.byteLength;
|
|
182
|
+
}
|
|
183
|
+
if (ArrayBuffer.isView(body)) {
|
|
184
|
+
return body.byteLength;
|
|
185
|
+
}
|
|
186
|
+
throw new Error("Project upload fixtures require size when body length cannot be inferred");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function createProjectUploadBody(body: BodyInit | Uint8Array, contentType: string): BodyInit {
|
|
190
|
+
if (body instanceof Blob) {
|
|
191
|
+
return body;
|
|
192
|
+
}
|
|
193
|
+
if (typeof body === "string") {
|
|
194
|
+
return new Blob([body], { type: contentType });
|
|
195
|
+
}
|
|
196
|
+
if (body instanceof Uint8Array) {
|
|
197
|
+
return new Blob([body.slice()], { type: contentType });
|
|
198
|
+
}
|
|
199
|
+
return body;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function getResponseText(response: Response): Promise<string> {
|
|
203
|
+
return response.text();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async function wait(input: { ms: number }): Promise<void> {
|
|
207
|
+
await new Promise((resolve) => {
|
|
208
|
+
dntShim.setTimeout(resolve, input.ms);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function waitForProjectUploadFixture(
|
|
213
|
+
context: LiveEvalApiContext,
|
|
214
|
+
input: {
|
|
215
|
+
projectId: string;
|
|
216
|
+
filePath: string;
|
|
217
|
+
requestTimeoutMs: number;
|
|
218
|
+
pollIntervalMs?: number;
|
|
219
|
+
maxAttempts?: number;
|
|
220
|
+
},
|
|
221
|
+
): Promise<string> {
|
|
222
|
+
const listUrl = createApiUrl(context, `/projects/${input.projectId}/uploads`);
|
|
223
|
+
const requestFetch = createFetch(context);
|
|
224
|
+
const maxAttempts = input.maxAttempts ?? 12;
|
|
225
|
+
const pollIntervalMs = input.pollIntervalMs ?? 2_000;
|
|
226
|
+
|
|
227
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
228
|
+
const listResponse = await requestFetch(listUrl, {
|
|
229
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
230
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
if (!listResponse.ok) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`Failed to confirm project upload fixture: ${listResponse.status} ${await getResponseText(
|
|
236
|
+
listResponse,
|
|
237
|
+
)}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const payload = getProjectUploadListResponseSchema().parse(await listResponse.json());
|
|
242
|
+
if (payload.data?.some((upload) => upload.path === input.filePath)) {
|
|
243
|
+
return input.filePath;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (attempt + 1 < maxAttempts) {
|
|
247
|
+
await wait({ ms: pollIntervalMs });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
throw new Error(`Project upload fixture did not appear in time: ${input.filePath}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function createLiveEvalApiClient(context: LiveEvalApiContext): LiveEvalApiClient {
|
|
255
|
+
return {
|
|
256
|
+
createConversation: (input) => createLiveEvalConversation(context, input),
|
|
257
|
+
deleteConversation: (input) => deleteLiveEvalConversation(context, input),
|
|
258
|
+
createProjectUploadFixture: (input) => createLiveEvalProjectUploadFixture(context, input),
|
|
259
|
+
getProjectFile: (input) => getLiveEvalProjectFile(context, input),
|
|
260
|
+
createRelease: (input) => createLiveEvalRelease(context, input),
|
|
261
|
+
deleteProjectFile: (input) => deleteLiveEvalProjectFile(context, input),
|
|
262
|
+
listOpenInputRequests: (input) => listOpenLiveEvalInputRequests(context, input),
|
|
263
|
+
waitForOpenInputRequest: (input) => waitForOpenLiveEvalInputRequest(context, input),
|
|
264
|
+
submitInputResponse: (input) => submitLiveEvalInputResponse(context, input),
|
|
265
|
+
cancelInputRequest: (input) => cancelLiveEvalInputRequest(context, input),
|
|
266
|
+
} satisfies LiveEvalApiClient;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export async function createLiveEvalConversation(
|
|
270
|
+
context: LiveEvalApiContext,
|
|
271
|
+
input: LiveEvalCreateConversationInput,
|
|
272
|
+
): Promise<string> {
|
|
273
|
+
const response = await createFetch(context)(createApiUrl(context, "/conversations"), {
|
|
274
|
+
method: "POST",
|
|
275
|
+
headers: createLiveEvalJsonHeaders(context),
|
|
276
|
+
body: JSON.stringify({
|
|
277
|
+
...(context.projectId ? { project_id: context.projectId } : {}),
|
|
278
|
+
title: input.title,
|
|
279
|
+
}),
|
|
280
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
`Failed to create eval conversation: ${response.status} ${await getResponseText(response)}`,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const payload = getLiveEvalIdResponseSchema().parse(await response.json());
|
|
290
|
+
if (!payload.id) {
|
|
291
|
+
throw new Error("Conversation creation response did not include id");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return payload.id;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export async function deleteLiveEvalConversation(
|
|
298
|
+
context: LiveEvalApiContext,
|
|
299
|
+
input: LiveEvalConversationInput,
|
|
300
|
+
): Promise<void> {
|
|
301
|
+
const response = await createFetch(context)(
|
|
302
|
+
createApiUrl(context, `/conversations/${input.conversationId}`),
|
|
303
|
+
{
|
|
304
|
+
method: "DELETE",
|
|
305
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
306
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
307
|
+
},
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
if (!response.ok && response.status !== 404) {
|
|
311
|
+
throw new Error(
|
|
312
|
+
`Failed to delete eval conversation ${input.conversationId}: ${response.status} ${await getResponseText(
|
|
313
|
+
response,
|
|
314
|
+
)}`,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export async function createLiveEvalProjectUploadFixture(
|
|
320
|
+
context: LiveEvalApiContext,
|
|
321
|
+
input: LiveEvalProjectUploadFixtureInput,
|
|
322
|
+
): Promise<string> {
|
|
323
|
+
const projectId = requireLiveEvalProjectId(
|
|
324
|
+
context.projectId,
|
|
325
|
+
"Project upload fixtures require a live-eval project id",
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const createResponse = await createFetch(context)(
|
|
329
|
+
createApiUrl(context, `/projects/${projectId}/uploads`),
|
|
330
|
+
{
|
|
331
|
+
method: "POST",
|
|
332
|
+
headers: createLiveEvalJsonHeaders(context),
|
|
333
|
+
body: JSON.stringify({
|
|
334
|
+
file_path: input.filePath,
|
|
335
|
+
content_type: input.contentType,
|
|
336
|
+
size: getProjectUploadBodySize(input.body, input.size),
|
|
337
|
+
}),
|
|
338
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
339
|
+
},
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (!createResponse.ok) {
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Failed to create project upload URL: ${createResponse.status} ${await getResponseText(
|
|
345
|
+
createResponse,
|
|
346
|
+
)}`,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const createPayload = getProjectUploadResponseSchema().parse(await createResponse.json());
|
|
351
|
+
if (!createPayload.file_upload_url) {
|
|
352
|
+
throw new Error("Project upload response did not include file_upload_url");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const uploadResponse = await createFetch(context)(createPayload.file_upload_url, {
|
|
356
|
+
method: "PUT",
|
|
357
|
+
headers: createProjectUploadHeaders(createPayload.required_headers, input.contentType),
|
|
358
|
+
body: createProjectUploadBody(input.body, input.contentType),
|
|
359
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
if (!uploadResponse.ok) {
|
|
363
|
+
throw new Error(
|
|
364
|
+
`Failed to upload project fixture: ${uploadResponse.status} ${await getResponseText(
|
|
365
|
+
uploadResponse,
|
|
366
|
+
)}`,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return waitForProjectUploadFixture(context, {
|
|
371
|
+
projectId,
|
|
372
|
+
filePath: input.filePath,
|
|
373
|
+
requestTimeoutMs: input.requestTimeoutMs,
|
|
374
|
+
pollIntervalMs: input.pollIntervalMs,
|
|
375
|
+
maxAttempts: input.maxAttempts,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export async function getLiveEvalProjectFile(
|
|
380
|
+
context: LiveEvalApiContext,
|
|
381
|
+
input: LiveEvalProjectFileInput,
|
|
382
|
+
): Promise<LiveEvalProjectFile | null> {
|
|
383
|
+
const projectId = requireLiveEvalProjectId(
|
|
384
|
+
context.projectId,
|
|
385
|
+
"getLiveEvalProjectFile requires a live-eval project id",
|
|
386
|
+
);
|
|
387
|
+
const response = await createFetch(context)(
|
|
388
|
+
createApiUrl(context, `/projects/${projectId}/files/${encodeURIComponent(input.filePath)}`),
|
|
389
|
+
{
|
|
390
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
391
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
392
|
+
},
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
if (response.status === 404) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!response.ok) {
|
|
400
|
+
throw new Error(
|
|
401
|
+
`Failed to read project file: ${response.status} ${await getResponseText(response)}`,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const payload = getProjectFileResponseSchema().parse(await response.json());
|
|
406
|
+
return {
|
|
407
|
+
path: payload.path ?? input.filePath,
|
|
408
|
+
content: payload.content ?? "",
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export async function createLiveEvalRelease(
|
|
413
|
+
context: LiveEvalApiContext,
|
|
414
|
+
input: LiveEvalCreateReleaseInput,
|
|
415
|
+
): Promise<string> {
|
|
416
|
+
const projectId = requireLiveEvalProjectId(
|
|
417
|
+
context.projectId,
|
|
418
|
+
"createLiveEvalRelease requires a live-eval project id",
|
|
419
|
+
);
|
|
420
|
+
const response = await createFetch(context)(
|
|
421
|
+
createApiUrl(context, `/projects/${projectId}/releases`),
|
|
422
|
+
{
|
|
423
|
+
method: "POST",
|
|
424
|
+
headers: createLiveEvalJsonHeaders(context),
|
|
425
|
+
body: JSON.stringify({
|
|
426
|
+
description: input.description ?? "eval platform capability release",
|
|
427
|
+
}),
|
|
428
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
429
|
+
},
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
if (!response.ok) {
|
|
433
|
+
throw new Error(
|
|
434
|
+
`Failed to create release: ${response.status} ${await getResponseText(response)}`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const payload = getLiveEvalIdResponseSchema().parse(await response.json());
|
|
439
|
+
if (!payload.id) {
|
|
440
|
+
throw new Error("Release creation response did not include id");
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return payload.id;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export async function deleteLiveEvalProjectFile(
|
|
447
|
+
context: LiveEvalApiContext,
|
|
448
|
+
input: LiveEvalProjectFileInput,
|
|
449
|
+
): Promise<void> {
|
|
450
|
+
const projectId = context.projectId;
|
|
451
|
+
if (!projectId) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const response = await createFetch(context)(
|
|
456
|
+
createApiUrl(context, `/projects/${projectId}/files/${encodeURIComponent(input.filePath)}`),
|
|
457
|
+
{
|
|
458
|
+
method: "DELETE",
|
|
459
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
460
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
461
|
+
},
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
if (!response.ok && response.status !== 404) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Failed to delete project file: ${response.status} ${await getResponseText(response)}`,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export async function listOpenLiveEvalInputRequests(
|
|
472
|
+
context: LiveEvalApiContext,
|
|
473
|
+
input: LiveEvalConversationInput,
|
|
474
|
+
): Promise<LiveEvalInputRequestRecord[]> {
|
|
475
|
+
const response = await createFetch(context)(
|
|
476
|
+
createApiUrl(context, `/conversations/${input.conversationId}/input-requests?status=open`),
|
|
477
|
+
{
|
|
478
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
479
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
480
|
+
},
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
if (!response.ok) {
|
|
484
|
+
throw new Error(
|
|
485
|
+
`Failed to list eval input requests: ${response.status} ${await getResponseText(response)}`,
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const payload = getInputRequestListResponseSchema().parse(await response.json());
|
|
490
|
+
return (payload.data ?? []).flatMap((item) => {
|
|
491
|
+
const parsed = getInputRequestRecordSchema().safeParse(item);
|
|
492
|
+
return parsed.success ? [parsed.data] : [];
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export async function waitForOpenLiveEvalInputRequest(
|
|
497
|
+
context: LiveEvalApiContext,
|
|
498
|
+
input: LiveEvalWaitForOpenInputRequestInput,
|
|
499
|
+
): Promise<string> {
|
|
500
|
+
const timeoutMs = input.timeoutMs ?? 30_000;
|
|
501
|
+
const pollIntervalMs = input.pollIntervalMs ?? 500;
|
|
502
|
+
const deadline = Date.now() + timeoutMs;
|
|
503
|
+
|
|
504
|
+
while (Date.now() < deadline) {
|
|
505
|
+
if (input.abortSignal.aborted) {
|
|
506
|
+
throw new Error("Eval sidecar aborted before an input request appeared");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const requests = await listOpenLiveEvalInputRequests(context, input);
|
|
510
|
+
const request = requests[0];
|
|
511
|
+
if (request) {
|
|
512
|
+
return request.id;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
await wait({ ms: pollIntervalMs });
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
throw new Error(
|
|
519
|
+
`Timed out while waiting for an open input request in conversation ${input.conversationId}`,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export async function submitLiveEvalInputResponse(
|
|
524
|
+
context: LiveEvalApiContext,
|
|
525
|
+
input: LiveEvalSubmitInputResponseInput,
|
|
526
|
+
): Promise<void> {
|
|
527
|
+
const response = await createFetch(context)(
|
|
528
|
+
createApiUrl(
|
|
529
|
+
context,
|
|
530
|
+
`/conversations/${input.conversationId}/input-requests/${input.inputRequestId}/responses`,
|
|
531
|
+
),
|
|
532
|
+
{
|
|
533
|
+
method: "POST",
|
|
534
|
+
headers: createLiveEvalJsonHeaders(context),
|
|
535
|
+
body: JSON.stringify({ values: input.values }),
|
|
536
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
537
|
+
},
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
if (!response.ok) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
`Failed to submit eval input response: ${response.status} ${await getResponseText(response)}`,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export async function cancelLiveEvalInputRequest(
|
|
548
|
+
context: LiveEvalApiContext,
|
|
549
|
+
input: LiveEvalInputRequestInput,
|
|
550
|
+
): Promise<void> {
|
|
551
|
+
const response = await createFetch(context)(
|
|
552
|
+
createApiUrl(
|
|
553
|
+
context,
|
|
554
|
+
`/conversations/${input.conversationId}/input-requests/${input.inputRequestId}/cancel`,
|
|
555
|
+
),
|
|
556
|
+
{
|
|
557
|
+
method: "POST",
|
|
558
|
+
headers: createLiveEvalAuthHeaders(context),
|
|
559
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
560
|
+
},
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
if (!response.ok) {
|
|
564
|
+
throw new Error(
|
|
565
|
+
`Failed to cancel eval input request: ${response.status} ${await getResponseText(response)}`,
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
export {
|
|
2
|
+
cancelLiveEvalInputRequest,
|
|
3
|
+
createLiveEvalApiClient,
|
|
4
|
+
createLiveEvalConversation,
|
|
5
|
+
createLiveEvalProjectUploadFixture,
|
|
6
|
+
createLiveEvalRelease,
|
|
7
|
+
deleteLiveEvalConversation,
|
|
8
|
+
deleteLiveEvalProjectFile,
|
|
9
|
+
getLiveEvalProjectFile,
|
|
10
|
+
listOpenLiveEvalInputRequests,
|
|
11
|
+
type LiveEvalApiClient,
|
|
12
|
+
type LiveEvalApiContext,
|
|
13
|
+
type LiveEvalConversationInput,
|
|
14
|
+
type LiveEvalCreateConversationInput,
|
|
15
|
+
type LiveEvalCreateReleaseInput,
|
|
16
|
+
type LiveEvalInputRequestInput,
|
|
17
|
+
type LiveEvalInputRequestRecord,
|
|
18
|
+
type LiveEvalInputResponseValues,
|
|
19
|
+
type LiveEvalProjectFileInput,
|
|
20
|
+
type LiveEvalProjectUploadFixtureInput,
|
|
21
|
+
type LiveEvalRequestTimeoutInput,
|
|
22
|
+
type LiveEvalSubmitInputResponseInput,
|
|
23
|
+
type LiveEvalWaitForOpenInputRequestInput,
|
|
24
|
+
submitLiveEvalInputResponse,
|
|
25
|
+
waitForOpenLiveEvalInputRequest,
|
|
26
|
+
} from "./api-client.js";
|
|
1
27
|
export {
|
|
2
28
|
buildFailureSuffix,
|
|
3
29
|
buildProgressLine,
|