@foldrun/core 11.1.0 → 11.2.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.
@@ -164,6 +164,15 @@ export interface EvalResult {
164
164
  /** How long one judge may take before it is cut off: a verdict on one
165
165
  * sentence is seconds; a stalled model must not hold a grade pass. */
166
166
  export declare const JUDGE_TIMEOUT_MS = 120000;
167
+ /**
168
+ * The environment a judge's model process starts with: the host's PATH, HOME
169
+ * and temp folder under the model's own variables. An account's provider env
170
+ * is only its URL, key and models, and a CLI started with no HOME dies on
171
+ * uv_os_homedir in a pod whose user has no passwd entry (FOL-107). Never the
172
+ * host's secrets: hostSafeEnv is an allowlist, as for drafts and the
173
+ * assistant's tool loop.
174
+ */
175
+ export declare function judgeSdkEnv(env: Record<string, string | undefined>): Record<string, string | undefined>;
167
176
  /** One judge call: its words and what it cost (the SDK's result line). */
168
177
  export declare function judgeCall(rubric: string, output: string, model: string, effort: Effort | null, env: Record<string, string | undefined>,
169
178
  /** What the output was an answer to — a live run's task, so the judge
package/dist/src/evals.js CHANGED
@@ -31,7 +31,7 @@
31
31
  // they pass — no point paying a model to grade output already known to be
32
32
  // wrong.
33
33
  import { accountModelEnv, withModelEnv, ModelKeyError } from "./model-env.js";
34
- import { sdkEnv } from "./step-exec.js";
34
+ import { sdkEnv, modelProcessError } from "./step-exec.js";
35
35
  import { platformModelEnv } from "./runner.js";
36
36
  import fs from "node:fs";
37
37
  import crypto from "node:crypto";
@@ -467,6 +467,17 @@ function shell(command, cwd) {
467
467
  /** How long one judge may take before it is cut off: a verdict on one
468
468
  * sentence is seconds; a stalled model must not hold a grade pass. */
469
469
  export const JUDGE_TIMEOUT_MS = 120_000;
470
+ /**
471
+ * The environment a judge's model process starts with: the host's PATH, HOME
472
+ * and temp folder under the model's own variables. An account's provider env
473
+ * is only its URL, key and models, and a CLI started with no HOME dies on
474
+ * uv_os_homedir in a pod whose user has no passwd entry (FOL-107). Never the
475
+ * host's secrets: hostSafeEnv is an allowlist, as for drafts and the
476
+ * assistant's tool loop.
477
+ */
478
+ export function judgeSdkEnv(env) {
479
+ return { ...hostSafeEnv(), ...env };
480
+ }
470
481
  /** One judge call: its words and what it cost (the SDK's result line). */
471
482
  export async function judgeCall(rubric, output, model, effort, env,
472
483
  /** What the output was an answer to — a live run's task, so the judge
@@ -491,7 +502,7 @@ context) {
491
502
  allowedTools: [],
492
503
  settingSources: [],
493
504
  strictMcpConfig: true,
494
- env,
505
+ env: judgeSdkEnv(env),
495
506
  maxTurns: 1,
496
507
  abortController: abort,
497
508
  },
@@ -511,7 +522,7 @@ context) {
511
522
  catch (err) {
512
523
  if (abort.signal.aborted)
513
524
  throw new Error(`the judge took longer than ${JUDGE_TIMEOUT_MS / 1000}s and was stopped`);
514
- throw err;
525
+ throw modelProcessError(err, "judge");
515
526
  }
516
527
  finally {
517
528
  clearTimeout(timer);
@@ -332,6 +332,14 @@ export declare function judgePrompt(rubric: string, reply: string, work: string)
332
332
  * "the only tools I have are the Claude Docs ones". `strictMcpConfig` keeps
333
333
  * the rest of the on-disk MCP configuration out; this keeps the account's.
334
334
  */
335
+ /**
336
+ * A model process's failure as a person should read it: one short line. The
337
+ * SDK's error for a CLI that died carries the CLI's stderr, which can be KBs
338
+ * of its minified bundle — internal prompt text included (FOL-107) — so that
339
+ * part goes to the server log, never to an eval result or a trace. An error
340
+ * that is already short (an API error the model answered) is kept as it is.
341
+ */
342
+ export declare function modelProcessError(err: unknown, where: string): Error;
335
343
  export declare function sdkEnv(base: Record<string, string | undefined> | undefined, extra?: Record<string, string>): Record<string, string | undefined>;
336
344
  /** The text of a tool result, whichever shape it came in: a string, or a
337
345
  * list of content blocks of which only the text ones say anything. */
@@ -1101,7 +1101,7 @@ async function judgeReply(rubric, reply, work, env, signal, model = "haiku", eff
1101
1101
  }
1102
1102
  }
1103
1103
  catch (err) {
1104
- return `FAIL — the judge could not run: ${err instanceof Error ? err.message : String(err)}`;
1104
+ return `FAIL — the judge could not run: ${modelProcessError(err, "verify judge").message}`;
1105
1105
  }
1106
1106
  return texts.join("\n").trim();
1107
1107
  }
@@ -1167,6 +1167,22 @@ function runVerify(agentDir, command, env, data, signal) {
1167
1167
  * "the only tools I have are the Claude Docs ones". `strictMcpConfig` keeps
1168
1168
  * the rest of the on-disk MCP configuration out; this keeps the account's.
1169
1169
  */
1170
+ /**
1171
+ * A model process's failure as a person should read it: one short line. The
1172
+ * SDK's error for a CLI that died carries the CLI's stderr, which can be KBs
1173
+ * of its minified bundle — internal prompt text included (FOL-107) — so that
1174
+ * part goes to the server log, never to an eval result or a trace. An error
1175
+ * that is already short (an API error the model answered) is kept as it is.
1176
+ */
1177
+ export function modelProcessError(err, where) {
1178
+ const full = err instanceof Error ? err.message : String(err);
1179
+ const at = full.indexOf(" stderr:");
1180
+ if (at < 0 && full.length <= 500)
1181
+ return err instanceof Error ? err : new Error(full);
1182
+ console.error(`[foldrun] ${where}: ${full}`);
1183
+ const head = (at >= 0 ? full.slice(0, at) : full.slice(0, 300)).trim().replace(/[.:]$/, "");
1184
+ return new Error(`${head} — the model process failed; the details are in the server log`);
1185
+ }
1170
1186
  export function sdkEnv(base, extra = {}) {
1171
1187
  return { ...(base ?? process.env), ...extra, ENABLE_CLAUDEAI_MCP_SERVERS: "false" };
1172
1188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldrun/core",
3
- "version": "11.1.0",
3
+ "version": "11.2.1",
4
4
  "description": "Agents are just folders. The format, the runner, the checks.",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",
package/src/evals.ts CHANGED
@@ -33,7 +33,7 @@
33
33
 
34
34
  import { accountModelEnv, withModelEnv, ModelKeyError } from "./model-env.ts";
35
35
  import type { TranslatorSpec } from "./translator.ts";
36
- import { sdkEnv } from "./step-exec.ts";
36
+ import { sdkEnv, modelProcessError } from "./step-exec.ts";
37
37
  import { platformModelEnv } from "./runner.ts";
38
38
  import fs from "node:fs";
39
39
  import crypto from "node:crypto";
@@ -621,6 +621,18 @@ function shell(command: string, cwd: string): Promise<{ code: number | null; out
621
621
  * sentence is seconds; a stalled model must not hold a grade pass. */
622
622
  export const JUDGE_TIMEOUT_MS = 120_000;
623
623
 
624
+ /**
625
+ * The environment a judge's model process starts with: the host's PATH, HOME
626
+ * and temp folder under the model's own variables. An account's provider env
627
+ * is only its URL, key and models, and a CLI started with no HOME dies on
628
+ * uv_os_homedir in a pod whose user has no passwd entry (FOL-107). Never the
629
+ * host's secrets: hostSafeEnv is an allowlist, as for drafts and the
630
+ * assistant's tool loop.
631
+ */
632
+ export function judgeSdkEnv(env: Record<string, string | undefined>): Record<string, string | undefined> {
633
+ return { ...hostSafeEnv(), ...env };
634
+ }
635
+
624
636
  /** One judge call: its words and what it cost (the SDK's result line). */
625
637
  export async function judgeCall(
626
638
  rubric: string,
@@ -653,7 +665,7 @@ export async function judgeCall(
653
665
  allowedTools: [],
654
666
  settingSources: [],
655
667
  strictMcpConfig: true,
656
- env,
668
+ env: judgeSdkEnv(env),
657
669
  maxTurns: 1,
658
670
  abortController: abort,
659
671
  },
@@ -669,7 +681,7 @@ export async function judgeCall(
669
681
  }
670
682
  } catch (err) {
671
683
  if (abort.signal.aborted) throw new Error(`the judge took longer than ${JUDGE_TIMEOUT_MS / 1000}s and was stopped`);
672
- throw err;
684
+ throw modelProcessError(err, "judge");
673
685
  } finally {
674
686
  clearTimeout(timer);
675
687
  }
package/src/step-exec.ts CHANGED
@@ -1309,7 +1309,7 @@ async function judgeReply(
1309
1309
  }
1310
1310
  }
1311
1311
  } catch (err) {
1312
- return `FAIL — the judge could not run: ${err instanceof Error ? err.message : String(err)}`;
1312
+ return `FAIL — the judge could not run: ${modelProcessError(err, "verify judge").message}`;
1313
1313
  }
1314
1314
  return texts.join("\n").trim();
1315
1315
  }
@@ -1377,6 +1377,22 @@ function runVerify(
1377
1377
  * "the only tools I have are the Claude Docs ones". `strictMcpConfig` keeps
1378
1378
  * the rest of the on-disk MCP configuration out; this keeps the account's.
1379
1379
  */
1380
+ /**
1381
+ * A model process's failure as a person should read it: one short line. The
1382
+ * SDK's error for a CLI that died carries the CLI's stderr, which can be KBs
1383
+ * of its minified bundle — internal prompt text included (FOL-107) — so that
1384
+ * part goes to the server log, never to an eval result or a trace. An error
1385
+ * that is already short (an API error the model answered) is kept as it is.
1386
+ */
1387
+ export function modelProcessError(err: unknown, where: string): Error {
1388
+ const full = err instanceof Error ? err.message : String(err);
1389
+ const at = full.indexOf(" stderr:");
1390
+ if (at < 0 && full.length <= 500) return err instanceof Error ? err : new Error(full);
1391
+ console.error(`[foldrun] ${where}: ${full}`);
1392
+ const head = (at >= 0 ? full.slice(0, at) : full.slice(0, 300)).trim().replace(/[.:]$/, "");
1393
+ return new Error(`${head} — the model process failed; the details are in the server log`);
1394
+ }
1395
+
1380
1396
  export function sdkEnv(base: Record<string, string | undefined> | undefined, extra: Record<string, string> = {}): Record<string, string | undefined> {
1381
1397
  return { ...(base ?? process.env), ...extra, ENABLE_CLAUDEAI_MCP_SERVERS: "false" };
1382
1398
  }