nylorun 0.26.0-beta → 0.27.0-beta

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # nylorun
2
2
 
3
+ ## 0.27.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - 2afa44d: The Runtime's primitives as its own Agent Plugins (ADR-106, D84). An `agent-folder/3` folder lists them under `plugins:` (`nylorun-memory`, `nylorun-triggers`, `nylorun-plan`, `nylorun-interactions`, `nylorun-artifacts`, `nylorun-sandbox`, which needs a computer), with no versions, and turns one of their tools off with `mcpServers.nylorun.tools.<tool>.enabled: false`. The compiler reads them as the `agent-folder/2` declarations they stand for (`memory`, `loop`, `engine.sandbox`, `engine.artifacts`, `engine.triggers`, which v3 refuses) and records them in `harness.engine.plugins`, each with its tools and the hash of its files. The engine presents their tools as the reserved server `nylorun`: the model reads `nylorun__memory` and the declared plugins' words as one text, with their skills (`memory`, `triggers`) in the catalog, served from the bundle; every effect keeps its target and `toolName`, so the record, tool policy (`kind: "runtime"` rules) and dispatch are unchanged. New: `ask` (`nylorun-interactions`, `harness.loop.ask`), a question that pauses the turn as an A2A `question`; `removeTools` takes `nylorun__<tool>`; `triggers` answers carry `now`; under `nylorun-triggers`, an agent-made trigger's run starts with a `[trigger <id> · <title> · nobody is watching]` line, and a turn a trigger started may set a one-off follow-up (`in` or `at`, `session: "this"`); the sandbox's instructions name the hosts `runtime.json` allows. `nylorun migrate folder <dir> --to 3` writes the plugins that keep an agent's tools and features, and `nylorun check --explain` names the plugin behind each. The JSON Schemas are republished as `agent-manifest/v8.4`, `harness-manifest/v1.4` and `agent-folder/v1/agent-md.4`.
8
+
9
+ ### Patch Changes
10
+
11
+ - Pin core to the tested release.
12
+ - Pin agents to the tested release.
13
+ - Pin admin to the tested release.
14
+ - Pin runtime to the tested release.
15
+ - Pin studio to the tested release.
16
+ - Updated dependencies [2afa44d]
17
+ - Updated dependencies
18
+ - Updated dependencies
19
+ - @nylorun/core@0.36.0-beta
20
+ - @nylorun/agents@0.35.0-beta
21
+ - @nylorun/admin@0.19.12-beta
22
+
3
23
  ## 0.26.0-beta
4
24
 
5
25
  ### Minor Changes
package/README.md CHANGED
@@ -60,6 +60,7 @@ nylorun chat <agent> [--session <id>] [--message <text>] # send each line (or
60
60
  nylorun migrate v8 <agent.json> [--runtime <environment-manifest.json>] [--name <name>] [--out <dir>] # the three files from a v7 manifest; reads no Runtime
61
61
  nylorun migrate folder <dir> [--out <dir>] # the agent folder of a three-file folder; reads no Runtime
62
62
  nylorun migrate folder <dir> --to 2 # make an agent folder agent-folder/2, declaring what it gets today
63
+ nylorun migrate folder <dir> --to 3 # make an agent-folder/2 folder agent-folder/3, with the Runtime's plugins
63
64
  nylorun export --folder <name>[@<n>] [--out <dir>] # the agent folder of a saved manifest (JSON or TypeScript)
64
65
  nylorun pull <name>[@<n>] [--out <dir>] # the folder a version was saved from, byte for byte
65
66
  nylorun agent-manifests list [--json] # name, latest version, runtime kind, harness, Agents
@@ -606,6 +607,24 @@ blocks the agent gets, with their versions and hashes (`harness.engine.blocks`).
606
607
  `nylorun migrate folder <dir> --to 2` writes the declarations that keep what an `agent-folder/1`
607
608
  folder gets, so nothing changes until you remove a line.
608
609
 
610
+ **The Runtime's plugins (`agent-folder/3`, ADR-106).** A v3 folder names the Runtime's features
611
+ as plugins instead of keys:
612
+
613
+ ```yaml
614
+ format: agent-folder/3
615
+ plugins: [nylorun-memory, nylorun-triggers, nylorun-plan, nylorun-interactions, nylorun-artifacts, nylorun-sandbox]
616
+ mcpServers:
617
+ nylorun:
618
+ tools: { save_artifact: { enabled: false } } # one plugin tool turned off
619
+ engine: { outputs: true, toolSearch: false } # the harness's own, as in v2
620
+ ```
621
+
622
+ Their tools reach the model as the server `nylorun` (`nylorun__memory`, `nylorun__bash`…), with
623
+ the declared plugins' words and skills, and each call's effect is the one it was in v2. The plugins
624
+ follow the Runtime installed, so they take no version. `nylorun-interactions` adds `ask`, a
625
+ question to whoever gave the agent its task. `nylorun migrate folder <dir> --to 3` writes the
626
+ plugins that keep an `agent-folder/2` folder's tools and features.
627
+
609
628
  The loop from an empty folder to an answer:
