@foldrun/core 9.1.0 → 9.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.
- package/dist/src/a2a-client.d.ts +165 -0
- package/dist/src/a2a-client.js +440 -0
- package/dist/src/a2a-publish.d.ts +37 -0
- package/dist/src/a2a-publish.js +116 -0
- package/dist/src/a2a-remotes.d.ts +73 -0
- package/dist/src/a2a-remotes.js +192 -0
- package/dist/src/a2a-tools.d.ts +148 -0
- package/dist/src/a2a-tools.js +833 -0
- package/dist/src/api-tools.js +15 -10
- package/dist/src/browser-pod.js +4 -0
- package/dist/src/completions.js +8 -8
- package/dist/src/frontmatter-fields.js +2 -0
- package/dist/src/frontmatter-schema.js +4 -0
- package/dist/src/limits.js +22 -4
- package/dist/src/run-container.d.ts +10 -1
- package/dist/src/run-container.js +17 -0
- package/dist/src/runner.d.ts +10 -0
- package/dist/src/runner.js +158 -14
- package/dist/src/scan.js +102 -5
- package/dist/src/secrets.d.ts +30 -0
- package/dist/src/secrets.js +41 -1
- package/dist/src/starter.js +6 -1
- package/dist/src/store.d.ts +34 -0
- package/dist/src/store.js +28 -7
- package/dist/src/subagents.d.ts +16 -0
- package/dist/src/subagents.js +23 -2
- package/package.json +4 -1
- package/src/a2a-client.ts +517 -0
- package/src/a2a-publish.ts +120 -0
- package/src/a2a-remotes.ts +225 -0
- package/src/a2a-tools.ts +919 -0
- package/src/api-tools.ts +20 -8
- package/src/browser-pod.ts +3 -0
- package/src/completions.ts +8 -8
- package/src/frontmatter-fields.ts +2 -0
- package/src/frontmatter-schema.ts +4 -0
- package/src/limits.ts +22 -4
- package/src/run-container.ts +22 -0
- package/src/runner.ts +152 -11
- package/src/scan.ts +123 -6
- package/src/secrets.ts +43 -1
- package/src/starter.ts +6 -1
- package/src/store.ts +47 -2
- package/src/subagents.ts +29 -2
package/dist/src/starter.js
CHANGED
|
@@ -373,6 +373,7 @@ All of it, \`/api/workspaces/<workspace>\` unless noted:
|
|
|
373
373
|
| \`/export\` · \`/import\` | GET · POST | the workspace, a flow (\`?kind=flow&name=\`) or an agent as a .zip; take one in (\`?dryRun=1\` first, \`?overwrite=1\` to replace) |
|
|
374
374
|
| \`/restore\` | POST | the workspace's source back to a point in its history — \`dryRun\` first, then \`confirm\` |
|
|
375
375
|
| \`/vocabulary\` | GET | what this workspace's documents may say |
|
|
376
|
+
| \`/a2a\` | GET | what it serves to outside agents over A2A: flows that say \`a2a:\`, card URLs, recent tasks |
|
|
376
377
|
| \`/check\` | GET | what \`foldrun check\` says about the deployed copy, as findings with rule ids (\`?security=1\`) |
|
|
377
378
|
| \`/assistant\` | POST | ask the assistant, or have it write agents, flows, tools and skills — from the docs only; proposals come back, nothing is written |
|
|
378
379
|
|
|
@@ -380,9 +381,11 @@ Account-level, outside \`/workspaces\`: \`/api/secrets\`, \`/api/keys\`, \`/api/
|
|
|
380
381
|
\`/api/approvals\`, \`/api/issues\` (what went wrong, open until resolved), \`/api/usage\`, \`/api/library/<kind>\`, \`/api/team\`, \`/api/billing\`,
|
|
381
382
|
\`/api/me/notifications\` (what mail you get; a key acts for whoever minted it),
|
|
382
383
|
\`/api/me/inbox\` (what waits on you: gates, questions, issues, proposed fixes, your failed runs),
|
|
384
|
+
\`/api/mcp\` (this account as MCP tools for an AI app such as Claude Desktop or Cursor — an API key; \`foldrun mcp\` serves the same over stdio, \`foldrun docs mcp\`),
|
|
383
385
|
\`/api/account/backups\` (snapshots, restore requests), \`/api/me/onboarding\` (getting started),
|
|
384
386
|
\`/api/healthz\` and \`/api/version\` (open), \`/api/changelog\` (release notes)
|
|
385
|
-
and \`/api/metrics\` (Prometheus).
|
|
387
|
+
and \`/api/metrics\` (Prometheus). Outside \`/api\`: \`/a2a/<account>/<ws>/flows/<flow>\`
|
|
388
|
+
(a published flow's agent card and A2A 1.0 JSON-RPC endpoint — an A2A key only, \`foldrun docs a2a\`).
|
|
386
389
|
|
|
387
390
|
Every call answers — and the CLI sends — \`Foldrun-Version: YYYY-MM-DD\` (dated API
|
|
388
391
|
versions; an account pin in Settings → API), \`X-RateLimit-*\` headers (a \`429\`
|
|
@@ -418,6 +421,7 @@ effort: low
|
|
|
418
421
|
overlap: skip # skip | queue — what a second run does while one is live
|
|
419
422
|
priority: normal # high | normal | low — where its runs stand in the queue
|
|
420
423
|
compute: { vcpu: 4, memory: 8Gi, disk: 40Gi } # optional: what one run may hold at once
|
|
424
|
+
a2a: { publish: false } # true: outside agents may call it over A2A (admin only; callers need an A2A key)
|
|
421
425
|
---
|
|
422
426
|
|
|
423
427
|
1. [[researcher]] — Find three sources on {{topic}}.
|
|
@@ -483,6 +487,7 @@ hooks: [no-force-push] # from hooks/ or the library: code at every tool cal
|
|
|
483
487
|
scripts: [summarise.py] # from scripts/, each becomes a callable tool
|
|
484
488
|
apis: [{ name: crm }] # an HTTP API, as a tool
|
|
485
489
|
mcpServers: {} # an MCP server, as a tool
|
|
490
|
+
remotes: [] # outside A2A agents [{name, card, secret?}] — the a2a_send/status/reply/cancel tools
|
|
486
491
|
agents: [writer] # colleagues this one may consult (an answer, no tools)
|
|
487
492
|
subagents: [researcher] # colleagues it may delegate a job to (own context, own tools ≤ its own)
|
|
488
493
|
sandbox: own # delegated to: run each job in its own sandbox (own tools, secrets, network)
|
package/dist/src/store.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { frontmatterErrorText } from "./matter.ts";
|
|
|
14
14
|
* the runtime, and there is nothing to fail to import.
|
|
15
15
|
*/
|
|
16
16
|
export declare function readFrontmatter(file: string): Record<string, unknown>;
|
|
17
|
+
import { type A2aPublication } from "./a2a-publish.ts";
|
|
18
|
+
import { type RemoteSpec } from "./a2a-remotes.ts";
|
|
17
19
|
import { type NetworkPolicy } from "./network.ts";
|
|
18
20
|
import { type WireFormat, type AuthShape } from "./providers.ts";
|
|
19
21
|
/**
|
|
@@ -306,6 +308,9 @@ export interface AgentInfo {
|
|
|
306
308
|
effort: string | null;
|
|
307
309
|
tools: string[];
|
|
308
310
|
apis: ApiSpec[];
|
|
311
|
+
/** `remotes:` — the outside A2A agents it may call, the entries that read
|
|
312
|
+
* (a2a-remotes.ts). Never a token: names, card URLs, secret NAMES. */
|
|
313
|
+
remotes?: RemoteSpec[];
|
|
309
314
|
/** The author's own tools named in `tools:` — the subset that is not a
|
|
310
315
|
* built-in. Same list as `tools`, minus what the runtime provides. */
|
|
311
316
|
ownTools: string[];
|
|
@@ -652,6 +657,10 @@ export interface FlowInfo {
|
|
|
652
657
|
owner: string | null;
|
|
653
658
|
/** Which of the three `owner` came from. */
|
|
654
659
|
ownerFrom: OwnerSource | null;
|
|
660
|
+
/** `a2a:` — whether outside agents may call this flow over A2A, and what
|
|
661
|
+
* its agent card says (a2a-publish.ts). Null when absent or unreadable:
|
|
662
|
+
* a block with a problem publishes nothing. */
|
|
663
|
+
a2a?: A2aPublication | null;
|
|
655
664
|
/** Flow-level frontmatter values the parser could not read — a bad
|
|
656
665
|
* `overlap:`/`priority:`/`catchup:`/`on:`/`signature:`, or a step line
|
|
657
666
|
* whose `[[target]]` is malformed. Errors, the way a bad step option is,
|
|
@@ -1445,6 +1454,11 @@ export interface RunRecord {
|
|
|
1445
1454
|
* expressed only as a status, because "failed" and "someone stopped it"
|
|
1446
1455
|
* are different facts and the trace should not conflate them. */
|
|
1447
1456
|
stopRequested?: boolean;
|
|
1457
|
+
/** Who stopped it, as the trail says it, when that was not a person
|
|
1458
|
+
* stopping it from the dashboard, the CLI or the API: "A2A caller
|
|
1459
|
+
* <key label>" for an A2A CancelTask (1 Nov 2026). Absent: a person.
|
|
1460
|
+
* Written by stopRun beside stopRequested, carried the same way. */
|
|
1461
|
+
stoppedBy?: string;
|
|
1448
1462
|
/**
|
|
1449
1463
|
* What this run concluded, in one line — the first line of the last step
|
|
1450
1464
|
* that produced a result, captured when the run finishes.
|
|
@@ -1523,6 +1537,17 @@ export interface RunRecord {
|
|
|
1523
1537
|
* step of this run — never the tokens. A link is good once; the second
|
|
1524
1538
|
* click is a 409, not a second approval. Written by approvals.ts. */
|
|
1525
1539
|
approvalLinksUsed?: string[];
|
|
1540
|
+
/** What started it, when that is not a person, a schedule or an event the
|
|
1541
|
+
* flow's own trigger names: "a2a" — an outside agent, over A2A (1 Nov
|
|
1542
|
+
* 2026). Absent for every other run. */
|
|
1543
|
+
trigger?: "a2a";
|
|
1544
|
+
/** For an A2A run: the A2A task it serves and the id of the A2A key (its
|
|
1545
|
+
* first id, kept across rotations) that asked. A correlation only — the
|
|
1546
|
+
* protocol's own state lives in the platform's a2a_tasks. */
|
|
1547
|
+
a2a?: {
|
|
1548
|
+
task: string;
|
|
1549
|
+
key: string;
|
|
1550
|
+
};
|
|
1526
1551
|
steps: StepRecord[];
|
|
1527
1552
|
}
|
|
1528
1553
|
/** Merge one part (the input, on the call; the output, on its completion)
|
|
@@ -1643,6 +1668,12 @@ export interface RunSummary {
|
|
|
1643
1668
|
revision?: string | null;
|
|
1644
1669
|
/** A step is parked for a person — what the approvals banner counts. */
|
|
1645
1670
|
awaitingApproval: boolean;
|
|
1671
|
+
/** RunRecord.trigger and .a2a: an outside agent started it. */
|
|
1672
|
+
trigger?: "a2a";
|
|
1673
|
+
a2a?: {
|
|
1674
|
+
task: string;
|
|
1675
|
+
key: string;
|
|
1676
|
+
};
|
|
1646
1677
|
steps: RunSummaryStep[];
|
|
1647
1678
|
}
|
|
1648
1679
|
/** One run's row. */
|
|
@@ -1661,6 +1692,9 @@ export declare function listRunSummaries(tenant: string, workspace: string): Run
|
|
|
1661
1692
|
export declare function listAllRunSummaries(tenant: string): (RunSummary & {
|
|
1662
1693
|
workspace: string;
|
|
1663
1694
|
})[];
|
|
1695
|
+
/** Who stopped a run, for a trail line: "a person" unless stopRun was told
|
|
1696
|
+
* otherwise (RunRecord.stoppedBy). */
|
|
1697
|
+
export declare function stoppedByText(run: Pick<RunRecord, "stoppedBy"> | null | undefined): string;
|
|
1664
1698
|
/**
|
|
1665
1699
|
* The status a person should see. "failed" and "someone stopped it" are
|
|
1666
1700
|
* different facts — the record keeps them apart (stopRequested), and the
|
package/dist/src/store.js
CHANGED
|
@@ -45,6 +45,8 @@ export function readFrontmatter(file) {
|
|
|
45
45
|
import { ownToolNames, legacyUseNames, retiredToolNames } from "./tool-names.js";
|
|
46
46
|
import { refNames } from "./refs.js";
|
|
47
47
|
import { checkFilter } from "./trigger-filter.js";
|
|
48
|
+
import { parseA2aPublish } from "./a2a-publish.js";
|
|
49
|
+
import { parseRemotes, remoteNetworkHosts, A2A_LIMIT_KEY } from "./a2a-remotes.js";
|
|
48
50
|
import { parseBudget, budgetProblem } from "./budget.js";
|
|
49
51
|
import { timezoneProblem } from "./clock.js";
|
|
50
52
|
import { parseStepLimits, readLimits } from "./limits.js";
|
|
@@ -1115,6 +1117,9 @@ function inlineToolNames(data) {
|
|
|
1115
1117
|
}
|
|
1116
1118
|
if (data.mcpServers && typeof data.mcpServers === "object")
|
|
1117
1119
|
out.push(...Object.keys(data.mcpServers));
|
|
1120
|
+
// remotes: grants the a2a tools, counted under `limits: {a2a: N}`.
|
|
1121
|
+
if (parseRemotes(data.remotes).length)
|
|
1122
|
+
out.push(A2A_LIMIT_KEY);
|
|
1118
1123
|
return out;
|
|
1119
1124
|
}
|
|
1120
1125
|
export function listAgents(tenant, workspace) {
|
|
@@ -1158,12 +1163,16 @@ export function listAgents(tenant, workspace) {
|
|
|
1158
1163
|
workspace: workspaceFront.network,
|
|
1159
1164
|
agent: data.network,
|
|
1160
1165
|
readsWeb,
|
|
1161
|
-
implied:
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1166
|
+
implied: [
|
|
1167
|
+
...parseApis(data.apis).map((a) => { try {
|
|
1168
|
+
return new URL(a.base).host;
|
|
1169
|
+
}
|
|
1170
|
+
catch {
|
|
1171
|
+
return "";
|
|
1172
|
+
} }),
|
|
1173
|
+
// remotes: — each card's own host, and nothing its card says.
|
|
1174
|
+
...remoteNetworkHosts(parseRemotes(data.remotes)),
|
|
1175
|
+
],
|
|
1167
1176
|
}),
|
|
1168
1177
|
readsWeb,
|
|
1169
1178
|
};
|
|
@@ -1176,6 +1185,7 @@ export function listAgents(tenant, workspace) {
|
|
|
1176
1185
|
effort: data.effort ?? null,
|
|
1177
1186
|
tools,
|
|
1178
1187
|
apis: parseApis(data.apis),
|
|
1188
|
+
remotes: parseRemotes(data.remotes),
|
|
1179
1189
|
ownTools: ownToolNames(data),
|
|
1180
1190
|
legacyUse: legacyUseNames(data),
|
|
1181
1191
|
retiredTools: retiredToolNames(data),
|
|
@@ -1689,6 +1699,7 @@ export function parseFlow(file, raw) {
|
|
|
1689
1699
|
approveWithin: durationOf(data.approve_within),
|
|
1690
1700
|
description: typeof data.description === "string" ? data.description.trim() || null : null,
|
|
1691
1701
|
...resolveOwner(data.owner, undefined, undefined, "flow"),
|
|
1702
|
+
a2a: parseA2aPublish(data.a2a),
|
|
1692
1703
|
frontProblems,
|
|
1693
1704
|
steps,
|
|
1694
1705
|
};
|
|
@@ -2505,7 +2516,9 @@ export function renameWorkspaceFile(tenant, workspace, from, to, meta = {}) {
|
|
|
2505
2516
|
// Refuse with the reason before any path validation: "not an editable
|
|
2506
2517
|
// path" is true of AGENTS.md too, and the generic sentence buries the
|
|
2507
2518
|
// specific one worth reading.
|
|
2508
|
-
|
|
2519
|
+
// Read as the paths the rename will use: `./AGENTS.md` is AGENTS.md
|
|
2520
|
+
// (1 Nov 2026 — the raw spelling slipped past this and still moved it).
|
|
2521
|
+
const why = anchoredReason(path.normalize(from)) ?? anchoredReason(path.normalize(to));
|
|
2509
2522
|
if (why)
|
|
2510
2523
|
throw new Error(why);
|
|
2511
2524
|
const dir = workspaceDir(tenant, workspace);
|
|
@@ -3014,6 +3027,8 @@ export function summarizeRun(run) {
|
|
|
3014
3027
|
...(run.startedBy ? { startedBy: run.startedBy } : {}),
|
|
3015
3028
|
...(run.parkedAt ? { parkedAt: run.parkedAt } : {}),
|
|
3016
3029
|
...(run.revision ? { revision: run.revision } : {}),
|
|
3030
|
+
...(run.trigger ? { trigger: run.trigger } : {}),
|
|
3031
|
+
...(run.a2a ? { a2a: run.a2a } : {}),
|
|
3017
3032
|
awaitingApproval: run.steps.some((s) => s.status === "awaiting-approval" && s.waitFor !== "event"),
|
|
3018
3033
|
steps: run.steps.map((s) => {
|
|
3019
3034
|
const error = s.status === "failed" ? s.events.filter((e) => e.type === "error").at(-1)?.text : undefined;
|
|
@@ -3212,6 +3227,12 @@ export function listAllRunSummaries(tenant) {
|
|
|
3212
3227
|
.flatMap((p) => listRunSummaries(tenant, p.name).map((s) => ({ ...s, workspace: p.name })))
|
|
3213
3228
|
.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
3214
3229
|
}
|
|
3230
|
+
/** Who stopped a run, for a trail line: "a person" unless stopRun was told
|
|
3231
|
+
* otherwise (RunRecord.stoppedBy). */
|
|
3232
|
+
export function stoppedByText(run) {
|
|
3233
|
+
const by = run?.stoppedBy?.trim();
|
|
3234
|
+
return by ? by : "a person";
|
|
3235
|
+
}
|
|
3215
3236
|
/**
|
|
3216
3237
|
* The status a person should see. "failed" and "someone stopped it" are
|
|
3217
3238
|
* different facts — the record keeps them apart (stopRequested), and the
|
package/dist/src/subagents.d.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The a2a tools (remotes:) are the parent's: one server, built for the
|
|
3
|
+
* PARENT's remotes with the parent's credentials, under the same four names
|
|
4
|
+
* whatever remotes a sub-agent declares. Intersecting names would hand a
|
|
5
|
+
* shared-sandbox sub-agent every remote its parent may call. So they are
|
|
6
|
+
* withheld from it entirely — not in its list, and refused if it calls one.
|
|
7
|
+
* A `sandbox: own` sub-agent runs as a step of its own, from its own file,
|
|
8
|
+
* and gets its OWN remotes there (runner.ts delegateFor → runStep).
|
|
9
|
+
*/
|
|
10
|
+
export declare function isA2aTool(tool: string): boolean;
|
|
11
|
+
/** What a shared-sandbox sub-agent is told, and what its refused call says. */
|
|
12
|
+
export declare const SUBAGENT_NO_REMOTES = "remotes: are not available to shared-sandbox sub-agents yet \u2014 give the sub-agent `sandbox: own`, or call the remote from the parent";
|
|
1
13
|
/** Plain JSON: this crosses into the run container. */
|
|
2
14
|
export interface SubagentSpec {
|
|
3
15
|
name: string;
|
|
@@ -50,6 +62,10 @@ export declare function subagentPrompt(o: {
|
|
|
50
62
|
parent: string;
|
|
51
63
|
workspace: string;
|
|
52
64
|
shared?: string | null;
|
|
65
|
+
}, extra?: {
|
|
66
|
+
/** It declares remotes:, which it does not get here. A second argument,
|
|
67
|
+
* so the signature only widened. */
|
|
68
|
+
remotesWithheld?: boolean;
|
|
53
69
|
}): string;
|
|
54
70
|
/** SDK definitions. `tools` is always set — an absent list inherits every
|
|
55
71
|
* tool the parent has, which is the one thing this module exists to stop. */
|
package/dist/src/subagents.js
CHANGED
|
@@ -27,6 +27,21 @@ import fs from "node:fs";
|
|
|
27
27
|
import path from "node:path";
|
|
28
28
|
import { refNames } from "./refs.js";
|
|
29
29
|
import { TOOL_MAP } from "./tool-names.js";
|
|
30
|
+
import { A2A_SERVER } from "./a2a-remotes.js";
|
|
31
|
+
/**
|
|
32
|
+
* The a2a tools (remotes:) are the parent's: one server, built for the
|
|
33
|
+
* PARENT's remotes with the parent's credentials, under the same four names
|
|
34
|
+
* whatever remotes a sub-agent declares. Intersecting names would hand a
|
|
35
|
+
* shared-sandbox sub-agent every remote its parent may call. So they are
|
|
36
|
+
* withheld from it entirely — not in its list, and refused if it calls one.
|
|
37
|
+
* A `sandbox: own` sub-agent runs as a step of its own, from its own file,
|
|
38
|
+
* and gets its OWN remotes there (runner.ts delegateFor → runStep).
|
|
39
|
+
*/
|
|
40
|
+
export function isA2aTool(tool) {
|
|
41
|
+
return tool === `mcp__${A2A_SERVER}` || tool.startsWith(`mcp__${A2A_SERVER}__`);
|
|
42
|
+
}
|
|
43
|
+
/** What a shared-sandbox sub-agent is told, and what its refused call says. */
|
|
44
|
+
export const SUBAGENT_NO_REMOTES = "remotes: are not available to shared-sandbox sub-agents yet — give the sub-agent `sandbox: own`, or call the remote from the parent";
|
|
30
45
|
/** Does this agent run in its own sandbox when delegated to? */
|
|
31
46
|
export function ownSandbox(front) {
|
|
32
47
|
return front.sandbox === "own";
|
|
@@ -63,7 +78,7 @@ export function subagentTools(own, parent) {
|
|
|
63
78
|
const servers = new Set(parent.filter((t) => /^mcp__[^_]/.test(t)).map((t) => t.replace(/__\*$/, "")).filter((t) => !t.slice(5).includes("__")));
|
|
64
79
|
const out = [];
|
|
65
80
|
for (const t of own) {
|
|
66
|
-
if (DELEGATE_TOOLS.includes(t) || out.includes(t))
|
|
81
|
+
if (DELEGATE_TOOLS.includes(t) || isA2aTool(t) || out.includes(t))
|
|
67
82
|
continue;
|
|
68
83
|
const server = /^mcp__([^_].*?)__/.exec(t)?.[1];
|
|
69
84
|
if (held.has(t) || (server && servers.has(`mcp__${server}`)))
|
|
@@ -73,9 +88,12 @@ export function subagentTools(own, parent) {
|
|
|
73
88
|
}
|
|
74
89
|
/** The sub-agent's system prompt: its own prose, told where it stands. It
|
|
75
90
|
* works in the PARENT's directory — the SDK shares the session's cwd. */
|
|
76
|
-
export function subagentPrompt(o) {
|
|
91
|
+
export function subagentPrompt(o, extra = {}) {
|
|
77
92
|
return [
|
|
78
93
|
o.body.trim(),
|
|
94
|
+
...(extra.remotesWithheld
|
|
95
|
+
? [`# Outside agents\n\nYour remotes: are not available to you as ${o.parent}'s sub-agent: ${SUBAGENT_NO_REMOTES}. If the job needs an outside agent, say so in your reply and ${o.parent} can call it.`]
|
|
96
|
+
: []),
|
|
79
97
|
`# Where you are\n\n` +
|
|
80
98
|
`You are ${o.name}, a sub-agent started by ${o.parent} to do one job and report back. ` +
|
|
81
99
|
`You work in ${o.parent}'s directory, \`agents/${o.parent}/\` in the \`${o.workspace}\` workspace: ` +
|
|
@@ -131,6 +149,9 @@ export function subagentGuard(specs) {
|
|
|
131
149
|
if (isDelegate(tool)) {
|
|
132
150
|
return `${s.name} is a sub-agent and cannot start another — do the work with your own tools`;
|
|
133
151
|
}
|
|
152
|
+
// The parent's remotes, with the parent's credentials: never a sub-agent's.
|
|
153
|
+
if (isA2aTool(tool))
|
|
154
|
+
return `${tool} is not available to ${s.name}: ${SUBAGENT_NO_REMOTES}`;
|
|
134
155
|
if (s.disallowedTools.includes(tool))
|
|
135
156
|
return `${tool} is disallowed for ${s.name}`;
|
|
136
157
|
if (subagentTools([tool], s.tools).length === 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foldrun/core",
|
|
3
|
-
"version": "9.1
|
|
3
|
+
"version": "9.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",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"foldrun": {
|
|
18
18
|
"publicApi": [
|
|
19
19
|
".",
|
|
20
|
+
"./a2a-client",
|
|
21
|
+
"./a2a-publish",
|
|
22
|
+
"./a2a-remotes",
|
|
20
23
|
"./agents-md",
|
|
21
24
|
"./browser-pod",
|
|
22
25
|
"./flow-patterns",
|