hivenet 0.6.0 → 0.7.1

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/dist/index.js CHANGED
@@ -31,11 +31,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  mod
32
32
  ));
33
33
 
34
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.26_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
34
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.30_typescript@5.9.3_yaml@2.9.1/node_modules/tsup/assets/esm_shims.js
35
35
  import path from "path";
36
36
  import { fileURLToPath } from "url";
37
37
  var init_esm_shims = __esm({
38
- "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.26_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
38
+ "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.30_typescript@5.9.3_yaml@2.9.1/node_modules/tsup/assets/esm_shims.js"() {
39
39
  "use strict";
40
40
  }
41
41
  });
@@ -15209,6 +15209,157 @@ function mediaTypeForFilename(filename) {
15209
15209
  const extension = /\.([^./\\]+)$/.exec(filename)?.[1]?.toLowerCase();
15210
15210
  return extension && MEDIA_TYPES[extension] || "application/octet-stream";
15211
15211
  }
15212
+ var evalCriterionIdSchema = external_exports.string().regex(
15213
+ /^[a-z][a-z0-9_]{0,47}$/,
15214
+ "Criterion ids are snake_case: a lowercase letter, then lowercase letters, digits or _ (at most 48)."
15215
+ );
15216
+ var weightSchema = external_exports.number().positive().max(100).optional();
15217
+ var evalJudgeCriterionSchema = external_exports.object({
15218
+ id: evalCriterionIdSchema,
15219
+ kind: external_exports.literal("judge"),
15220
+ description: external_exports.string().trim().min(1).max(2e3).describe("The yes/no question the judge answers about the result."),
15221
+ weight: weightSchema
15222
+ });
15223
+ var evalCommandCriterionSchema = external_exports.object({
15224
+ id: evalCriterionIdSchema,
15225
+ kind: external_exports.literal("command"),
15226
+ description: external_exports.string().trim().min(1).max(500).describe("What the check proves, for people reading results."),
15227
+ command: external_exports.string().trim().min(1).max(4e3),
15228
+ contains: external_exports.string().min(1).max(1e3).optional().describe("Stdout must contain this text."),
15229
+ regex: external_exports.string().min(1).max(500).optional().describe("Stdout must match this regex."),
15230
+ timeout_sec: external_exports.number().int().min(1).max(600).optional(),
15231
+ weight: weightSchema
15232
+ }).refine((criterion) => !(criterion.contains && criterion.regex), {
15233
+ message: "A command criterion takes contains or regex, not both."
15234
+ });
15235
+ var evalCriterionSchema = external_exports.discriminatedUnion("kind", [
15236
+ evalJudgeCriterionSchema,
15237
+ evalCommandCriterionSchema
15238
+ ]);
15239
+ var evalJudgeSchema = external_exports.object({
15240
+ model: external_exports.string().trim().min(1).max(128).default("anthropic/claude-sonnet-5"),
15241
+ /** Give the judge the agent's ATIF trajectory, e.g. to grade which tool or skill it used. */
15242
+ reads_trajectory: external_exports.boolean().default(false),
15243
+ /** Workspace files the judge reads, relative to the workdir. */
15244
+ files: external_exports.array(external_exports.string().trim().min(1).max(256)).max(20).default([])
15245
+ });
15246
+ var ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
15247
+ var SINGLE_LINE = /^[^\r\n]+$/;
15248
+ var evalMcpServerSchema = external_exports.object({
15249
+ name: external_exports.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/),
15250
+ transport: external_exports.enum(["stdio", "sse", "streamable-http"]),
15251
+ url: external_exports.url().max(2e3).optional(),
15252
+ command: external_exports.string().trim().min(1).max(500).optional(),
15253
+ args: external_exports.array(external_exports.string().max(500)).max(30).default([])
15254
+ });
15255
+ var evalEnvironmentSchema = external_exports.object({
15256
+ /** The base image, e.g. `node:22-slim`. */
15257
+ image: external_exports.string().trim().regex(/^[A-Za-z0-9][A-Za-z0-9._\-/:@]{0,255}$/, "image must be a Docker image reference."),
15258
+ /** Dockerfile RUN lines, cached in the image: toolchains, not the product under test. */
15259
+ build: external_exports.array(external_exports.string().trim().regex(SINGLE_LINE).max(2e3)).max(30).default([]),
15260
+ /**
15261
+ * Runs before every trial, so each one tests the current product. Harbor runs it as the
15262
+ * healthcheck and retries it on failure, so it must be safe to run twice.
15263
+ */
15264
+ setup: external_exports.object({
15265
+ command: external_exports.string().trim().min(1).max(8e3),
15266
+ timeout_sec: external_exports.number().int().min(10).max(3600).default(600)
15267
+ }).nullable().default(null),
15268
+ workdir: external_exports.string().regex(/^\/[A-Za-z0-9._\-/]{0,255}$/).default("/app"),
15269
+ network: external_exports.object({
15270
+ mode: external_exports.enum(["public", "allowlist", "no-network"]).default("public"),
15271
+ allowed_hosts: external_exports.array(external_exports.string().trim().min(1).max(253)).max(50).default([])
15272
+ }).prefault({}),
15273
+ /** Values reach setup and the agent; secret-like names take only `${VAR}` templates. */
15274
+ env: external_exports.record(external_exports.string().regex(ENV_NAME), external_exports.string().max(2e3)).default({}),
15275
+ mcp_servers: external_exports.array(evalMcpServerSchema).max(10).default([])
15276
+ });
15277
+ var evalAgentSchema = external_exports.object({
15278
+ timeout_sec: external_exports.number().int().min(30).max(7200).default(900)
15279
+ });
15280
+ var evalVersionFieldsSchema = external_exports.object({
15281
+ /** The task in the owner's words. Never the reporter's `actual` or `mistake`. */
15282
+ instruction: external_exports.string().trim().min(1).max(2e4),
15283
+ /** What "done" means, in one or two sentences. */
15284
+ end_goal: external_exports.string().trim().min(1).max(2e3).optional(),
15285
+ criteria: external_exports.array(evalCriterionSchema).min(1).max(30),
15286
+ judge: evalJudgeSchema.optional(),
15287
+ environment: evalEnvironmentSchema,
15288
+ agent: evalAgentSchema.prefault({}),
15289
+ /** A reference solution for Harbor's `oracle` agent, as a bash script. */
15290
+ solution: external_exports.string().trim().min(1).max(2e4).optional(),
15291
+ change_note: external_exports.string().trim().min(1).max(500).optional()
15292
+ });
15293
+ var evalVersionInputSchema = evalVersionFieldsSchema.refine(
15294
+ (input) => new Set(input.criteria.map((c) => c.id)).size === input.criteria.length,
15295
+ { message: "Criterion ids must be unique.", path: ["criteria"] }
15296
+ );
15297
+ var HARBOR_ID = external_exports.string().regex(/^[0-9a-f-]{36}$/i, "Harbor ids are UUIDs.");
15298
+ var boundedRecord = (max) => external_exports.record(external_exports.string().min(1).max(200), external_exports.number()).refine((record2) => Object.keys(record2).length <= max, `At most ${max} keys.`);
15299
+ var evalTrialScenarioSchema = external_exports.object({
15300
+ /** Folders the job mounted (`harbor run --mounts`), by name: the path stays on the machine. */
15301
+ mounts: external_exports.array(external_exports.string().min(1).max(200)).max(5).optional(),
15302
+ /** `--skill` */
15303
+ skills: external_exports.array(external_exports.string().min(1).max(200)).max(20).optional(),
15304
+ /** `--mcp-config` */
15305
+ mcp_servers: external_exports.array(external_exports.string().min(1).max(100)).max(20).optional(),
15306
+ /** `--extra-instruction` text, or the file `--extra-instruction-path` named. */
15307
+ instructions: external_exports.array(external_exports.string().min(1).max(500)).max(5).optional(),
15308
+ /** `--ak` and `--ae`, without secret-looking names. */
15309
+ agent_options: external_exports.record(external_exports.string().min(1).max(64), external_exports.string().max(200)).refine((record2) => Object.keys(record2).length <= 20, "At most 20 agent options.").optional()
15310
+ });
15311
+ var evalTrialCiSchema = external_exports.object({
15312
+ provider: external_exports.literal("github"),
15313
+ /** `owner/name` */
15314
+ repository: external_exports.string().min(1).max(200),
15315
+ /** The commit under test: a pull request's head, else the commit that triggered the run. */
15316
+ commit: external_exports.string().regex(/^[0-9a-f]{7,64}$/i).optional(),
15317
+ branch: external_exports.string().min(1).max(250).optional(),
15318
+ pull_request: external_exports.number().int().positive().optional(),
15319
+ /** What started the workflow: pull_request, push, schedule, workflow_dispatch… */
15320
+ event: external_exports.string().min(1).max(50).optional(),
15321
+ run_url: external_exports.url({ protocol: /^https?$/ }).max(500).optional()
15322
+ });
15323
+ var evalTrialUploadSchema = external_exports.object({
15324
+ harbor_trial_id: HARBOR_ID,
15325
+ harbor_job_id: HARBOR_ID,
15326
+ harbor_job_name: external_exports.string().max(200).optional(),
15327
+ /** Set on a regrade: the trial it derives from. */
15328
+ source_harbor_trial_id: HARBOR_ID.optional(),
15329
+ /** `[task].name` from the trial's result: `<project slug>/<eval id>` for Hivenet tasks. */
15330
+ task_name: external_exports.string().min(1).max(300),
15331
+ /** `task.digest` from the trial's lock.json. */
15332
+ task_digest: external_exports.string().regex(/^sha256:[0-9a-f]{64}$/),
15333
+ agent: external_exports.string().min(1).max(100),
15334
+ agent_version: external_exports.string().max(100).optional(),
15335
+ model: external_exports.string().max(200).optional(),
15336
+ /** The reasoning effort it ran at (`harbor run --ak reasoning_effort=…`): part of the lane. */
15337
+ effort: external_exports.string().min(1).max(40).optional(),
15338
+ harbor_version: external_exports.string().max(50).optional(),
15339
+ exception: external_exports.object({ type: external_exports.string().min(1).max(200), message: external_exports.string().max(2e3) }).optional(),
15340
+ /** reward.json. Absent when the verifier wrote nothing: the trial wasn't graded. */
15341
+ rewards: boundedRecord(32).optional(),
15342
+ /** reward-details.json leaves, keyed by criterion id. */
15343
+ criteria: boundedRecord(64).optional(),
15344
+ metrics: external_exports.object({
15345
+ input_tokens: external_exports.number().int().nonnegative(),
15346
+ output_tokens: external_exports.number().int().nonnegative(),
15347
+ cache_tokens: external_exports.number().int().nonnegative(),
15348
+ cost_usd: external_exports.number().nonnegative(),
15349
+ setup_sec: external_exports.number().nonnegative(),
15350
+ agent_sec: external_exports.number().nonnegative(),
15351
+ verifier_sec: external_exports.number().nonnegative()
15352
+ }).partial().optional(),
15353
+ started_at: external_exports.iso.datetime({ offset: true }).optional(),
15354
+ finished_at: external_exports.iso.datetime({ offset: true }).optional(),
15355
+ scenario: evalTrialScenarioSchema.optional(),
15356
+ ci: evalTrialCiSchema.optional()
15357
+ });
15358
+ var MAX_TRIALS_PER_PUSH = 200;
15359
+ var MAX_TRAJECTORY_BYTES = 8 * 1024 * 1024;
15360
+ var evalResultsUploadSchema = external_exports.object({
15361
+ trials: external_exports.array(evalTrialUploadSchema).min(1).max(MAX_TRIALS_PER_PUSH)
15362
+ });
15212
15363
  var PROTOCOL_VERSION = 1;