610
629
 
611
630
  ```
package/dist/cli.js CHANGED
@@ -36,6 +36,8 @@ Agent manifests:
36
36
  (agent.manifest.json; reads no Runtime)
37
37
  migrate folder <dir> --to 2 make an agent folder agent-folder/2, declaring every
38
38
  engine feature it gets today, so nothing it gets changes
39
+ migrate folder <dir> --to 3 make an agent-folder/2 folder agent-folder/3, declaring
40
+ its Runtime features as plugins (plugins: [nylorun-...])
39
41
  export --folder <name>[@<version>] [--out <dir>]
40
42
  write the agent folder of a saved manifest (Runtime API)
41
43
  pull <name>[@<version>] [--out <dir>]
@@ -116,7 +116,8 @@ async function fixFolder(pack, diagnostics, cwd) {
116
116
  export function explainLines(agents) {
117
117
  const lines = [];
118
118
  for (const agent of agents) {
119
- lines.push(` ${agent.agent}: ${agent.declared ? "declares its engine features (agent-folder/2)" : "every engine feature by default (agent-folder/1)"}`);
119
+ const plugins = agent.features.some((item) => item.declaredBy.startsWith("nylorun-"));
120
+ lines.push(` ${agent.agent}: ${plugins ? "declares the Runtime's plugins (agent-folder/3)" : agent.declared ? "declares its engine features (agent-folder/2)" : "every engine feature by default (agent-folder/1)"}`);
120
121
  for (const item of agent.features) {
121
122
  const adds = [
122
123
  ...(item.tools.length > 0 ? [`tools ${item.tools.join(", ")}`] : []),
@@ -1,5 +1,5 @@
1
1
  import type { StackDeps } from "../stack/commands.js";
2
- export declare const migrateFormatUsage = "nylorun migrate folder <dir> --to 2\n\nMakes the agent folder <dir> agent-folder/2, in place: it adds format: agent-folder/2 to its\nAGENT.md, and to it and each subagent's AGENT.md the engine: block that declares every engine\nfeature the folder gets today by default (the sandbox tools, save_artifact and the outputs folder\nwhen runtime.json has a computer, read_artifact, tool search). Nothing the model reads or may\ncall changes, which it checks before it writes; then remove the lines the agent does not need.\nReads no Runtime.";
2
+ export declare const migrateFormatUsage = "nylorun migrate folder <dir> --to 2|3\n\nMakes the agent folder <dir> agent-folder/2, in place: it adds format: agent-folder/2 to its\nAGENT.md, and to it and each subagent's AGENT.md the engine: block that declares every engine\nfeature the folder gets today by default (the sandbox tools, save_artifact and the outputs folder\nwhen runtime.json has a computer, read_artifact, tool search). Nothing the model reads or may\ncall changes, which it checks before it writes; then remove the lines the agent does not need.\n\nWith --to 3, makes an agent-folder/2 folder agent-folder/3 (ADR-106): the Runtime's plugins\n(plugins: [nylorun-memory, ...]) in place of memory, loop, runtime.selfWake and engine's\nsandbox, artifacts and triggers, with mcpServers.nylorun turning off the tools the folder left\nout, and memory's instructions moved to the end of AGENT.md's body. Every agent keeps the same\ntools and features, which it checks before it writes; the words the model reads become the\nplugins'. Reads no Runtime.";
3
3
  /** The `engine:` block that keeps what an agent-folder/1 agent gets, as YAML lines. */
4
4
  export declare function engineLines(computer: boolean): string[];
5
5
  /**
@@ -8,5 +8,5 @@ export declare function engineLines(computer: boolean): string[];
8
8
  * none). Undefined when it has no frontmatter.
9
9
  */
10
10
  export declare function withFrontmatter(text: string, lines: readonly string[], format?: string): string | undefined;
11
- /** `nylorun migrate folder <dir> --to 2` */
11
+ /** `nylorun migrate folder <dir> --to 2|3` */
12
12
  export declare function migrateFormatCommand(deps: StackDeps, dir: string, to: string): Promise<number>;
@@ -17,18 +17,25 @@ import { readFile, writeFile } from "node:fs/promises";
17
17
  import { join, relative } from "node:path";
18
18
  import { AGENT_FOLDER_FILE, checkFolder } from "@nylorun/agents";
19
19
  import { SANDBOX_TOOL_NAMES } from "@nylorun/core/define";
20
- import { previewTurn } from "@nylorun/core/engine";
20
+ import { previewTurn, runtimeToolOf } from "@nylorun/core/engine";
21
+ import { folderV3Edit } from "@nylorun/core/folder";
21
22
  import { CliError } from "../errors.js";
22
23
  import { diagnosticLines, packed } from "./folder.js";
23
24
  import { usageError } from "./runtime.js";
24
- export const migrateFormatUsage = `nylorun migrate folder <dir> --to 2
25
+ export const migrateFormatUsage = `nylorun migrate folder <dir> --to 2|3
25
26
 
26
27
  Makes the agent folder <dir> agent-folder/2, in place: it adds format: agent-folder/2 to its
27
28
  AGENT.md, and to it and each subagent's AGENT.md the engine: block that declares every engine
28
29
  feature the folder gets today by default (the sandbox tools, save_artifact and the outputs folder
29
30
  when runtime.json has a computer, read_artifact, tool search). Nothing the model reads or may
30
31
  call changes, which it checks before it writes; then remove the lines the agent does not need.
31
- Reads no Runtime.`;
32
+
33
+ With --to 3, makes an agent-folder/2 folder agent-folder/3 (ADR-106): the Runtime's plugins
34
+ (plugins: [nylorun-memory, ...]) in place of memory, loop, runtime.selfWake and engine's
35
+ sandbox, artifacts and triggers, with mcpServers.nylorun turning off the tools the folder left
36
+ out, and memory's instructions moved to the end of AGENT.md's body. Every agent keeps the same
37
+ tools and features, which it checks before it writes; the words the model reads become the
38
+ plugins'. Reads no Runtime.`;
32
39
  /** The `engine:` block that keeps what an agent-folder/1 agent gets, as YAML lines. */
