@foldrun/core 2.3.0 → 2.5.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-activity.d.ts +5 -0
- package/dist/src/agent-activity.js +31 -0
- package/dist/src/agent-import.js +1 -1
- package/dist/src/agent-tools.js +1 -1
- package/dist/src/agents-md.js +1 -1
- package/dist/src/alerts.d.ts +60 -0
- package/dist/src/alerts.js +161 -0
- package/dist/src/browser-pod.js +4 -0
- package/dist/src/capture.d.ts +23 -0
- package/dist/src/capture.js +80 -0
- package/dist/src/compare.d.ts +57 -0
- package/dist/src/compare.js +116 -0
- package/dist/src/completions.js +1 -0
- package/dist/src/deploy.d.ts +36 -1
- package/dist/src/deploy.js +170 -11
- package/dist/src/egress.d.ts +16 -1
- package/dist/src/evals.d.ts +5 -1
- package/dist/src/evals.js +26 -18
- package/dist/src/frontmatter-fields.js +9 -0
- package/dist/src/frontmatter-schema.js +3 -0
- package/dist/src/history.d.ts +4 -0
- package/dist/src/history.js +15 -0
- package/dist/src/hooks.js +1 -1
- package/dist/src/insights.d.ts +30 -0
- package/dist/src/insights.js +152 -0
- package/dist/src/issues.d.ts +140 -0
- package/dist/src/issues.js +302 -0
- package/dist/src/library.js +1 -1
- package/dist/src/limits.d.ts +8 -0
- package/dist/src/limits.js +36 -5
- package/dist/src/linkable.js +1 -1
- package/dist/src/matter.d.ts +8 -0
- package/dist/src/matter.js +28 -0
- package/dist/src/model-credential.d.ts +14 -0
- package/dist/src/model-credential.js +40 -0
- package/dist/src/model-env.d.ts +14 -2
- package/dist/src/model-env.js +34 -9
- package/dist/src/network.d.ts +12 -0
- package/dist/src/network.js +25 -1
- package/dist/src/notify.d.ts +16 -0
- package/dist/src/notify.js +17 -7
- package/dist/src/okf.js +1 -1
- package/dist/src/online-checks.d.ts +76 -0
- package/dist/src/online-checks.js +432 -0
- package/dist/src/operator.d.ts +277 -0
- package/dist/src/operator.js +176 -2
- package/dist/src/otel-config.d.ts +18 -0
- package/dist/src/otel-config.js +69 -0
- package/dist/src/otel.d.ts +38 -0
- package/dist/src/otel.js +85 -0
- package/dist/src/outcome.d.ts +40 -0
- package/dist/src/outcome.js +77 -0
- package/dist/src/package.js +1 -1
- package/dist/src/platform.d.ts +1 -1
- package/dist/src/prompt-layers.d.ts +30 -0
- package/dist/src/prompt-layers.js +77 -0
- package/dist/src/provider-health.js +1 -1
- package/dist/src/providers.d.ts +5 -0
- package/dist/src/providers.js +2 -2
- package/dist/src/run-container.d.ts +16 -2
- package/dist/src/run-container.js +57 -5
- package/dist/src/runner.d.ts +53 -2
- package/dist/src/runner.js +356 -70
- package/dist/src/runs-filter.d.ts +48 -0
- package/dist/src/runs-filter.js +73 -0
- package/dist/src/scan.d.ts +19 -1
- package/dist/src/scan.js +60 -7
- package/dist/src/starter.js +4 -2
- package/dist/src/step-exec.d.ts +29 -1
- package/dist/src/step-exec.js +106 -6
- package/dist/src/store.d.ts +130 -3
- package/dist/src/store.js +145 -6
- package/dist/src/tokens.d.ts +38 -0
- package/dist/src/tokens.js +57 -0
- package/dist/src/tool-names.js +1 -1
- package/dist/src/tool-programs.js +1 -1
- package/dist/src/trace-tree.d.ts +40 -0
- package/dist/src/trace-tree.js +156 -0
- package/dist/src/translator.d.ts +8 -0
- package/dist/src/translator.js +7 -2
- package/dist/src/trigger-log.d.ts +1 -1
- package/dist/src/workspace-check.d.ts +18 -0
- package/dist/src/workspace-check.js +34 -0
- package/package.json +2 -2
- package/src/agent-activity.ts +32 -0
- package/src/agent-import.ts +1 -1
- package/src/agent-tools.ts +1 -1
- package/src/agents-md.ts +1 -1
- package/src/alerts.ts +190 -0
- package/src/browser-pod.ts +3 -0
- package/src/capture.ts +88 -0
- package/src/compare.ts +146 -0
- package/src/completions.ts +1 -0
- package/src/deploy.ts +184 -10
- package/src/egress.ts +12 -2
- package/src/evals.ts +26 -18
- package/src/frontmatter-fields.ts +9 -0
- package/src/frontmatter-schema.ts +3 -0
- package/src/history.ts +13 -0
- package/src/hooks.ts +1 -1
- package/src/insights.ts +174 -0
- package/src/issues.ts +396 -0
- package/src/library.ts +1 -1
- package/src/limits.ts +38 -5
- package/src/linkable.ts +1 -1
- package/src/matter.ts +33 -0
- package/src/model-credential.ts +45 -0
- package/src/model-env.ts +42 -10
- package/src/network.ts +25 -1
- package/src/notify.ts +22 -7
- package/src/okf.ts +1 -1
- package/src/online-checks.ts +450 -0
- package/src/operator.ts +213 -3
- package/src/otel-config.ts +67 -0
- package/src/otel.ts +100 -0
- package/src/outcome.ts +90 -0
- package/src/package.ts +1 -1
- package/src/platform.ts +1 -1
- package/src/prompt-layers.ts +90 -0
- package/src/provider-health.ts +1 -1
- package/src/providers.ts +7 -2
- package/src/run-container.ts +66 -7
- package/src/runner.ts +363 -46
- package/src/runs-filter.ts +88 -0
- package/src/scan.ts +68 -7
- package/src/starter.ts +4 -2
- package/src/step-exec.ts +147 -9
- package/src/store.ts +254 -8
- package/src/tokens.ts +68 -0
- package/src/tool-names.ts +1 -1
- package/src/tool-programs.ts +1 -1
- package/src/trace-tree.ts +187 -0
- package/src/translator.ts +13 -2
- package/src/trigger-log.ts +1 -0
- package/src/workspace-check.ts +41 -0
package/src/providers.ts
CHANGED
|
@@ -54,6 +54,11 @@ export interface ProviderPreset {
|
|
|
54
54
|
* Off means the translator drops thinking rather than send a parameter
|
|
55
55
|
* the endpoint would reject. */
|
|
56
56
|
reasoningEffort?: boolean;
|
|
57
|
+
/** Whether the endpoint takes `prompt_cache_key` — a hint that requests
|
|
58
|
+
* with the same key share a prompt prefix, so its cache can be routed
|
|
59
|
+
* to. Only set where the parameter is documented; an endpoint that does
|
|
60
|
+
* not know it may refuse the request. */
|
|
61
|
+
promptCacheKey?: boolean;
|
|
57
62
|
/** One line a person should read before relying on it. */
|
|
58
63
|
note?: string;
|
|
59
64
|
/** A tool loop was driven through this endpoint from this runtime. */
|
|
@@ -427,7 +432,7 @@ export const PROVIDERS: readonly ProviderPreset[] = [
|
|
|
427
432
|
|
|
428
433
|
// ------------------------------------------- Chat-Completions, translated
|
|
429
434
|
{ name: "openai", title: "OpenAI", format: "openai", baseUrl: "https://api.openai.com/v1", auth: "bearer", verified: true,
|
|
430
|
-
maxTokensParam: "max_completion_tokens", reasoningEffort: true,
|
|
435
|
+
maxTokensParam: "max_completion_tokens", reasoningEffort: true, promptCacheKey: true,
|
|
431
436
|
note: "Reached over Chat Completions, which OpenAI keeps supporting; the Responses API is not spoken here, so a reasoning model's reasoning does not carry across tool calls." , search: "openai" },
|
|
432
437
|
{ name: "gemini", title: "Google Gemini", format: "openai", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", auth: "bearer",
|
|
433
438
|
note: "Google's OpenAI-compatible route. Unknown parameters are ignored silently; reasoning cannot be switched off on the newest models." },
|
|
@@ -435,7 +440,7 @@ export const PROVIDERS: readonly ProviderPreset[] = [
|
|
|
435
440
|
maxTokensParam: "max_completion_tokens", reasoningEffort: true },
|
|
436
441
|
{ name: "groq", title: "Groq", format: "openai", baseUrl: "https://api.groq.com/openai/v1", auth: "bearer",
|
|
437
442
|
maxTokensParam: "max_completion_tokens", reasoningEffort: true },
|
|
438
|
-
{ name: "mistral", title: "Mistral", format: "openai", baseUrl: "https://api.mistral.ai/v1", auth: "bearer" },
|
|
443
|
+
{ name: "mistral", title: "Mistral", format: "openai", baseUrl: "https://api.mistral.ai/v1", auth: "bearer", promptCacheKey: true },
|
|
439
444
|
{ name: "together", title: "Together AI", format: "openai", baseUrl: "https://api.together.ai/v1", auth: "bearer" },
|
|
440
445
|
{ name: "cerebras", title: "Cerebras", format: "openai", baseUrl: "https://api.cerebras.ai/v1", auth: "bearer",
|
|
441
446
|
maxTokensParam: "max_completion_tokens", reasoningEffort: true },
|
package/src/run-container.ts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
// The runner image bundles @foldrun/core itself, so the driver runs the same
|
|
19
19
|
// executeStep the server would — one implementation, two homes.
|
|
20
20
|
|
|
21
|
+
import type { PeerInfo } from "./operator.ts";
|
|
21
22
|
import { isHookRecord, type HookRecord } from "./hooks.ts";
|
|
22
23
|
import fs from "node:fs";
|
|
23
24
|
import os from "node:os";
|
|
@@ -25,9 +26,9 @@ import path from "node:path";
|
|
|
25
26
|
import crypto from "node:crypto";
|
|
26
27
|
import { spawn, spawnSync } from "node:child_process";
|
|
27
28
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
28
|
-
import { isPlatformPath, type ApiSpec, type Effort } from "./store.ts";
|
|
29
|
+
import { CAPTURE_CAP, isPlatformPath, type ApiSpec, type Effort, type ModelCall } from "./store.ts";
|
|
29
30
|
import { divertedSummary, isDivertedPath, overlayTestWrites } from "./test-mode.ts";
|
|
30
|
-
import type { EventExtra, ExecUsage } from "./step-exec.ts";
|
|
31
|
+
import type { CallIo, EventExtra, ExecUsage } from "./step-exec.ts";
|
|
31
32
|
import type { TokenPrice } from "./catalog.ts";
|
|
32
33
|
import { isFileValue, fileContent } from "./secrets.ts";
|
|
33
34
|
import { safeTenantSegment, systemInstallSh, SYSTEM_FROM_INPUT_SH, INSTALL_SOCKET, type RuntimeSpec } from "./runtime.ts";
|
|
@@ -77,6 +78,8 @@ export interface ContainerStepInput {
|
|
|
77
78
|
/** `schema:` and `max_turns:`, resolved host-side — see ExecOptions. */
|
|
78
79
|
schema?: Record<string, unknown> | boolean;
|
|
79
80
|
maxTurns?: number;
|
|
81
|
+
/** `capture:` resolved host-side (FOL-54 step 4) — see ExecOptions. */
|
|
82
|
+
capture?: "metadata" | "full";
|
|
80
83
|
/** `limits:` resolved host-side, and the SDK-name → foldrun-name map the
|
|
81
84
|
* count reads (limits.ts) — enforced in the pod by the same hook. */
|
|
82
85
|
limits?: Record<string, number>;
|
|
@@ -93,6 +96,10 @@ export interface ContainerStepInput {
|
|
|
93
96
|
desks?: RunDigest[];
|
|
94
97
|
/** tools: [ask] — ask_person, and how long it may wait for an answer. */
|
|
95
98
|
ask?: { timeoutSec: number };
|
|
99
|
+
/** tools: [peers] — this step's agent and the other steps of its
|
|
100
|
+
* parallel group, gathered host-side at launch. The driver rebuilds the
|
|
101
|
+
* colleagues' tools in here over the lease's /peers door. */
|
|
102
|
+
peers?: { self: string; siblings: PeerInfo[] };
|
|
96
103
|
/** A Chat-Completions provider: the driver starts the runtime's translator
|
|
97
104
|
* on loopback and points the SDK at it. Null or absent: the env's
|
|
98
105
|
* ANTHROPIC_BASE_URL is spoken to directly. */
|
|
@@ -614,7 +621,7 @@ try {
|
|
|
614
621
|
const { buildScriptTools } = await import("@foldrun/core/script-tools");
|
|
615
622
|
const { buildConsultTools } = await import("@foldrun/core/agent-tools");
|
|
616
623
|
const { buildSearchTools, buildHistoryTools, buildDeskTools } = await import("@foldrun/core/context-tools");
|
|
617
|
-
const { httpChannel, buildAskTool, inboxReader } = await import("@foldrun/core/operator");
|
|
624
|
+
const { httpChannel, buildAskTool, buildPeerTools, inboxReader } = await import("@foldrun/core/operator");
|
|
618
625
|
const { startTranslator } = await import("@foldrun/core/translator");
|
|
619
626
|
const { prepareRuntime } = await import("@foldrun/core/runtime");
|
|
620
627
|
const { materializeFileSecrets } = await import("@foldrun/core/secret-files");
|
|
@@ -678,11 +685,18 @@ try {
|
|
|
678
685
|
// A long result is kept in a file only when the agent can read it back.
|
|
679
686
|
// (tool-output.ts canReadBack, inlined: the driver imports core by subpath.)
|
|
680
687
|
const keepIn = { dir: agentDir, readable: () => (input.allowed ?? []).some((t) => t === "Read" || t === "Grep") };
|
|
681
|
-
|
|
688
|
+
// A declared secret named like a model variable crosses as
|
|
689
|
+
// FOLDRUN_DECLARED_<NAME> (runner.ts, FOL-19): the model keeps its own
|
|
690
|
+
// settings, and the agent's API and script tools and verify: get the value
|
|
691
|
+
// back under the name it declared. Built here, after the runtime and any
|
|
692
|
+
// mid-step install have added their paths to env.
|
|
693
|
+
const toolEnv = { ...env };
|
|
694
|
+
for (const [k, v] of Object.entries(env)) if (k.startsWith("FOLDRUN_DECLARED_")) toolEnv[k.slice("FOLDRUN_DECLARED_".length)] = v;
|
|
695
|
+
const api = buildApiTools("", input.apis, undefined, { env: toolEnv, missing: [] }, keepIn);
|
|
682
696
|
const script = buildScriptTools(
|
|
683
697
|
agentDir,
|
|
684
698
|
input.scripts,
|
|
685
|
-
|
|
699
|
+
toolEnv,
|
|
686
700
|
"/library/scripts",
|
|
687
701
|
runtime.interpreters,
|
|
688
702
|
null,
|
|
@@ -705,6 +719,7 @@ try {
|
|
|
705
719
|
// ask_person when tools: [ask], and the run's inbox after every tool call.
|
|
706
720
|
const channel = httpChannel(env.FOLDRUN_EGRESS);
|
|
707
721
|
const ask = input.ask ? buildAskTool({ channel, timeoutSec: input.ask.timeoutSec, emit }) : { server: null };
|
|
722
|
+
const peers = input.peers ? buildPeerTools({ channel, self: input.peers.self, siblings: input.peers.siblings, emit }) : { server: null };
|
|
708
723
|
const inbox = channel ? inboxReader(channel, emit) : undefined;
|
|
709
724
|
|
|
710
725
|
mark("tools");
|
|
@@ -726,6 +741,7 @@ try {
|
|
|
726
741
|
...(history.server ? { foldrun_history: history.server } : {}),
|
|
727
742
|
...(desks.server ? { foldrun_desks: desks.server } : {}),
|
|
728
743
|
...(ask.server ? { foldrun_ask: ask.server } : {}),
|
|
744
|
+
...(peers.server ? { foldrun_peers: peers.server } : {}),
|
|
729
745
|
...(install.server ? { foldrun_install: install.server } : {}),
|
|
730
746
|
...input.mcpServers,
|
|
731
747
|
},
|
|
@@ -737,10 +753,11 @@ try {
|
|
|
737
753
|
budgetNote: input.budgetNote,
|
|
738
754
|
price: input.price,
|
|
739
755
|
verify: input.verify,
|
|
740
|
-
verifyEnv:
|
|
756
|
+
verifyEnv: toolEnv,
|
|
741
757
|
output: input.output,
|
|
742
758
|
schema: input.schema,
|
|
743
759
|
maxTurns: input.maxTurns,
|
|
760
|
+
...(input.capture === "metadata" || input.capture === "full" ? { capture: input.capture } : {}),
|
|
744
761
|
...(input.limits && Object.keys(input.limits).length ? { limits: input.limits, toolOwners: input.toolOwners ?? {} } : {}),
|
|
745
762
|
...(input.hookNames?.length ? { hookNames: input.hookNames, hookBase: input.hookBase ?? {} } : {}),
|
|
746
763
|
// Slim browsing: the platform put this step on the slim image to browse
|
|
@@ -1190,9 +1207,47 @@ export function buildFailureSummary(log: string, opts: { tail?: number; maxLines
|
|
|
1190
1207
|
|
|
1191
1208
|
// ---------- running one step ----------
|
|
1192
1209
|
|
|
1210
|
+
const num = (v: unknown) => (typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0);
|
|
1211
|
+
|
|
1212
|
+
/** A tool call's content from the sandbox, as far as it is well-formed and
|
|
1213
|
+
* within the cap; anything else is dropped (FOL-54 step 4). */
|
|
1214
|
+
function callIoOf(v: unknown): CallIo | null {
|
|
1215
|
+
if (!v || typeof v !== "object") return null;
|
|
1216
|
+
const o = v as Record<string, unknown>;
|
|
1217
|
+
// The cap plus the slack the runner masks inside before it cuts.
|
|
1218
|
+
const text = (x: unknown) => (typeof x === "string" ? x.slice(0, CAPTURE_CAP + 4096) : undefined);
|
|
1219
|
+
const io: CallIo = {
|
|
1220
|
+
...(text(o.input) !== undefined ? { input: text(o.input) } : {}),
|
|
1221
|
+
...(text(o.output) !== undefined ? { output: text(o.output) } : {}),
|
|
1222
|
+
...(typeof o.inputChars === "number" ? { inputChars: num(o.inputChars) } : {}),
|
|
1223
|
+
...(typeof o.outputChars === "number" ? { outputChars: num(o.outputChars) } : {}),
|
|
1224
|
+
...(o.truncated === true ? { truncated: true } : {}),
|
|
1225
|
+
};
|
|
1226
|
+
return io.input !== undefined || io.output !== undefined ? io : null;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/** One model call from the sandbox, well-formed or dropped. */
|
|
1230
|
+
function modelCallOf(v: unknown): ModelCall | null {
|
|
1231
|
+
if (!v || typeof v !== "object") return null;
|
|
1232
|
+
const o = v as Record<string, unknown>;
|
|
1233
|
+
const t = (o.tokens ?? {}) as Record<string, unknown>;
|
|
1234
|
+
if (typeof o.id !== "string" || !o.id || o.id.length > 128 || typeof o.at !== "string" || Number.isNaN(Date.parse(o.at))) return null;
|
|
1235
|
+
return {
|
|
1236
|
+
id: o.id,
|
|
1237
|
+
n: Math.max(1, Math.floor(num(o.n))),
|
|
1238
|
+
at: o.at,
|
|
1239
|
+
ms: num(o.ms),
|
|
1240
|
+
...(typeof o.model === "string" ? { model: o.model.slice(0, 128) } : {}),
|
|
1241
|
+
...(typeof o.stop === "string" ? { stop: o.stop.slice(0, 64) } : {}),
|
|
1242
|
+
tokens: { input: num(t.input), output: num(t.output), cacheRead: num(t.cacheRead), cacheWrite: num(t.cacheWrite) },
|
|
1243
|
+
tools: Math.floor(num(o.tools)),
|
|
1244
|
+
...(typeof o.subagent === "string" && /^[a-z0-9-]{1,64}$/.test(o.subagent) ? { subagent: o.subagent } : {}),
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1193
1248
|
export function parseDriverLine(
|
|
1194
1249
|
line: string,
|
|
1195
|
-
): { e: "event"; type: "text" | "tool" | "info" | "error"; text: string; call?: string; ms?: number; err?: boolean; bytes?: number; operator?: OperatorEvent; subagent?: string; check?: boolean; hook?: HookRecord } | { e: "done" } & ContainerStepOutcome | null {
|
|
1250
|
+
): { e: "event"; type: "text" | "tool" | "info" | "error"; text: string; call?: string; ms?: number; err?: boolean; bytes?: number; operator?: OperatorEvent; subagent?: string; check?: boolean; hook?: HookRecord; io?: CallIo; turn?: ModelCall; inCall?: string; responding?: true } | { e: "done" } & ContainerStepOutcome | null {
|
|
1196
1251
|
const trimmed = line.trim();
|
|
1197
1252
|
if (!trimmed.startsWith("{")) return null;
|
|
1198
1253
|
try {
|
|
@@ -1210,6 +1265,10 @@ export function parseDriverLine(
|
|
|
1210
1265
|
...(typeof parsed.subagent === "string" && /^[a-z0-9-]{1,64}$/.test(parsed.subagent) ? { subagent: parsed.subagent } : {}),
|
|
1211
1266
|
...(parsed.check === true ? { check: true } : {}),
|
|
1212
1267
|
...(isHookRecord(parsed.hook) ? { hook: parsed.hook } : {}),
|
|
1268
|
+
...(callIoOf(parsed.io) ? { io: callIoOf(parsed.io)! } : {}),
|
|
1269
|
+
...(typeof parsed.inCall === "string" && parsed.inCall.length <= 128 ? { inCall: parsed.inCall } : {}),
|
|
1270
|
+
...(modelCallOf(parsed.turn) ? { turn: modelCallOf(parsed.turn)! } : {}),
|
|
1271
|
+
...(parsed.responding === true ? { responding: true as const } : {}),
|
|
1213
1272
|
};
|
|
1214
1273
|
}
|
|
1215
1274
|
if (parsed.e === "done") {
|