15213
15364
  var MAX_FEEDBACK_LENGTH = 5e3;
15214
15365
  var MAX_SUBJECT_LENGTH = 500;
@@ -15311,8 +15462,12 @@ var metadataSchema = external_exports.record(
15311
15462
  external_exports.string().min(1).max(40),
15312
15463
  external_exports.union([external_exports.string().max(200), external_exports.number().finite(), external_exports.boolean()])
15313
15464
  ).refine((value) => Object.keys(value).length <= 20, { message: "at most 20 metadata keys" });
15465
+ var threadSchema = external_exports.object({ id: external_exports.string().regex(THREAD_ID_PATTERN) });
15466
+ function newThreadId() {
15467
+ return crypto.randomUUID().replaceAll("-", "");
15468
+ }
15314
15469
  var feedbackEventSchema = external_exports.object({
15315
- v: external_exports.literal(PROTOCOL_VERSION),
15470
+ v: external_exports.literal(PROTOCOL_VERSION).default(PROTOCOL_VERSION),
15316
15471
  /** Tenant slug or domain this feedback is addressed to. Optional when the write key implies it. */
15317
15472
  to: external_exports.string().max(253).optional(),
15318
15473
  feedback: external_exports.string().min(1).max(MAX_FEEDBACK_LENGTH),
@@ -15320,7 +15475,7 @@ var feedbackEventSchema = external_exports.object({
15320
15475
  subject: external_exports.string().min(1).max(MAX_SUBJECT_LENGTH).optional(),
15321
15476
  sentiment: sentimentSchema.optional(),
15322
15477
  author: authorSchema.optional(),
15323
- thread: external_exports.object({ id: external_exports.string().regex(THREAD_ID_PATTERN) }),
15478
+ thread: threadSchema.optional().transform((thread) => thread ?? { id: newThreadId() }),
15324
15479
  eval: evalReportSchema.optional(),
15325
15480
  /** Id of an owner/system question this submission answers (from a prior response's `ask`). */
15326
15481
  question: external_exports.string().max(64).optional(),
@@ -15333,8 +15488,8 @@ var feedbackEventSchema = external_exports.object({
15333
15488
  client: external_exports.object({
15334
15489
  name: external_exports.string().max(64),
15335
15490
  version: external_exports.string().max(32)
15336
- }),
15337
- consent: external_exports.object({ telemetry: external_exports.boolean() })
15491
+ }).default({ name: "http", version: "0" }),
15492
+ consent: external_exports.object({ telemetry: external_exports.boolean() }).default({ telemetry: false })
15338
15493
  });
15339
15494
  var knownIssueSchema = external_exports.object({
15340
15495
  title: external_exports.string().max(120),
@@ -15426,7 +15581,7 @@ function validateIngestResponse(input) {
15426
15581
  return result.success ? { ok: true, data: result.data } : { ok: false, errors: formatIssues(result.error) };
15427
15582
  }
15428
15583
  function feedbackEventJsonSchema() {
15429
- return external_exports.toJSONSchema(feedbackEventSchema);
15584
+ return external_exports.toJSONSchema(feedbackEventSchema, { io: "input" });
15430
15585
  }
15431
15586
  function descriptorJsonSchema() {
15432
15587
  return external_exports.toJSONSchema(descriptorSchema);
@@ -16069,7 +16224,7 @@ function inferAuthor(context) {
16069
16224
  }
16070
16225
  var CONFIG_FILE_NAME = "feedback.config.json";
16071
16226
  var DESCRIPTOR_CACHE_TTL_MS = 60 * 60 * 1e3;
16072
- var RESOLVE_TIMEOUT_MS = 5e3;
16227
+ var RESOLVE_TIMEOUT_MS = 1e4;
16073
16228
  function parseDsn(dsn) {
16074
16229
  let url2;
16075
16230
  try {
@@ -16185,7 +16340,17 @@ function destinationFromDescriptor(descriptor, to) {
16185
16340
  };
16186
16341
  }
16187
16342
  function registryUrl(env = process.env) {
16188
- return env[REGISTRY_ENV_VAR]?.trim() || DEFAULT_REGISTRY_URL;
16343
+ const value = env[REGISTRY_ENV_VAR]?.trim() || DEFAULT_REGISTRY_URL;
16344
+ try {
16345
+ const url2 = new URL(value);
16346
+ if (!["http:", "https:"].includes(url2.protocol) || url2.username || url2.password || url2.search || url2.hash || url2.pathname !== "/" || !/^[a-z0-9._:[\]-]+$/i.test(url2.hostname))
16347
+ throw new Error("Not an origin");
16348
+ return url2.origin;
16349
+ } catch {
16350
+ throw new FeedbackError(
16351
+ "Registry must be an HTTP(S) origin, such as https://feedback.example.com, without credentials, a path, query or fragment."
16352
+ );
16353
+ }
16189
16354
  }
16190
16355
  async function resolveDestination(options = {}) {
16191
16356
  const env = options.env ?? process.env;
@@ -16194,6 +16359,19 @@ async function resolveDestination(options = {}) {
16194
16359
  if (options.dsn) {
16195
16360
  return parseDsn(options.dsn);
16196
16361
  }
16362
+ if (options.registry !== void 0) {
16363
+ const to2 = options.to?.trim();
16364
+ if (!options.registry.trim() || !to2 || to2.includes(".")) {
16365
+ throw new FeedbackError("Use --registry with --to <project-slug>, not a domain.");
16366
+ }
16367
+ const origin = registryUrl({ [REGISTRY_ENV_VAR]: options.registry });
16368
+ return resolveViaDescriptor(
16369
+ `${origin}/v1/registry/${encodeURIComponent(to2)}`,
16370
+ to2,
16371
+ fetchImpl,
16372
+ cacheDir
16373
+ );
16374
+ }
16197
16375
  const envDsn = env[DSN_ENV_VAR]?.trim();
16198
16376
  if (envDsn) {
16199
16377
  return parseDsn(envDsn);
@@ -16256,23 +16434,24 @@ async function postEvent(options) {
16256
16434
  body = void 0;
16257
16435
  }
16258
16436
  const parsed = validateIngestResponse(body);
16259
- return {
16260
- kind: "accepted",
16261
- response: parsed.ok ? parsed.data : { id: "unknown", thread: options.event.thread.id }
16262
- };
16437
+ return parsed.ok ? { kind: "accepted", response: parsed.data } : { kind: "unreachable", error: "Server returned an invalid delivery receipt." };
16263
16438
  }
16264
16439
  var OUTBOX_FILE = "outbox.jsonl";
16265
- var MAX_OUTBOX_ENTRIES = 100;
16440
+ var MAX_FLUSH_ENTRIES = 100;
16266
16441
  var STALE_CLAIM_MS = 30 * 60 * 1e3;
16267
16442
  function outboxPath(env = process.env) {
16268
16443
  return path5.join(feedbackHomeDir(env), OUTBOX_FILE);
16269
16444
  }
16270
16445
  function appendToOutbox(entry, env = process.env) {
16446
+ return appendEntriesToOutbox([entry], env);
16447
+ }
16448
+ function appendEntriesToOutbox(entries, env) {
16449
+ if (entries.length === 0) return true;
16271
16450
  try {
16272
16451
  const file2 = outboxPath(env);
16273
16452
  mkdirSync2(path5.dirname(file2), { recursive: true });
16274
- appendFileSync(file2, `${JSON.stringify(entry)}
16275
- `);
16453
+ appendFileSync(file2, entries.map((entry) => `${JSON.stringify(entry)}
16454
+ `).join(""));
16276
16455
  return true;
16277
16456
  } catch {
16278
16457
  return false;
@@ -16314,24 +16493,30 @@ function claimQueue(env) {
16314
16493
  async function flushOutbox(options = {}) {
16315
16494
  const env = options.env ?? process.env;
16316
16495
  const claims = claimQueue(env);
16317
- const entries = claims.flatMap(readEntries).slice(-MAX_OUTBOX_ENTRIES);
16496
+ const entries = claims.flatMap(readEntries);
16497
+ const deadline = Date.now() + (options.maxDurationMs ?? Number.POSITIVE_INFINITY);
16318
16498
  const failures = [];
16499
+ let attempted = 0;
16319
16500
  let delivered = 0;
16320
- for (const entry of entries) {
16501
+ for (const entry of entries.slice(0, MAX_FLUSH_ENTRIES)) {
16502
+ const timeLeft = deadline - Date.now();
16503
+ if (timeLeft <= 0) break;
16504
+ attempted++;
16321
16505
  const result = await postEvent({
16322
16506
  endpoint: entry.endpoint,
16323
16507
  ...entry.writeKey ? { writeKey: entry.writeKey } : {},
16324
16508
  event: entry.event,
16325
- timeoutMs: options.timeoutMs ?? 5e3,
16509
+ timeoutMs: Math.max(1, Math.floor(Math.min(options.timeoutMs ?? 5e3, timeLeft))),
16326
16510
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
16327
16511
  });
16328
- if (result.kind === "accepted" || result.kind === "rejected") {
16329
- delivered += result.kind === "accepted" ? 1 : 0;
16512
+ if (result.kind === "accepted") {
16513
+ delivered++;
16330
16514
  } else {
16331
16515
  failures.push(entry);
16332
16516
  }
16333
16517
  }
16334
- if (failures.every((entry) => appendToOutbox(entry, env))) {
16518
+ const remaining = entries.slice(attempted).concat(failures);
16519
+ if (appendEntriesToOutbox(remaining, env)) {
16335
16520
  for (const claim of claims) {
16336
16521
  try {
16337
16522
  rmSync(claim, { force: true });
@@ -16339,16 +16524,22 @@ async function flushOutbox(options = {}) {
16339
16524
  }
16340
16525
  }
16341
16526
  }
16342
- return { delivered, remaining: failures.length };
16527
+ return { delivered, remaining: remaining.length };
16343
16528
  }
16344
16529
  async function resolveApiOrigin(options) {
16345
- if (!options.to && !options.dsn) {
16346
- return new URL(DEFAULT_REGISTRY_URL).origin;
16530
+ const env = options.env ?? process.env;
16531
+ if (options.registry !== void 0 && !options.to && !options.dsn) {
16532
+ if (!options.registry.trim()) throw new FeedbackError("Registry must not be empty.");
16533
+ return registryUrl({ [REGISTRY_ENV_VAR]: options.registry });
16534
+ }
16535
+ if (!options.to && !options.dsn && !env[DSN_ENV_VAR]?.trim()) {
16536
+ return registryUrl(env);
16347
16537
  }
16348
16538
  const destination = await resolveDestination({
16349
16539
  ...options.to !== void 0 ? { to: options.to } : {},
16350
16540
  ...options.dsn !== void 0 ? { dsn: options.dsn } : {},
16351
- ...options.env ? { env: options.env } : {},
16541
+ ...options.registry !== void 0 ? { registry: options.registry } : {},
16542
+ env,
16352
16543
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
16353
16544
  });
16354
16545
  return new URL(destination.endpoint).origin;
@@ -16357,12 +16548,12 @@ function ownerApi(options) {
16357
16548
  const origin = (options.apiOrigin ?? new URL(DEFAULT_REGISTRY_URL).origin).replace(/\/$/, "");
16358
16549
  const fetchImpl = options.fetchImpl ?? fetch;
16359
16550
  const timeoutMs = options.timeoutMs ?? 15e3;
16360
- async function request(path6, init) {
16551
+ async function request(path6, init, timeout = timeoutMs) {
16361
16552
  let response;
16362
16553
  try {
16363
16554
  response = await fetchImpl(`${origin}${path6}`, {
16364
16555
  ...init,
16365
- signal: AbortSignal.timeout(timeoutMs),
16556
+ signal: AbortSignal.timeout(timeout),
16366
16557
  headers: {
16367
16558
  authorization: `Bearer ${options.secretKey}`,
16368
16559
  ...init?.body ? { "content-type": "application/json" } : {},
@@ -16495,6 +16686,33 @@ function ownerApi(options) {
16495
16686
  body: JSON.stringify({ status, ...note !== void 0 ? { note } : {} })
16496
16687
  });
16497
16688
  },
16689
+ /** Draft a runnable version of an eval (a person approves it in the dashboard). */
16690
+ async draftEvalVersion(id, fields) {
16691
+ return request(`/v1/evals/${encodeURIComponent(id)}/versions`, {
16692
+ method: "POST",
16693
+ body: JSON.stringify(fields)
16694
+ });
16695
+ },
16696
+ /** Compiled Harbor tasks: every accepted eval's current version, or the given refs. */
16697
+ async pullEvalTasks(refs = []) {
16698
+ const query = refs.map((ref) => `ref=${encodeURIComponent(ref)}`).join("&");
16699
+ return request(`/v1/evals/tasks${query ? `?${query}` : ""}`);
16700
+ },
16701
+ /** Harbor trials read from a job directory, with their grades. */
16702
+ async pushEvalResults(trials) {
16703
+ return request("/v1/evals/results", {
16704
+ method: "POST",
16705
+ body: JSON.stringify({ trials })
16706
+ });
16707
+ },
16708
+ /** A stored trial's ATIF trajectory (`agent/trajectory.json`), as read from disk. */
16709
+ async pushTrialTrajectory(harborTrialId, trajectory) {
16710
+ return request(
16711
+ `/v1/evals/trials/${encodeURIComponent(harborTrialId)}/trajectory`,
16712
+ { method: "PUT", body: trajectory },
16713
+ Math.max(timeoutMs, 6e4)
16714
+ );
16715
+ },
16498
16716
  /** Attach an external link (Slack message, Linear/GitHub issue, PR) to evt_… or iss_…. */
16499
16717
  async addLink(id, url2, label) {
16500
16718
  const path6 = id.startsWith("iss_") ? `/v1/issues/${id}` : `/v1/events/${id}`;
@@ -16534,6 +16752,7 @@ async function prepareFeedback(options) {
16534
16752
  const resolveOptions = {
16535
16753
  ...options.to !== void 0 ? { to: options.to } : {},
16536
16754
  ...options.dsn !== void 0 ? { dsn: options.dsn } : {},
16755
+ ...options.registry !== void 0 ? { registry: options.registry } : {},
16537
16756
  cwd,
16538
16757
  env,
16539
16758
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
@@ -16702,6 +16921,7 @@ export {
16702
16921
  resolveThreadId,
16703
16922
  sendFeedback,
16704
16923
  sentimentSchema,
16924
+ threadSchema,
16705
16925
  validateDescriptor,
16706
16926
  validateFeedbackEvent,
16707
16927
  validateIngestResponse