@foldrun/core 2.5.0 → 2.7.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/dist/src/agent-import.js +2 -2
- package/dist/src/agent-tools.js +2 -2
- package/dist/src/agents-md.d.ts +5 -1
- package/dist/src/agents-md.js +42 -18
- package/dist/src/capture.js +39 -1
- package/dist/src/completions.js +25 -3
- package/dist/src/deploy.js +72 -7
- package/dist/src/egress.d.ts +16 -0
- package/dist/src/evals.d.ts +22 -1
- package/dist/src/evals.js +43 -14
- package/dist/src/flow-lint.d.ts +14 -0
- package/dist/src/flow-lint.js +35 -0
- package/dist/src/flow-patterns.js +29 -14
- package/dist/src/frontmatter-fields.d.ts +27 -0
- package/dist/src/frontmatter-fields.js +51 -3
- package/dist/src/frontmatter-guard.d.ts +19 -0
- package/dist/src/frontmatter-guard.js +67 -0
- package/dist/src/frontmatter-schema.d.ts +2 -2
- package/dist/src/frontmatter-schema.js +30 -2
- package/dist/src/frontmatter-text.d.ts +31 -0
- package/dist/src/frontmatter-text.js +102 -0
- package/dist/src/judge-verdict.d.ts +19 -0
- package/dist/src/judge-verdict.js +54 -0
- package/dist/src/matter.d.ts +34 -0
- package/dist/src/matter.js +104 -0
- package/dist/src/network.d.ts +0 -1
- package/dist/src/network.js +10 -7
- package/dist/src/package.js +9 -2
- package/dist/src/provider-health.js +2 -2
- package/dist/src/run-container.d.ts +9 -0
- package/dist/src/run-container.js +34 -1
- package/dist/src/runner.js +193 -39
- package/dist/src/scan.d.ts +11 -0
- package/dist/src/scan.js +86 -8
- package/dist/src/secret-files.js +23 -2
- package/dist/src/secrets.d.ts +62 -2
- package/dist/src/secrets.js +206 -20
- package/dist/src/starter.js +23 -0
- package/dist/src/step-exec.d.ts +10 -2
- package/dist/src/step-exec.js +12 -9
- package/dist/src/store.d.ts +17 -3
- package/dist/src/store.js +14 -10
- package/package.json +1 -1
- package/src/agent-import.ts +2 -2
- package/src/agent-tools.ts +2 -2
- package/src/agents-md.ts +39 -14
- package/src/capture.ts +33 -1
- package/src/completions.ts +26 -3
- package/src/deploy.ts +59 -7
- package/src/egress.ts +15 -1
- package/src/evals.ts +45 -13
- package/src/flow-lint.ts +36 -0
- package/src/flow-patterns.ts +26 -13
- package/src/frontmatter-fields.ts +74 -3
- package/src/frontmatter-guard.ts +70 -0
- package/src/frontmatter-schema.ts +30 -4
- package/src/frontmatter-text.ts +109 -0
- package/src/judge-verdict.ts +52 -0
- package/src/matter.ts +112 -0
- package/src/network.ts +10 -6
- package/src/package.ts +8 -2
- package/src/provider-health.ts +2 -2
- package/src/run-container.ts +41 -1
- package/src/runner.ts +189 -40
- package/src/scan.ts +86 -8
- package/src/secret-files.ts +22 -2
- package/src/secrets.ts +237 -23
- package/src/starter.ts +23 -0
- package/src/step-exec.ts +21 -8
- package/src/store.ts +23 -10
package/src/step-exec.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// results. That is what lets the same function run somewhere the vault, the
|
|
9
9
|
// library and the account do not exist.
|
|
10
10
|
|
|
11
|
+
import { judgeVerdict, JUDGE_VERDICT_INSTRUCTION } from "./judge-verdict.ts";
|
|
11
12
|
import { runHook, runToolCallHooks, matchesTool, hookLine, resolveHooks, type HookDef, type HookRecord } from "./hooks.ts";
|
|
12
13
|
import fs from "node:fs";
|
|
13
14
|
import os from "node:os";
|
|
@@ -133,6 +134,11 @@ export interface ExecOptions {
|
|
|
133
134
|
* `matches: re`, `file: path`, `judge: sentence`) — see checkVerify. */
|
|
134
135
|
verify?: string;
|
|
135
136
|
verifyEnv?: Record<string, string>;
|
|
137
|
+
/** The model `verify: judge:` grades with — the workspace's `judge:` from
|
|
138
|
+
* AGENTS.md, resolved; absent, the fast tier. */
|
|
139
|
+
judgeModel?: string;
|
|
140
|
+
/** And how long it thinks — `judge: {effort}`; absent, the SDK's default. */
|
|
141
|
+
judgeEffort?: Effort;
|
|
136
142
|
/** `output: json` — the reply must carry one JSON value; extracting it is
|
|
137
143
|
* part of finishing the step, and failing to is failing the step. */
|
|
138
144
|
output?: "json";
|
|
@@ -1066,6 +1072,8 @@ async function executeStepInner(opts: ExecOptions, runQuery: QueryFn): Promise<E
|
|
|
1066
1072
|
data,
|
|
1067
1073
|
modelEnv: opts.env,
|
|
1068
1074
|
signal: halt.signal,
|
|
1075
|
+
...(opts.judgeModel ? { judgeModel: opts.judgeModel } : {}),
|
|
1076
|
+
...(opts.judgeEffort ? { judgeEffort: opts.judgeEffort } : {}),
|
|
1069
1077
|
});
|
|
1070
1078
|
} finally {
|
|
1071
1079
|
for (const t of clocks) clearTimeout(t);
|
|
@@ -1170,6 +1178,9 @@ export async function checkVerify(
|
|
|
1170
1178
|
/** The step's own model environment, for `judge:` — it grades on the
|
|
1171
1179
|
* fast tier through the same credential the step rode. */
|
|
1172
1180
|
modelEnv?: Record<string, string | undefined>;
|
|
1181
|
+
/** The judge's model and effort (the workspace's `judge:`). */
|
|
1182
|
+
judgeModel?: string;
|
|
1183
|
+
judgeEffort?: Effort;
|
|
1173
1184
|
/** Ends a shell check or a judge mid-way: the step's clock ran out, or a
|
|
1174
1185
|
* person asked the run to stop. */
|
|
1175
1186
|
signal?: AbortSignal;
|
|
@@ -1233,9 +1244,9 @@ export async function checkVerify(
|
|
|
1233
1244
|
// GOOD` on a reply that did (fix-desk, run-muwevg72-7mza): the joined
|
|
1234
1245
|
// text opened with the narration before it.
|
|
1235
1246
|
const reply = ctx.conclusion?.trim() ? ctx.conclusion : output;
|
|
1236
|
-
const
|
|
1237
|
-
const ok =
|
|
1238
|
-
return { ok, headline: ok ? "PASS" : "FAIL", detail
|
|
1247
|
+
const said = await judgeReply(value, reply, output, ctx.modelEnv ?? {}, ctx.signal, ctx.judgeModel, ctx.judgeEffort);
|
|
1248
|
+
const { passed: ok, detail } = judgeVerdict(said);
|
|
1249
|
+
return { ok, headline: ok ? "PASS" : "FAIL", detail };
|
|
1239
1250
|
}
|
|
1240
1251
|
}
|
|
1241
1252
|
return { ok: false, headline: `unknown check "${kind}"`, detail: "" };
|
|
@@ -1243,8 +1254,8 @@ export async function checkVerify(
|
|
|
1243
1254
|
|
|
1244
1255
|
/**
|
|
1245
1256
|
* A toolless, fast-tier grading call: does the reply satisfy the sentence?
|
|
1246
|
-
* Same shape as the eval judge
|
|
1247
|
-
*
|
|
1257
|
+
* Same shape as the eval judge: reasoning first, then the verdict alone on
|
|
1258
|
+
* the last line (judge-verdict.ts says why).
|
|
1248
1259
|
*/
|
|
1249
1260
|
export function judgePrompt(rubric: string, reply: string, work: string): string {
|
|
1250
1261
|
const shown = reply.slice(0, 20_000);
|
|
@@ -1253,8 +1264,7 @@ export function judgePrompt(rubric: string, reply: string, work: string): string
|
|
|
1253
1264
|
`never this:\n<work>\n${work.slice(-20_000)}\n</work>\n\n`
|
|
1254
1265
|
: "";
|
|
1255
1266
|
return (
|
|
1256
|
-
`You are grading a reply against one requirement.
|
|
1257
|
-
`first word, then one sentence of reason.\n\nRequirement: ${rubric}\n\n` +
|
|
1267
|
+
`You are grading a reply against one requirement. ${JUDGE_VERDICT_INSTRUCTION}\n\nRequirement: ${rubric}\n\n` +
|
|
1258
1268
|
context +
|
|
1259
1269
|
`<reply>\n${shown}\n</reply>`
|
|
1260
1270
|
);
|
|
@@ -1266,6 +1276,8 @@ async function judgeReply(
|
|
|
1266
1276
|
work: string,
|
|
1267
1277
|
env: Record<string, string | undefined>,
|
|
1268
1278
|
signal?: AbortSignal,
|
|
1279
|
+
model = "haiku",
|
|
1280
|
+
effort?: Effort,
|
|
1269
1281
|
): Promise<string> {
|
|
1270
1282
|
const texts: string[] = [];
|
|
1271
1283
|
const abortController = new AbortController();
|
|
@@ -1275,7 +1287,8 @@ async function judgeReply(
|
|
|
1275
1287
|
const q = query({
|
|
1276
1288
|
prompt: judgePrompt(rubric, reply, work),
|
|
1277
1289
|
options: {
|
|
1278
|
-
model
|
|
1290
|
+
model,
|
|
1291
|
+
...(effort ? { effort } : {}),
|
|
1279
1292
|
systemPrompt: "You grade text against a stated requirement. Be strict and literal.",
|
|
1280
1293
|
tools: [],
|
|
1281
1294
|
settingSources: [],
|
package/src/store.ts
CHANGED
|
@@ -31,7 +31,7 @@ import { platform } from "./platform.ts";
|
|
|
31
31
|
import { toLF, asRaw } from "./eol.ts";
|
|
32
32
|
import type { TestEffect } from "./test-mode.ts";
|
|
33
33
|
import type { OperatorEvent } from "./operator.ts";
|
|
34
|
-
import matter from "./matter.ts";
|
|
34
|
+
import matter, { frontmatterErrorText, configMatter } from "./matter.ts";
|
|
35
35
|
import { readAgentsMdKeys } from "./agents-md.ts";
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -44,7 +44,7 @@ import { readAgentsMdKeys } from "./agents-md.ts";
|
|
|
44
44
|
* the runtime, and there is nothing to fail to import.
|
|
45
45
|
*/
|
|
46
46
|
export function readFrontmatter(file: string): Record<string, unknown> {
|
|
47
|
-
return
|
|
47
|
+
return configMatter(fs.readFileSync(file, "utf8")).data as Record<string, unknown>;
|
|
48
48
|
}
|
|
49
49
|
import { ownToolNames, legacyUseNames, retiredToolNames } from "./tool-names.ts";
|
|
50
50
|
import { refNames } from "./refs.ts";
|
|
@@ -1602,7 +1602,7 @@ export function listAgents(tenant: string, workspace: string): AgentInfo[] {
|
|
|
1602
1602
|
let data: Record<string, any> = {};
|
|
1603
1603
|
let frontmatterError: string | undefined;
|
|
1604
1604
|
try {
|
|
1605
|
-
({ data } =
|
|
1605
|
+
({ data } = configMatter(fs.readFileSync(path.join(dir, name, "agent.md"), "utf8")));
|
|
1606
1606
|
} catch (err) {
|
|
1607
1607
|
frontmatterError = frontmatterErrorText(err);
|
|
1608
1608
|
}
|
|
@@ -1652,12 +1652,9 @@ export function listAgents(tenant: string, workspace: string): AgentInfo[] {
|
|
|
1652
1652
|
});
|
|
1653
1653
|
}
|
|
1654
1654
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
export
|
|
1658
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1659
|
-
return `frontmatter does not parse — ${msg.split("\n")[0].trim()}. Quote a value that contains a colon followed by a space.`;
|
|
1660
|
-
}
|
|
1655
|
+
// Kept here for callers that import it from the store; it lives in matter.ts
|
|
1656
|
+
// so the scanner can use it without the store.
|
|
1657
|
+
export { frontmatterErrorText };
|
|
1661
1658
|
|
|
1662
1659
|
/** The body of a file whose frontmatter would not parse: what follows the
|
|
1663
1660
|
* closing fence, so a flow's steps can still be read and shown. */
|
|
@@ -1839,7 +1836,7 @@ export function parseFlow(file: string, raw: string): FlowInfo {
|
|
|
1839
1836
|
let content: string;
|
|
1840
1837
|
let frontError: string | null = null;
|
|
1841
1838
|
try {
|
|
1842
|
-
({ data, content } =
|
|
1839
|
+
({ data, content } = configMatter(raw));
|
|
1843
1840
|
} catch (err) {
|
|
1844
1841
|
frontError = frontmatterErrorText(err);
|
|
1845
1842
|
content = bodyAfterFrontmatter(raw);
|
|
@@ -3297,6 +3294,15 @@ export function sumAttempts(tries: StepAttempt[]): Pick<StepAttempt, "costUsd" |
|
|
|
3297
3294
|
export { type TokenUsage, type PromptLayerRecord, tokensOf, sumTokens, cacheHitRate, measuredHitRate, runTokens, promptLayersChanged, promptCacheNote } from "./tokens.ts";
|
|
3298
3295
|
import { sumTokens, type TokenUsage, type PromptLayerRecord } from "./tokens.ts";
|
|
3299
3296
|
|
|
3297
|
+
/** The marker rescueStep puts in a rescue's instruction; how a rescue record
|
|
3298
|
+
* written before `rescueOf` existed is still recognised. */
|
|
3299
|
+
export const RESCUE_MARKER = "<rescue>\nYou are taking this step over:";
|
|
3300
|
+
|
|
3301
|
+
/** Is this record an on-fail rescue rather than a step of the flow? */
|
|
3302
|
+
export function isRescueRecord(step: { rescueOf?: string; instruction?: string | null }): boolean {
|
|
3303
|
+
return !!step.rescueOf || (step.instruction ?? "").includes(RESCUE_MARKER);
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3300
3306
|
export interface StepRecord {
|
|
3301
3307
|
agent: string;
|
|
3302
3308
|
instruction: string;
|
|
@@ -3450,6 +3456,13 @@ export interface StepRecord {
|
|
|
3450
3456
|
* actually executed in. Carried steps provide context and are never
|
|
3451
3457
|
* billed again — the original run's ledger line already paid for them. */
|
|
3452
3458
|
carriedFrom?: string;
|
|
3459
|
+
/** Set on an on-fail rescue record (runner.ts rescueStep): the agent of the
|
|
3460
|
+
* failed step it took over. A rescue is not a step of the flow: a resumed
|
|
3461
|
+
* drive must not launch it as one of its group, and a re-run must not
|
|
3462
|
+
* copy it as work (21 Oct 2026: one rerun carried 77 fixers as pending
|
|
3463
|
+
* steps). Records written before this field are recognised by their
|
|
3464
|
+
* instruction's `<rescue>` block instead — see isRescueRecord. */
|
|
3465
|
+
rescueOf?: string;
|
|
3453
3466
|
/**
|
|
3454
3467
|
* Sandbox seconds this step rented, and how many of them were cold start.
|
|
3455
3468
|
* Set only on the isolated path — an in-process step rents nothing, so
|