33
40
  export function engineLines(computer) {
34
41
  return computer
@@ -73,10 +80,89 @@ function seen(manifest) {
73
80
  const one = (item) => ({ system: item.system, tools: item.tools });
74
81
  return JSON.stringify({ root: one(preview), pinned: preview.pinned, agents: Object.fromEntries(Object.entries(preview.agents).map(([id, item]) => [id, one(item)])) });
75
82
  }
76
- /** `nylorun migrate folder <dir> --to 2` */
83
+ /** What each agent of a compiled folder may call, by the effects of its tools, and what is pinned. */
84
+ function effects(manifest) {
85
+ if ("kind" in manifest.harness)
86
+ return "";
87
+ const preview = previewTurn(manifest);
88
+ // The skill tools come with the plugins' skills (memory, triggers), so they are left out here.
89
+ const skillTools = new Set(["load_skill", "read_skill_resource"]);
90
+ const tools = (item) => item.tools
91
+ .map((tool) => runtimeToolOf(tool.name) ?? tool.name)
92
+ .filter((name) => !skillTools.has(name))
93
+ .sort();
94
+ return JSON.stringify({ root: tools(preview), pinned: preview.pinned.length, agents: Object.fromEntries(Object.entries(preview.agents).map(([id, item]) => [id, tools(item)])) });
95
+ }
96
+ /** `nylorun migrate folder <dir> --to 3` (ADR-106). */
97
+ async function migrateToV3(deps, dir) {
98
+ const cwd = deps.cwd ?? process.cwd();
99
+ const where = relative(cwd, dir) || ".";
100
+ const before = await checkFolder(await packed(dir));
101
+ if (!before.manifest) {
102
+ for (const line of diagnosticLines(dir, cwd, before.diagnostics))
103
+ deps.err(line);
104
+ throw new CliError(`${where} does not compile: fix it first (nylorun check ${where}).`, 1);
105
+ }
106
+ if (before.compiler === "agent-folder/3") {
107
+ deps.out(`${where} is agent-folder/3 already: nothing to do.`);
108
+ return 0;
109
+ }
110
+ if (before.compiler !== "agent-folder/2")
111
+ throw new CliError(`${where} is ${before.compiler}: migrate it to agent-folder/2 first (nylorun migrate folder ${where} --to 2).`, 1);
112
+ const harness = before.manifest.harness;
113
+ if ("kind" in harness)
114
+ throw new CliError(`${where} is a flow: migrate each agent folder it holds instead.`, 1);
115
+ const read = async (path) => readFile(join(dir, ...path.split("/")), "utf8");
116
+ const edits = new Map();
117
+ const runtimeJson = await read("runtime.json").catch(() => undefined);
118
+ const root = folderV3Edit({ agentMd: await read(AGENT_FOLDER_FILE), ...(runtimeJson === undefined ? {} : { runtimeJson }), role: "root" });
119
+ if (!root.ok)
120
+ throw new CliError(`${join(where, AGENT_FOLDER_FILE)}: ${root.reason}.`, 1);
121
+ edits.set(AGENT_FOLDER_FILE, root.agentMd);
122
+ if (root.runtimeJson !== undefined && root.runtimeJson !== runtimeJson)
123
+ edits.set("runtime.json", root.runtimeJson);
124
+ for (const tool of harness.tools ?? []) {
125
+ if (!tool.agent)
126
+ continue;
127
+ const path = `agents/${tool.name}/${AGENT_FOLDER_FILE}`;
128
+ const edited = folderV3Edit({ agentMd: await read(path), role: "subagent" });
129
+ if (!edited.ok)
130
+ throw new CliError(`${join(where, path)}: ${edited.reason}.`, 1);
131
+ edits.set(path, edited.agentMd);
132
+ }
133
+ const pack = await packed(dir);
134
+ const encoder = new TextEncoder();
135
+ const files = new Map(pack.files);
136
+ const entries = pack.entries.map((entry) => {
137
+ const text = edits.get(entry.path);
138
+ if (text === undefined)
139
+ return entry;
140
+ const bytes = encoder.encode(text);
141
+ const source = files.get(entry.path);
142
+ files.set(entry.path, { ...source, size: bytes.byteLength, read: async () => bytes });
143
+ return { ...entry, size: bytes.byteLength, sha256: sha256Hex(bytes) };
144
+ });
145
+ const after = await checkFolder({ ...pack, entries, files });
146
+ if (!after.manifest) {
147
+ for (const line of diagnosticLines(dir, cwd, after.diagnostics))
148
+ deps.err(line);
149
+ throw new CliError(`${where} would not compile as agent-folder/3: nothing was written.`, 1);
150
+ }
151
+ if (effects(after.manifest) !== effects(before.manifest))
152
+ throw new CliError(`${where} as agent-folder/3 would change what its agents may call: nothing was written.`, 1);
153
+ for (const [path, text] of edits)
154
+ await writeFile(join(dir, ...path.split("/")), text);
155
+ for (const path of edits.keys())
156
+ deps.out(`wrote ${join(where, path)}`);
157
+ deps.out(`${where} is agent-folder/3: its agents keep their tools, now named nylorun__<tool>, with the plugins' words. Check what each gets with nylorun check --explain ${where}, and update instructions that name the tools.`);
158
+ return 0;
159
+ }
160
+ /** `nylorun migrate folder <dir> --to 2|3` */
77
161
  export async function migrateFormatCommand(deps, dir, to) {
162
+ if (to === "3" || to === "agent-folder/3")
163
+ return migrateToV3(deps, dir);
78
164
  if (to !== "2" && to !== "agent-folder/2")
79
- throw usageError(`--to takes 2 (agent-folder/2).\n${migrateFormatUsage}`);
165
+ throw usageError(`--to takes 2 (agent-folder/2) or 3 (agent-folder/3).\n${migrateFormatUsage}`);
80
166
  const cwd = deps.cwd ?? process.cwd();
81
167
  const where = relative(cwd, dir) || ".";
82
168
  const before = await checkFolder(await packed(dir));
@@ -75,7 +75,7 @@ export async function migrateCommand(deps, args) {
75
75
  return 0;
76
76
  }
77
77
  if (version === "folder") {
78
- // `--to 2`: an agent folder made agent-folder/2 in place (ADR-100).
78
+ // `--to 2` or `--to 3`: an agent folder made agent-folder/2 (ADR-100) or agent-folder/3 (ADR-106) in place.
79
79
  const to = rest.indexOf("--to");
80
80
  if (to < 0)
81
81
  return migrateFolderCommand(deps, rest);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nylorun",
3
- "version": "0.26.0-beta",
3
+ "version": "0.27.0-beta",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Set up and run local Nylorun Tenants (Runtime and Studio) with Docker Compose, and act on a Tenant through its Runtime and Management APIs",
@@ -30,9 +30,9 @@
30
30
  "prepack": "npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "@nylorun/admin": "0.19.11-beta",
34
- "@nylorun/agents": "0.34.0-beta",
35
- "@nylorun/core": "0.35.0-beta"
33
+ "@nylorun/admin": "0.19.12-beta",
34
+ "@nylorun/agents": "0.35.0-beta",
35
+ "@nylorun/core": "0.36.0-beta"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@earendil-works/pi-ai": "1.3.0",
@@ -46,7 +46,7 @@
46
46
  "nylo": "dist/nylo.js"
47
47
  },
48
48
  "nylorun": {
49
- "runtime": "0.41.0-beta",
50
- "studio": "0.35.4-beta"
49
+ "runtime": "0.42.0-beta",
50
+ "studio": "0.35.5-beta"
51
51
  }
52
52
  }