@nylorun/agents 0.14.0-beta → 0.16.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 +112 -0
- package/README.md +193 -121
- package/dist/access.d.ts +6 -26
- package/dist/access.js +1 -26
- package/dist/files.d.ts +31 -0
- package/dist/files.js +60 -0
- package/dist/http.d.ts +0 -5
- package/dist/http.js +0 -8
- package/dist/index.d.ts +8 -13
- package/dist/index.js +4 -6
- package/dist/plugins/load.d.ts +3 -2
- package/dist/plugins/load.js +40 -100
- package/dist/plugins/plugin.d.ts +6 -1
- package/dist/plugins/plugin.js +20 -7
- package/dist/reads.d.ts +17 -0
- package/dist/reads.js +17 -0
- package/dist/sandboxes.d.ts +29 -0
- package/dist/sandboxes.js +10 -1
- package/dist/session-client.d.ts +91 -114
- package/dist/session-client.js +79 -109
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/load.d.ts +14 -3
- package/dist/skills/load.js +50 -32
- package/dist/skills/skills.d.ts +6 -4
- package/dist/skills/skills.js +17 -10
- package/package.json +3 -3
- package/dist/action-handler.d.ts +0 -63
- package/dist/action-handler.js +0 -279
- package/dist/delivery-token.d.ts +0 -62
- package/dist/delivery-token.js +0 -159
- package/dist/execute-action.d.ts +0 -16
- package/dist/execute-action.js +0 -288
- package/dist/plugins/launch.d.ts +0 -17
- package/dist/plugins/launch.js +0 -71
- package/dist/sandbox/client.d.ts +0 -63
- package/dist/sandbox/client.js +0 -29
- package/dist/sandbox/index.d.ts +0 -2
- package/dist/sandbox/index.js +0 -1
- package/dist/served-definitions.d.ts +0 -20
- package/dist/served-definitions.js +0 -100
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
+
## 0.16.0-beta
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 4bd2a0b: **Flows run no code: workflow manifest v3 (manifest-only agents, step M2).** A flow agent is data: each stage gets the previous stage's output, a switch reads it, a map runs over it and a loop asks a verifier agent. See MIGRATION.md for what replaces each function.
|
|
8
|
+
|
|
9
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`):** stage `input` functions, `switch` `on`, loop `verify` functions and `decide` are removed; a builder option that names one is refused with what replaces it. `.loop()` takes a verifier agent and a required `max`. New `.pipe(...children)` adds one stage per child; `.step()` is a deprecated alias (`NYLORUN_DEP_STEP`). `Chain`, `Switch`, `Parallel`, `Map`, `Loop`, `withInstructions`, `withoutTools`, `isSlot`, `functionKey` and the `StageArgs`, `LoopVerifyFn`, `LoopDecideArgs`, `LoopChoice` and v1 workflow types are removed. `Agent.from` for a flow takes tool nodes only.
|
|
10
|
+
- **Breaking (`@nylorun/core`):** workflow manifests are `workflowSchemaVersion: 3`; no node carries `input`, a switch has no `on`, a loop's `verify` is an agent and `max` is required. A v1 or v2 manifest is refused with a message naming the change. The `fn` and `verify` Actions and effect kinds, and the `loop.decided` event, are removed. `WorkflowManifestV2` / `WorkflowNodeV2` / `isWorkflowManifestV2` are now `WorkflowManifest` / `WorkflowNode` / `isWorkflowManifest`.
|
|
11
|
+
- **Breaking (`@nylorun/harness`):** the flow engine is `flow-3` and runs only v3 manifests; v1 and v2 engines, `agentTurnValue` and the `fn` / `verify` effect kinds are removed. A switch picks the case named by the previous output or its `route` field, a map runs over an array or an `items` array, and a loop retries with its verifier's feedback until `max`. An `agent` effect carries the flow's input as `flowInput` when the stage's input differs.
|
|
12
|
+
- **Breaking (`@nylorun/runtime`):** no `fn` or `verify` Actions are offered or delivered. An agent stage's message shows the flow's input as the original request before its own input, and each verifier verdict is recorded as `loop.verified`.
|
|
13
|
+
- `@nylorun/studio`: the workflow tree draws v3 manifests (a loop shows its verifier agent and `max`); the loop timeline drops decide outcomes, and `loop.verified` shows the feedback.
|
|
14
|
+
|
|
15
|
+
- 713e676: **Remote MCP servers only (blueprint D47).** Nylorun accepts `streamable-http` and `sse` MCP servers, declared by URL and reached through the gates; stdio servers and plugin roots are gone. See MIGRATION.md.
|
|
16
|
+
|
|
17
|
+
- **Breaking (`@nylorun/core`):** `McpServerManifest` and the manifest schema keep only `streamable-http` and `sse`. A `stdio` server is refused by `.mcp({...})` (`McpError`, code `mcp.stdio`), by `Agent.from` and by the wire schema, all with one message (`stdioMcpRefusal`): "MCP server 'x' uses stdio; Nylorun accepts remote MCP servers only (streamable-http or sse). Run the server behind an HTTP transport and declare its URL." `PutAgentRequest` loses `pluginRoots`, `CapabilityDeclaration` loses `pluginRoot`, and the Harness API's `RunRouting` loses `pluginRoots`.
|
|
18
|
+
- **Breaking (`@nylorun/agents`):** `.plugin()` and `plugin()` throw `PluginError` (code `plugin.mcp-stdio`) for a stdio server in a plugin's `mcp.json`; its remote servers and skills load as before. `saveAgent` no longer sends plugin roots. `prepareStdioLaunch`, `expandPluginPlaceholders` and `StdioLaunch` are removed.
|
|
19
|
+
- **Breaking (`@nylorun/runtime`):** no stdio MCP launcher: `PUT /v1/agents/:id` refuses a stdio server (`400`) and `pluginRoots`. `TenantConfig.childEnv`, `TenantPaths.pluginData` and `tmp`, `tenantChildEnvironment`, `startEphemeralRuntime({ baseline })` and `configForFactory`'s `baseline` and `hostConfig` are removed; the harness service no longer takes `childEnv` or `paths.pluginData`.
|
|
20
|
+
- `nylorun`: the local stack no longer mounts the Host root's `plugins/` into the runtime and harness containers, nor the Tenant's `plugin-data/`, `home/` and `tmp/` into the harness, which now mounts only `sandboxes/`.
|
|
21
|
+
|
|
22
|
+
- c135267: **Action endpoints are removed (manifest-only agents, M6).** The Runtime runs no code of yours during a session: an agent's tools are HTTP tools, remote MCP servers, agents used as tools and the Runtime's built-ins. Protocol stays 8; the `action-endpoints` feature is gone, so a client that requires it is refused. See MIGRATION.md, "Action endpoints are removed".
|
|
23
|
+
|
|
24
|
+
- **Breaking (`@nylorun/core`):** the `Action`, endpoint (`PutEndpointsRequest`, `Endpoint`, `EndpointHealth`, …) and delivery schemas, `SIGNATURE_HEADER`, `OUTCOME_HEADER`, `DELIVERY_TOKEN_TYPE` and the `action.*` events (`action.pending`, `.delivered`, `.delivery_failed`, `.completed`, `.uncertain`) are removed, and `ToolDefinition.background` with them. `ActionOutcome` is renamed `EffectOutcome`. Tenant status loses `checks.endpoints`, `agents[].registered` and `agents[].endpoint`, and `counts.pendingActions`; the session view loses `actions`. A `turn.paused` interaction carries the tool call's `callId`. New `codeToolsOf` and `codeToolRefusal` name a definition's tools that would run your code. The Harness API is v2 (`HARNESS_API_VERSION = 2`): `TurnStart.options.holdMs` and `effect.resolved` are removed.
|
|
25
|
+
- **Breaking (`@nylorun/harness`):** held runs are gone: `createHarness` loses `holdMs`, and `apiHost` its `hold` option.
|
|
26
|
+
- **Breaking (`@nylorun/agents`):** `createActionHandler`, `executeAction`, `createActionSandbox`, `definitionDeclaresSandbox`, `isActionSandboxTool` and the `Action`, `ActionOutcome`, `ActionHandler`, `ActionHandlerOptions`, `RegisterOptions`, `ExecuteActionOptions` and `ExecutableDefinition` types are removed. `saveAgent` refuses a code tool (`tool({ run })`) or a flow tool stage before sending; its `implementationVersion` is optional (`NYLORUN_IMPLEMENTATION_VERSION`, else `dev`).
|
|
27
|
+
- **Breaking (`@nylorun/runtime`):** `/v1/endpoints` and `/v1/actions/*` answer `404`; delivery tokens, the deliverer, background tools, held runs (`TenantConfig.actionHoldMs`), `DurableExecution.deliver`, the Restate `NylorunAction` object, the `action_result` wake and the gates service's `/nylorun/v1/deliveries` are removed, and a migration drops the `actions` and `endpoints` tables. `PUT /v1/agents/:id` refuses a definition with a code tool or a flow tool stage (`400`); a tool the Runtime cannot run fails with `tool.unavailable`. The fixture model answers in text when the agent offers no `lookup_order` tool.
|
|
28
|
+
- **Breaking (`@nylorun/cli`):** `nylo endpoints` is removed (a usage error that says why); `nylo status` shows uncertain effects instead of pending Actions.
|
|
29
|
+
- **Breaking (`@nylorun/create-agent`):** the starter saves its agent with `saveAgent` and runs no server: no Action endpoint, `PORT` or `NYLORUN_ACTIONS_URL`. Its assistant has no tools, with a commented `http()` tool to start from.
|
|
30
|
+
- `nylorun`: the local stack's comments speak of MCP servers and HTTP tools on this machine, not Action endpoints.
|
|
31
|
+
- `@nylorun/studio`: the `action.*` event views and delivery status are removed; the chat shows `tool.completed`, and the Agent Manifest tab lists tools without a target as code tools.
|
|
32
|
+
|
|
33
|
+
- d36f0d9: **Hooks are removed; manifests are v5 (manifest-only agents, step M1).** The Runtime no longer calls the developer's code before or after a turn or a model call. See MIGRATION.md for what replaces each use.
|
|
34
|
+
|
|
35
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`):** `.beforeTurn()`, `.beforeModel()`, `.afterModel()`, `.afterTurn()`, the deprecated `.before()` / `.after()`, a capability's `before` / `after`, and the `Patch`, `Decision`, `TurnDecision`, `BeforeHook`, `AfterHook`, `HookScope` types and `runHookPoint` / `hooksFrom` helpers are removed. A capability that still passes `before` or `after` is refused with `hooks were removed: …`.
|
|
36
|
+
- **Breaking (`@nylorun/core`):** `manifestSchemaVersion` is 5. `capabilities[].hooks` is gone; a manifest that names it, or a v3/v4 manifest, is refused with a message naming the change. The `hook` Action and the `hook` effect kind of the Harness API are removed.
|
|
37
|
+
- **Breaking (`@nylorun/harness`):** the turn loop runs no hooks; the turn state a checkpoint carries is `{ turnId }`, and the engine version is `hosted-4`, so checkpoints of earlier engines are refused.
|
|
38
|
+
- `@nylorun/runtime`: no `hook` Actions are offered or delivered.
|
|
39
|
+
- `@nylorun/studio`: the Agent Manifest tab drops the Hooks count and the turn lifecycle.
|
|
40
|
+
|
|
41
|
+
- 107b07d: **Skills are files the Runtime holds and serves itself (track R2 M4).** Breaking: a skill's manifest names every file of its folder, and the skill tools no longer run in the developer's process. The protocol stays at 8 until the track ships.
|
|
42
|
+
|
|
43
|
+
- `@nylorun/core`: `SkillManifest` gains `files`, each path of the skill's folder (`SKILL.md` required, `/`-separated, no `..`, at most 500 files) mapped to `sha256:<hex>`, so the manifest hash pins them. `skillRecords` and `SkillRecord` are gone; a declaration's `skillFiles` holds the bytes to upload (`SkillFileSource`). `load_skill` and `read_skill_resource` keep their names and input schemas but fail with `skills.runtime-only` outside a Runtime. New `DefinitionFileViewSchema`, error code `definition_files_missing`, Harness API request `definition.file`, and `definitionFilesOf`, `isSkillTool` and the definition-file limits. A top-level `functions` key is reserved and refused ("Functions are not available yet").
|
|
44
|
+
- `@nylorun/runtime`: `PUT /v1/files/sha256:<hex>` stores a definition file (application key; at most 10 MiB; a body of another hash is `400`; `201` stored, `200` held already) in the Object store at `definitions/sha256/<hex>`, and `HEAD` says whether the Tenant holds one. New tables `definition_files` and `definition_file_uses` (migration `0013_definition_files`). `PUT /v1/agents/{id}` refuses a definition, nested agents and flow agents included, that names a file the Tenant lacks (`400 definition_files_missing`). Core serves `load_skill` (the `SKILL.md` body, the other files' paths, and `sandboxPath` with a sandbox) and `read_skill_resource` (text files only) from those files, with no Action. A session's sandbox gets each skill's files read-only under `/skills/<name>/` before the first call that opens it, and the sandbox's instructions name them; pod sandboxes mount an `emptyDir` at `/skills`. Unused files are not deleted yet.
|
|
45
|
+
- `@nylorun/agents`: `.skills()`, `skills()` and `.plugin()` read every file of a skill's folder, binary included (not `.git/`, `node_modules/`, OS files or `.env` files), and hash it; a file over 10 MiB or more than 500 files fail the build. `saveAgent` uploads the files the Runtime lacks before the definition; `client.files` (`has`, `upload`, `ensure`) does it by hand.
|
|
46
|
+
- `@nylorun/harness`: tests only.
|
|
47
|
+
- `@nylorun/studio`: the agent's manifest lists each skill's files.
|
|
48
|
+
|
|
49
|
+
### Minor Changes
|
|
50
|
+
|
|
51
|
+
- a64aaca: **HTTP in flows (manifest-only agents, after M2 and M3).** An `http()` tool is a flow stage, and `http({ url })` is a Loop's HTTP verifier; the Runtime makes both requests through its Tool Gate, with no Action endpoint.
|
|
52
|
+
|
|
53
|
+
- `@nylorun/core`: an HTTP tool may be a stage in `.pipe()`, a switch case, a Map item or a Loop body; its tool node carries its `http` target and binds nothing. The build refuses an HTTP stage whose input is known to be the wrong type (`flow.input-mismatch`, e.g. after an agent with no `.output()`) and `approval: "always"` on one (`flow.approval-unsupported`). `http()` without a name and an input returns an `HttpTarget`, an HTTP verifier: `.loop(body, { verify: http({ url, method?, credential?, timeoutMs? }), max })`, in the manifest `loop.verify: { http }`. `fn` and `command` verify targets are refused ("Functions are not available yet"). New `flowHttpTarget()` finds an HTTP stage or verifier by stage key; `isHttpTarget()`, `WorkflowHttpVerify` and `WorkflowLoopVerify` are exported.
|
|
54
|
+
- `@nylorun/harness`: the flow engine checks an HTTP stage's input against its schema (`tool.invalid-input`), runs it as a `tool` effect and fails the stage on a failed outcome (`http.status`, `http.timeout`, `tool.invalid-output`, …). An HTTP verifier is a `tool` effect with `{ input, output, iteration }` and `context.role: "verify-http"`; a non-verdict or a failed request is `loop.verify-failed`. A Loop body that starts with an HTTP stage is retried with the Loop's input.
|
|
55
|
+
- `@nylorun/agents`: `http()` builds HTTP verifiers too.
|
|
56
|
+
- `@nylorun/runtime`: a flow's HTTP stages and verifiers are executed like an agent's HTTP tool: address policy, the flow session's vault credential, `Nylorun-Session-Id`/`-Turn-Id`/`-Agent-Id` (the flow agent's id) and the flow effect id as `Idempotency-Key`, run once at the gates service (`POST /nylorun/v1/http-calls` takes `tool: { sessionId?, stage }`) and `uncertain` when the answer is lost. An HTTP verifier's verdict is recorded as `loop.verified`.
|
|
57
|
+
- `@nylorun/studio`: the workflow tree shows HTTP stages and HTTP verifiers with their method and URL.
|
|
58
|
+
|
|
59
|
+
- 40b7648: **HTTP tools and static approval (manifest-only agents, M3).** A tool can be one HTTP request the Runtime makes through its Tool Gate, with no Action endpoint; code tools keep working.
|
|
60
|
+
|
|
61
|
+
- `@nylorun/core`: `ToolManifest` gains `http` (`url`, `method` `POST`/`PUT`/`PATCH`, `credential`, `timeoutMs` up to 300000) and `approval` (`never`/`always`, HTTP tools only); a tool is never both an agent and an HTTP request, and `fn` and `command` are refused ("Functions are not available yet"). Remote MCP servers take `approval`. `http()` builds an HTTP tool, `httpToolOf()` reads one; `SESSION_ID_HEADER`, `TURN_ID_HEADER` and `AGENT_ID_HEADER` name the headers it sends. `Agent.from` rebuilds HTTP tools without an implementation; an HTTP tool is refused as a flow stage.
|
|
62
|
+
- `@nylorun/harness`: hosted HTTP tools keep their target, and `approval: "always"` (an HTTP tool's, or `DurableSessionTool.approval` for a remote MCP server's tools) pauses each call for approval. **Breaking:** `HarnessExecutors.recovers.remoteMcp` is renamed `recovers.tool`.
|
|
63
|
+
- `@nylorun/agents`: exports `http` and the identity header constants.
|
|
64
|
+
- `@nylorun/runtime`: the Tool Gate runs HTTP tool calls (`POST /nylorun/v1/http-calls` at the gates service, or in process): the input as JSON under the Host's address policy, the session's vault credential bound to the URL, `Nylorun-Session-Id`/`-Turn-Id`/`-Agent-Id` and the effect id as `Idempotency-Key`. A keyed call runs once (`tool_crossings`), so a re-send after a takeover joins it and one lost with the gateway is `uncertain`. Non-2xx answers, timeouts, refused addresses, missing credentials and output mismatches are tool errors the model sees. The credential resolver is asked with `target.kind: "http"` and the tool's `credential` name.
|
|
65
|
+
- `@nylorun/studio`: the Agent Manifest tab lists HTTP tools with their method and URL, and marks tools and MCP servers that wait for approval.
|
|
66
|
+
|
|
67
|
+
### Patch Changes
|
|
68
|
+
|
|
69
|
+
- Pin core to the tested release.
|
|
70
|
+
- Updated dependencies [4bd2a0b]
|
|
71
|
+
- Updated dependencies [a64aaca]
|
|
72
|
+
- Updated dependencies [40b7648]
|
|
73
|
+
- Updated dependencies [713e676]
|
|
74
|
+
- Updated dependencies [c135267]
|
|
75
|
+
- Updated dependencies [d36f0d9]
|
|
76
|
+
- Updated dependencies [107b07d]
|
|
77
|
+
- @nylorun/core@0.15.0-beta
|
|
78
|
+
|
|
79
|
+
## 0.15.0-beta
|
|
80
|
+
|
|
81
|
+
### Major Changes
|
|
82
|
+
|
|
83
|
+
- 98b0d37: **Protocol 8: the Runtime API and the Management API take separate keys (Runtime and Management APIs, step A4).** Upgrade every package together; `nylorun`, `@nylorun/cli` and Studio already use management keys (A3).
|
|
84
|
+
|
|
85
|
+
- **Breaking (`@nylorun/runtime`): `/v1/tenant/*` takes only a management key.** An application key there, alone or acting for a subject, is `403 key_role_mismatch`; a management key acting for a subject is `403 subject_invalid`. This covers the Tenant's status, seed and reset, models, providers, usage and budgets, sandbox and artifact settings, application keys, vaults and signing keys. A management key on any other route but `/v1/me` and the public `/v1/access/jwks` is `403 key_role_mismatch`.
|
|
86
|
+
- **Breaking (`@nylorun/runtime`): vaults and signing keys moved.** They are at `/v1/tenant/vaults…` (including `…/oauth/start`) and `/v1/tenant/signing-keys…`; `/v1/vaults…` and `/v1/access/signing-keys…` are gone, with no alias. Opening a session with `vaultIds` is unchanged, as are `GET /v1/oauth/callback` and `GET /v1/access/jwks`.
|
|
87
|
+
- **Breaking (`@nylorun/core`, `@nylorun/runtime`): `tenant:settings` is retired.** It leaves `SUBJECT_SCOPES`; `Nylorun-Scopes` may still name it and it grants nothing. `/v1/tenant/models` and `/v1/tenant/providers` no longer admit `agents:write` subjects: apps don't read the model catalog.
|
|
88
|
+
- **Breaking (`@nylorun/agents`):** the vault methods (`createVault`, `listVaults`, `getVault`, `deleteVault`, `createCredential`, `listCredentials`, `getCredential`, `rotateCredential`, `deleteCredential`) and `client.access.signingKeys` / `SigningKeysClient` are removed; use `admin.vaults` and `admin.signingKeys` from `@nylorun/admin`'s `createManagementClient`. `client.access.jwks()` stays.
|
|
89
|
+
- `@nylorun/core`: `PROTOCOL_VERSION` is 8 and `HOST_PROTOCOL` 4–8, with the required feature `management-api`. Runtime API routes keep their request and response shapes.
|
|
90
|
+
- `@nylorun/runtime`: `startEphemeralRuntime` registers a management key (`managementKey`, the key `bootstrap`).
|
|
91
|
+
|
|
92
|
+
### Minor Changes
|
|
93
|
+
|
|
94
|
+
- c66d8ed: Add optional session reads and a resumable model-ledger export: pinned manifests, usage totals, model calls, and opt-in session/history/sandbox pages (Host feature `session-reads`), and `GET /v1/tenant/calls/model` on the Management API (Host feature `calls-export`). Usage and model calls take an application key acting as itself; the export takes a management key. Runtime reads use a separate bounded, read-only Drizzle pool. The additive migration `0012_session_reads` preserves unknown legacy creation times and usage quality; the export uses safe transaction order without skipping committed rows. `@nylorun/agents` adds `client.sessions.page()`, `session.manifest()`, `session.usage()`, `session.modelCalls()`, `session.history({ limit })` and `client.sandboxes.page()`; `@nylorun/admin` adds `models.exportCalls()`. Legacy unpaged responses are unchanged.
|
|
95
|
+
|
|
96
|
+
### Patch Changes
|
|
97
|
+
|
|
98
|
+
- b28bdd7: **Local MCP servers work on a local Tenant, and a server that does not connect shows.** Additive; the protocol stays at 7.
|
|
99
|
+
|
|
100
|
+
- `@nylorun/runtime`: remote MCP servers (`streamable-http`, `sse`) are reached under the Host's address policy, as Action endpoints are (`NYLORUN_ENDPOINT_*`, `tenant/outbound.ts`). In the local Docker stack `localhost`, `127.0.0.1` and `[::1]` now mean the machine that runs Docker (`host.docker.internal`), so `.mcp({ x: { type: "streamable-http", url: "http://localhost:3002/x" } })` connects where it used to fail with `fetch failed`. With `NYLORUN_ENDPOINT_PRIVATE=refuse` a server on a private address is refused; with `NYLORUN_ENDPOINT_HTTP=refuse` an `http` server is refused. Redirects are still not followed. A connection failure now names its cause (`connect ECONNREFUSED …`) instead of `fetch failed`. This applies in the gateway, a harness process and an in-process Tenant. `guardedFetch` takes `stream: true`: the answer streams, unbounded, with no timeout but the caller's signal.
|
|
101
|
+
- `@nylorun/core`: new session event `mcp.discovered`, recorded once on the session's first turn with the MCP snapshot: one entry per declared server with `outcome` (`connected`, `refused`, `failed`), `message` and the number of `tools` it added (`McpDiscoveredPayloadSchema`, `McpServerOutcomeSchema`). A server that does not connect adds no tools for the session's life; this is where that shows in the event log, beside `mcpDiagnostics`.
|
|
102
|
+
- `@nylorun/agents`: `.plugin()` and `plugin()` emit a process warning (`NylorunPluginWarning`, the diagnostic's code) for each part of the package they skip, so building or registering the agent says when a plugin's MCP server was dropped. The `plugin.mcp-server-skipped` message now says why: for example, plain `http` is accepted only for `localhost`, `127.0.0.1` or `[::1]`.
|
|
103
|
+
- `@nylorun/studio`: the event list labels `mcp.discovered` and summarizes each server's outcome.
|
|
104
|
+
|
|
105
|
+
- Pin core to the tested release.
|
|
106
|
+
- Updated dependencies [3b3bdc6]
|
|
107
|
+
- Updated dependencies [6576e12]
|
|
108
|
+
- Updated dependencies [b28bdd7]
|
|
109
|
+
- Updated dependencies [cc107b1]
|
|
110
|
+
- Updated dependencies [7f763c3]
|
|
111
|
+
- Updated dependencies [98b0d37]
|
|
112
|
+
- Updated dependencies [c66d8ed]
|
|
113
|
+
- @nylorun/core@0.14.0-beta
|
|
114
|
+
|
|
3
115
|
## 0.14.0-beta
|
|
4
116
|
|
|
5
117
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -1,49 +1,85 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Runtime API client package: definition authoring and a session client. The Tenant's
|
|
4
|
+
settings, models, vaults, signing keys and application keys are the Management
|
|
5
|
+
API's, through [`@nylorun/admin`](../admin/README.md). Depends only on `@nylorun/core` among Nylorun
|
|
5
6
|
packages. A developer application's production tree should contain only this
|
|
6
7
|
package and `@nylorun/core` from Nylorun. Vocabulary:
|
|
7
8
|
[runtime/src/CONTEXT.md](../runtime/src/CONTEXT.md).
|
|
8
9
|
|
|
9
|
-
## Application entry
|
|
10
|
+
## Application entry: save your agents
|
|
10
11
|
|
|
11
12
|
```ts
|
|
12
13
|
// src/main.ts
|
|
13
|
-
import {
|
|
14
|
-
import { createActionHandler } from "@nylorun/agents";
|
|
14
|
+
import { createClient } from "@nylorun/agents";
|
|
15
15
|
import { agents } from "../agents/index.js";
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
createServer(actions.node).listen(3001); // or actions.fetch in Hono, Next.js, Workers, Bun
|
|
20
|
-
await actions.register({ url });
|
|
17
|
+
const client = createClient();
|
|
18
|
+
for (const agent of agents) await client.saveAgent(agent);
|
|
21
19
|
```
|
|
22
20
|
|
|
23
|
-
The Runtime
|
|
24
|
-
|
|
25
|
-
(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
21
|
+
The Runtime runs each agent from its manifest and the files saved with it (skills), and
|
|
22
|
+
never calls your code during a session. Your services are reached as tools: [HTTP
|
|
23
|
+
tools](#http-tools) and remote MCP servers. `saveAgent` refuses, before sending anything, an
|
|
24
|
+
agent with a tool that would run your code (`tool({ run })`) or a flow agent with a tool
|
|
25
|
+
stage: make it an `http()` tool or serve it from a remote MCP server. `tool({ run })` still
|
|
26
|
+
runs in the local engine (`@nylorun/harness/run`). `implementationVersion` defaults to
|
|
27
|
+
`NYLORUN_IMPLEMENTATION_VERSION`, else `dev`.
|
|
28
|
+
|
|
29
|
+
`createClient()` finds the Runtime through the two `NYLORUN_*` variables or the Project link
|
|
30
|
+
that `npx nylorun start` writes; with neither, it fails with `connection_missing` and names
|
|
31
|
+
those steps. Action endpoints (`createActionHandler`), and before them `connectAgents` and
|
|
32
|
+
executors, were removed; see [MIGRATION.md](../MIGRATION.md#action-endpoints-are-removed).
|
|
33
|
+
|
|
34
|
+
## HTTP tools
|
|
35
|
+
|
|
36
|
+
A tool can be one HTTP request to your service, made by the Runtime itself: no code of
|
|
37
|
+
yours runs during the session.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Agent, http } from "@nylorun/agents";
|
|
41
|
+
import { z } from "zod";
|
|
42
|
+
|
|
43
|
+
const refundOrder = http({
|
|
44
|
+
name: "refund_order",
|
|
45
|
+
description: "Refund an order.",
|
|
46
|
+
input: z.object({ orderId: z.string(), amount: z.number() }), // or a JSON Schema object
|
|
47
|
+
output: z.object({ refundId: z.string() }), // optional
|
|
48
|
+
url: "https://billing.example.com/refunds",
|
|
49
|
+
method: "POST", // default; or PUT, PATCH
|
|
50
|
+
credential: "billing", // optional: a vault credential bound to this URL
|
|
51
|
+
timeoutMs: 20_000, // default 60000, at most 300000
|
|
52
|
+
approval: "always", // optional: each call waits for session.approve()
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const support = Agent({ id: "support" }).tools(refundOrder);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The tool goes into the manifest as `http` (and `approval`), and the Runtime's
|
|
59
|
+
Tool Gate sends the model's input as the JSON body, under the Host's address
|
|
60
|
+
policy (`NYLORUN_ENDPOINT_*`), with `content-type: application/json`,
|
|
61
|
+
`Nylorun-Session-Id`, `Nylorun-Turn-Id`, `Nylorun-Agent-Id` and an
|
|
62
|
+
`Idempotency-Key` that is the same when the Runtime re-sends the call after a
|
|
63
|
+
restart, so your service can drop duplicates. A `2xx` JSON answer is the output
|
|
64
|
+
(text when it is not JSON and the tool has no `output`), checked against
|
|
65
|
+
`output`. Any other status (with the start of its body), a timeout, a refused
|
|
66
|
+
address or a mismatched output is a tool error the model sees. A call whose
|
|
67
|
+
answer was lost with the gateway is `uncertain` and never sent again.
|
|
68
|
+
|
|
69
|
+
`credential` works as for a remote MCP server: the session's attached vaults
|
|
70
|
+
must hold a credential bound to the tool's exact URL (a `credentialSelections`
|
|
71
|
+
entry whose `serverName` is the `credential` picks one when several are), else
|
|
72
|
+
the operator's credential resolver is asked; without one the call fails before
|
|
73
|
+
it is sent. `approval: "always"` pauses the turn for `session.approve()`; a
|
|
74
|
+
denied call never runs and the model sees the denial. A remote MCP server takes
|
|
75
|
+
`approval: "always"` too, for every one of its tools:
|
|
76
|
+
`.mcp({ shop: { type: "streamable-http", url, approval: "always" } })`.
|
|
77
|
+
An HTTP tool is also a flow stage (see [Flow agents](#flow-agents)), and runs
|
|
78
|
+
only on the Runtime (a local `run()` reports `http.runtime-only`).
|
|
43
79
|
|
|
44
80
|
## Connection resolution
|
|
45
81
|
|
|
46
|
-
`resolveConnection` / `createClient()
|
|
82
|
+
`resolveConnection` / `createClient()`:
|
|
47
83
|
|
|
48
84
|
1. Explicit `{ url, key }`
|
|
49
85
|
2. Environment — if `NYLORUN_RUNTIME_URL` or `NYLORUN_SERVER_KEY` is set, both
|
|
@@ -59,22 +95,20 @@ Runtime serves one Tenant, so nothing names it: the `tenant` option is gone
|
|
|
59
95
|
is ignored.
|
|
60
96
|
|
|
61
97
|
```ts
|
|
62
|
-
import { Agent,
|
|
98
|
+
import { Agent, createClient, http } from "@nylorun/agents";
|
|
63
99
|
import { z } from "zod";
|
|
64
100
|
|
|
65
101
|
const assistant = Agent({ id: "assistant", name: "Assistant" })
|
|
66
102
|
.instructions("Use the available tools.")
|
|
67
103
|
.tools(
|
|
68
|
-
|
|
104
|
+
http({
|
|
69
105
|
name: "lookup",
|
|
70
106
|
input: z.object({ id: z.string() }),
|
|
71
|
-
|
|
72
|
-
return { id, owner: ctx.info };
|
|
73
|
-
},
|
|
107
|
+
url: "https://items.example.com/lookup",
|
|
74
108
|
}),
|
|
75
109
|
);
|
|
76
110
|
|
|
77
|
-
// Explicit
|
|
111
|
+
// Explicit Runtime API client (options or env / link via createClient()).
|
|
78
112
|
const client = createClient({
|
|
79
113
|
url: process.env.NYLORUN_RUNTIME_URL,
|
|
80
114
|
key: process.env.NYLORUN_SERVER_KEY,
|
|
@@ -86,20 +120,6 @@ const session = await client.createSession({
|
|
|
86
120
|
});
|
|
87
121
|
await session.input("Look up item 123", { idempotencyKey: requestId });
|
|
88
122
|
const history = await session.history();
|
|
89
|
-
|
|
90
|
-
// A process that only serves Actions holds no key: it reads the Tenant's public keys.
|
|
91
|
-
const actions = createActionHandler({
|
|
92
|
-
agents: [assistant],
|
|
93
|
-
implementationVersion: "app-1",
|
|
94
|
-
runtime: { url: process.env.NYLORUN_RUNTIME_URL! },
|
|
95
|
-
url: "https://app.example.com/nylorun/actions",
|
|
96
|
-
onError: console.error,
|
|
97
|
-
});
|
|
98
|
-
app.post("/nylorun/actions", actions.node);
|
|
99
|
-
// A deploy step with the application key registers the URL once:
|
|
100
|
-
await createActionHandler({ agents: [assistant], client }).register({
|
|
101
|
-
url: "https://app.example.com/nylorun/actions",
|
|
102
|
-
});
|
|
103
123
|
```
|
|
104
124
|
|
|
105
125
|
```sh
|
|
@@ -125,7 +145,9 @@ const assistant = Agent({ id: "assistant", name: "Order assistant" })
|
|
|
125
145
|
.skills("./assistant-skills");
|
|
126
146
|
```
|
|
127
147
|
|
|
128
|
-
Each subdirectory under the catalog must contain a `SKILL.md` with YAML frontmatter (`name`, `description`) per [Agent Skills](https://agentskills.io/home).
|
|
148
|
+
Each subdirectory under the catalog must contain a `SKILL.md` with YAML frontmatter (`name`, `description`) per [Agent Skills](https://agentskills.io/home). Every file of a skill's folder, binary included (not `.git/`, `node_modules/`, OS files like `.DS_Store`, or `.env` and `.env.*` files, which hold secrets), is part of the definition: the manifest names each one by path and SHA-256 (`skills.<name>.files`), at most 500 files of 10 MiB each. `saveAgent` uploads the files the Runtime does not hold (`client.files`, `PUT /v1/files/sha256:<hex>`) before it puts the definition, which the Runtime refuses while it names a file it lacks (`400 definition_files_missing`).
|
|
149
|
+
|
|
150
|
+
The Runtime serves the skills itself, with no call to your process: `load_skill` returns a skill's `SKILL.md` body and the paths of its other files, and `read_skill_resource` returns a text file. A session with a sandbox also has each skill's files read-only under `/skills/<name>/`, so the model can run a skill's scripts with `bash`. Run without a Runtime, the skill tools only say so.
|
|
129
151
|
|
|
130
152
|
Declare MCP servers with `.mcp(...)` (same map shape as agent-plugins `mcpServers`):
|
|
131
153
|
|
|
@@ -139,7 +161,7 @@ const assistant = Agent({ id: "assistant", name: "Assistant" })
|
|
|
139
161
|
});
|
|
140
162
|
```
|
|
141
163
|
|
|
142
|
-
Each key names a server; its `name` defaults to the key and, when given, must equal it. Repeated `.mcp()` calls add servers to the same capability.
|
|
164
|
+
Each key names a server; its `name` defaults to the key and, when given, must equal it. Repeated `.mcp()` calls add servers to the same capability. Nylorun accepts remote servers only: `streamable-http` and `sse` ([Agent Plugins MCP servers](https://agent-plugins.org/plugin-authors/mcp-servers)); a `stdio` server is refused, so run it behind an HTTP transport and declare its URL. Attach an Agent Plugin package with `.plugin(path)`: its skills and remote MCP servers join the agent, and a stdio server in its `mcp.json` throws.
|
|
143
165
|
|
|
144
166
|
Give a session a sandbox when you open it. The agent declares nothing, so the same agent runs with or without one, in any Tenant:
|
|
145
167
|
|
|
@@ -154,7 +176,7 @@ const session = await client.createSession({
|
|
|
154
176
|
});
|
|
155
177
|
```
|
|
156
178
|
|
|
157
|
-
The model gets `bash`, `read`, `write`, `edit`, `grep` and `glob` on a persistent `/workspace`. These tools run in the Runtime, not in your process
|
|
179
|
+
The model gets `bash`, `read`, `write`, `edit`, `grep` and `glob` on a persistent `/workspace`. These tools run in the Runtime, not in your process. The Runtime decides where the sandbox runs: today an emulated shell in the Runtime process, which is not a VM boundary and takes no `image`.
|
|
158
180
|
|
|
159
181
|
`sandbox` takes `false` for none, `{ id }` to attach a sandbox resource (below), or an inline sandbox as above; omit it for the Tenant's default. `{ session }`, sharing another session's sandbox, still works and is deprecated. The Runtime checks it against the Tenant's limits (`GET`/`PUT /v1/tenant/sandbox`: a network ceiling, a resource maximum, the idle timeout) and answers `400` with every problem it finds. A caller acting for a user (`app.as(...)`) can't define one inline; it gets the Tenant's default or `false`. Private networks, loopback, the host and cloud metadata endpoints are always blocked.
|
|
160
182
|
|
|
@@ -196,35 +218,46 @@ const support = Agent({ id: "support" })
|
|
|
196
218
|
.subagents(researcher);
|
|
197
219
|
```
|
|
198
220
|
|
|
199
|
-
The tool is named after the agent's `id` and takes `{ task: string }`; the agent's `description` (required) is what the parent's model reads to decide when to delegate. The child starts with a fresh context: it sees its own instructions and the task, nothing of the parent's conversation, and only its final text (or `outputSchema` result) comes back. It keeps its own tools,
|
|
221
|
+
The tool is named after the agent's `id` and takes `{ task: string }`; the agent's `description` (required) is what the parent's model reads to decide when to delegate. The child starts with a fresh context: it sees its own instructions and the task, nothing of the parent's conversation, and only its final text (or `outputSchema` result) comes back. It keeps its own tools, skills and MCP servers, saved with the parent, shares the session's sandbox, and starts with empty `ctx.state`. Tools can read `ctx.agent` (`{ id, path, delegationId }`). Several delegation calls in one model response run in parallel. An empty answer, a failure (with the child's last text marked as evidence) or a cancelled child reaches the parent's model as a failed tool result, never as success. The Runtime emits `delegation.started` and `delegation.completed`; `session.history({ agent })` filters by `delegationId` (one child invocation) or by path such as `support/researcher` (every concurrent child that shares that path).
|
|
200
222
|
|
|
201
|
-
A flow agent can be a subagent too: `.subagents(researchFlow)` with a `description` like any other. Its manifest is inlined in the parent's, so it is saved with the parent
|
|
223
|
+
A flow agent can be a subagent too: `.subagents(researchFlow)` with a `description` like any other. Its manifest is inlined in the parent's, so it is saved with the parent. When the model calls it, the flow runs on the Runtime in its own linked session (a fresh one per call, linked from the parent's with a `node.agent` event at `support/<flow id>`), its agents in theirs, and the flow's output comes back as the tool result; a failed flow is a failed tool result. Cancelling the parent cancels the flow. Flow agents as subagents run on the Runtime only, not in a local `run()`. An approval asked for inside the flow waits on the flow's own session.
|
|
202
224
|
|
|
203
|
-
Delegate when the parent should keep the answer. When a specialist should own the rest of the conversation,
|
|
225
|
+
Delegate when the parent should keep the answer. When a specialist should own the rest of the conversation, send the next message with a turn manifest that has the specialist's instructions instead. This version is one level deep and non-interactive: a delegated agent cannot use agents as tools, its tools cannot declare `approval` (keep those on the parent), and `ctx.ask`, `ctx.approve`, `ctx.sleep` or `ctx.waitFor` inside it fail with `delegation.interaction-unsupported`. Delegation is not an approval boundary; approvals live on tools.
|
|
204
226
|
|
|
205
227
|
## Flow agents
|
|
206
228
|
|
|
207
|
-
An agent's body is either a ReAct loop (the model decides) or a flow (
|
|
208
|
-
decides). A flow agent is built from stages
|
|
209
|
-
|
|
210
|
-
`
|
|
211
|
-
and `
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
An agent's body is either a ReAct loop (the model decides) or a flow (its manifest
|
|
230
|
+
decides). A flow agent is built from stages and is registered, saved and opened as a
|
|
231
|
+
session like any agent: put it in `export const agents`, `saveAgent(flowAgent)`, then
|
|
232
|
+
`createSession({ agentId })` and `session.input(value)`. `input` sends string values as
|
|
233
|
+
`content` and other JSON as `data`. On the wire a flow agent is a workflow manifest v3
|
|
234
|
+
(`kind: "workflow"`, `workflowSchemaVersion: 3`) that embeds the agents it runs, so one
|
|
235
|
+
document and one manifest hash cover the whole flow; its agents are not listed on their own.
|
|
236
|
+
|
|
237
|
+
A flow runs no code of yours: the first stage gets the flow's input, and every later stage
|
|
238
|
+
gets the previous stage's output. So each agent returns, through its `.output()` schema,
|
|
239
|
+
what the next stage needs.
|
|
215
240
|
|
|
216
241
|
```ts
|
|
217
|
-
import { Agent, tool } from "@nylorun/agents";
|
|
242
|
+
import { Agent, VerdictSchema, tool } from "@nylorun/agents";
|
|
218
243
|
import { z } from "zod";
|
|
219
244
|
|
|
220
245
|
const planner = Agent({ id: "planner" })
|
|
221
|
-
.instructions("Return {
|
|
222
|
-
.output(z.object({
|
|
246
|
+
.instructions("Return { items: string[] }, one task each.")
|
|
247
|
+
.output(z.object({ items: z.array(z.string()) }));
|
|
223
248
|
|
|
224
249
|
const coder = Agent({ id: "coder" })
|
|
225
250
|
.instructions("Implement one task. Return { summary }.")
|
|
226
251
|
.output(z.object({ summary: z.string() }));
|
|
227
252
|
|
|
253
|
+
const reviewer = Agent({ id: "reviewer" })
|
|
254
|
+
.instructions("Pass the response when its summary says what changed.")
|
|
255
|
+
.output(VerdictSchema);
|
|
256
|
+
|
|
257
|
+
const prWriter = Agent({ id: "pr-writer" })
|
|
258
|
+
.instructions("Return the summaries you are given as { summaries }.")
|
|
259
|
+
.output(z.object({ summaries: z.array(z.string()) }));
|
|
260
|
+
|
|
228
261
|
const openPr = tool({
|
|
229
262
|
name: "open-pr",
|
|
230
263
|
input: z.object({ summaries: z.array(z.string()) }),
|
|
@@ -235,52 +268,88 @@ const openPr = tool({
|
|
|
235
268
|
});
|
|
236
269
|
|
|
237
270
|
export const shipFeature = Agent({ id: "ship-feature" })
|
|
238
|
-
.
|
|
239
|
-
.map(
|
|
240
|
-
|
|
241
|
-
verify: ({ output }) => (output.summary ? { pass: true } : { pass: false, feedback: "Say what you changed." }),
|
|
242
|
-
max: 2,
|
|
243
|
-
}),
|
|
244
|
-
{ id: "implement", input: ({ input }) => input.tasks },
|
|
245
|
-
)
|
|
246
|
-
.step(openPr, { input: ({ input }) => ({ summaries: input.map((item) => item.summary) }) });
|
|
271
|
+
.pipe(planner)
|
|
272
|
+
.map(Agent({ id: "code" }).loop(coder, { verify: reviewer, max: 2 }), { id: "implement" })
|
|
273
|
+
.pipe(prWriter, openPr);
|
|
247
274
|
|
|
248
275
|
export const agents = [shipFeature];
|
|
249
276
|
```
|
|
250
277
|
|
|
251
278
|
| Stage | Role |
|
|
252
279
|
| --- | --- |
|
|
253
|
-
| **`.
|
|
254
|
-
| **`.switch({ ...cases, default? }
|
|
280
|
+
| **`.pipe(a, b, …)`** | Run agents, tools or `flow()`s in order; each one's output is the next one's input |
|
|
281
|
+
| **`.switch({ ...cases, default? })`** | Run the case the previous output names: a string, or its `route` field |
|
|
255
282
|
| **`.parallel(branches)`** | Fixed named branches at once, same input; output is an object |
|
|
256
|
-
| **`.map(each)`** | Run `each` once per item of the
|
|
257
|
-
| **`.loop(body, { verify, max
|
|
283
|
+
| **`.map(each)`** | Run `each` once per item of the previous output: an array, or its `items`; output is an array |
|
|
284
|
+
| **`.loop(body, { verify, max })`** | Run `body`, ask `verify` (an agent, or `http({ url })`), run again with its feedback until it passes, at most `max` times |
|
|
285
|
+
|
|
286
|
+
Every stage takes `{ id }` to name it (`.loop` takes it beside `verify` and `max`).
|
|
287
|
+
`flow()` builds a sequence with no id for a case, branch, map item or loop body that
|
|
288
|
+
is more than one step. A verifier agent gets `{ task, response, iteration }` and returns
|
|
289
|
+
a verdict, `{ pass, feedback? }` (`VerdictSchema`), with feedback when it fails; the
|
|
290
|
+
verdict is recorded as a `loop.verified` event. An agent after the first stage also
|
|
291
|
+
sees the flow's input, as the original request, before its own input. Types flow from
|
|
292
|
+
each stage's `.output()` schema to the flow agent's output. `.step(x, { id })` is a
|
|
293
|
+
deprecated alias for `.pipe(x.withId(id))`.
|
|
294
|
+
|
|
295
|
+
An [HTTP tool](#http-tools) is a stage too: in `.pipe()`, a case, a Map item or a Loop
|
|
296
|
+
body. Its input is the previous output, which must match the tool's `input` (an
|
|
297
|
+
object); a mismatch the build can see, such as an agent with no `.output()` before it,
|
|
298
|
+
is refused (`flow.input-mismatch`), and any other fails the stage when it runs
|
|
299
|
+
(`tool.invalid-input`). The Runtime makes the request as for an agent's HTTP tool, with
|
|
300
|
+
`Nylorun-Agent-Id` set to the flow agent's id and `credential` taken from the flow
|
|
301
|
+
session's vaults; its answer is the next stage's input. A failure status, a timeout or
|
|
302
|
+
an answer that does not match `output` fails the stage with its code (`http.status`,
|
|
303
|
+
`http.timeout`, `tool.invalid-output`, …). A Loop body that starts with an HTTP stage
|
|
304
|
+
is retried with the Loop's input, not the feedback. `approval: "always"` is not
|
|
305
|
+
supported on a flow stage yet (`flow.approval-unsupported`).
|
|
306
|
+
|
|
307
|
+
A Loop may be judged by your service instead of an agent: `http({ url, method?,
|
|
308
|
+
credential?, timeoutMs? })`, with no name or input, is an HTTP verifier. The Runtime
|
|
309
|
+
sends `{ input, output, iteration }` (the Loop's input, the attempt's output, its
|
|
310
|
+
number) and reads a verdict, `{ pass, feedback? }`, from the answer; anything else, or a
|
|
311
|
+
failed request, fails the Loop (`loop.verify-failed`). Its verdicts are recorded as
|
|
312
|
+
`loop.verified`, as an agent's are.
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import { Agent, http } from "@nylorun/agents";
|
|
316
|
+
import { z } from "zod";
|
|
258
317
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
318
|
+
const order = Agent({ id: "order" })
|
|
319
|
+
.instructions("Name the order to refund as { orderId }.")
|
|
320
|
+
.output(z.object({ orderId: z.string() }));
|
|
321
|
+
|
|
322
|
+
const refund = http({
|
|
323
|
+
name: "refund",
|
|
324
|
+
input: z.object({ orderId: z.string() }),
|
|
325
|
+
output: z.object({ refundId: z.string() }),
|
|
326
|
+
url: "https://billing.example.com/refunds",
|
|
327
|
+
credential: "billing",
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const fixer = Agent({ id: "fixer" }).instructions("Fix the failing test.");
|
|
331
|
+
|
|
332
|
+
export const refunds = Agent({ id: "refunds" }).pipe(order, refund);
|
|
333
|
+
export const fixTests = Agent({ id: "fix-tests" }).loop(fixer, {
|
|
334
|
+
verify: http({ url: "https://ci.example.com/verify", credential: "ci" }),
|
|
335
|
+
max: 3,
|
|
336
|
+
});
|
|
337
|
+
```
|
|
265
338
|
|
|
266
339
|
Agents inside a flow keep their own sessions, linked from the flow's session and
|
|
267
|
-
named by the agent:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
`.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
Name the stages you may reorder.
|
|
275
|
-
|
|
276
|
-
`Chain`, `Switch`, `Parallel`, `Map` and `Loop` still build workflow manifest v1
|
|
277
|
-
directly and run as before; a flow agent can't be a child of them.
|
|
340
|
+
named by the agent: its id (or `.withId("…")`), with `[i]` for each Map item and a
|
|
341
|
+
nested flow agent's id in front of its own agents'. Control stages add nothing, so
|
|
342
|
+
wrapping a step in `.loop()` or moving it between cases keeps its session. An agent
|
|
343
|
+
may appear once per flow; use it again under a new id with `writer.withId("final-writer")`
|
|
344
|
+
(`flow.duplicate-leaf`). A code tool stage (`.pipe(tool({ run }))`) runs only in the local
|
|
345
|
+
engine: the Runtime runs no code of yours, so `saveAgent` refuses a flow agent with one. Use
|
|
346
|
+
an HTTP stage instead.
|
|
278
347
|
|
|
279
348
|
The agents in a flow share one sandbox: open the flow's session with it,
|
|
280
|
-
`createSession({ …, sandbox: { … } })`, and every agent
|
|
281
|
-
|
|
349
|
+
`createSession({ …, sandbox: { … } })`, and every agent in the flow uses it. Share it
|
|
350
|
+
with other sessions by opening them all on one sandbox resource
|
|
282
351
|
(`sandbox: { id }`, see `client.sandboxes`), and call
|
|
283
|
-
built-ins via `session.sandbox` (application)
|
|
352
|
+
built-ins via `session.sandbox` (application).
|
|
284
353
|
Observe with `session.observe({ follow: true })` to merge linked agent streams;
|
|
285
354
|
`pending()` lists waits across the tree. Studio renders the manifest tree and
|
|
286
355
|
live node status. Source examples:
|
|
@@ -293,15 +362,15 @@ Use `session.observe({ cursor, signal })` for resumable canonical events, `sessi
|
|
|
293
362
|
|
|
294
363
|
Connection defaults follow `resolveConnection` (options → environment → Project
|
|
295
364
|
link). Implementation version defaults from `NYLORUN_IMPLEMENTATION_VERSION`,
|
|
296
|
-
then `dev`.
|
|
297
|
-
|
|
298
|
-
Agents do not hash the manifest, and an in-flight action is still delivered after
|
|
299
|
-
the registered digest changes. Model selection and model credentials belong to
|
|
365
|
+
then `dev`. Agents do not hash the manifest; the Runtime pins the digest of the
|
|
366
|
+
definition a session opens with. Model selection and model credentials belong to
|
|
300
367
|
the Tenant.
|
|
301
368
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
369
|
+
The Runtime makes a lost HTTP tool call `uncertain` instead of repeating its external effect.
|
|
370
|
+
In the local engine (`@nylorun/harness/run`), `tool({ run })` tools receive state, info,
|
|
371
|
+
identity, resume, signal, approval/response helpers and memoized `step`. Arbitrary middleware
|
|
372
|
+
closures are rejected for durable definitions. Agent definitions have no `.run()`; explicit
|
|
373
|
+
local execution is available through `@nylorun/harness/run`.
|
|
305
374
|
|
|
306
375
|
## AG-UI
|
|
307
376
|
|
|
@@ -377,7 +446,7 @@ no reasoning, state, activity or subagent events, and an agent used as a tool
|
|
|
377
446
|
shows only its result; frontend tools in `RunAgentInput.tools` are rejected
|
|
378
447
|
(`400`); one text part per user message; earlier messages cannot be edited or
|
|
379
448
|
regenerated. A browser reaches the Runtime only with a trusted issuer's token,
|
|
380
|
-
never with a
|
|
449
|
+
never with a key.
|
|
381
450
|
|
|
382
451
|
## A2A
|
|
383
452
|
|
|
@@ -495,12 +564,12 @@ completes.
|
|
|
495
564
|
## Acting for a person (app servers)
|
|
496
565
|
|
|
497
566
|
A server that signs people in and calls the Runtime for them (an "app server")
|
|
498
|
-
keeps
|
|
567
|
+
keeps its application key to itself and names the person on each call:
|
|
499
568
|
|
|
500
569
|
```ts
|
|
501
570
|
import { createClient } from "@nylorun/agents";
|
|
502
571
|
|
|
503
|
-
const app = createClient(); // the
|
|
572
|
+
const app = createClient(); // the application key, on the server only
|
|
504
573
|
|
|
505
574
|
// Per request, after your own sign-in:
|
|
506
575
|
const person = app.as(`app:${user.id}`, { scopes: ["sessions:own"] });
|
|
@@ -519,22 +588,25 @@ compatibility check, so calling `as()` per request is cheap.
|
|
|
519
588
|
| --- | --- |
|
|
520
589
|
| `sessions:own` | The person's own sessions: create, list, read, stream, message, approve, respond, cancel; and their artifacts |
|
|
521
590
|
| `agents:read` | Listing the Tenant's agents |
|
|
522
|
-
| `agents:write` | Saving agents; listing agents
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
the
|
|
527
|
-
|
|
528
|
-
|
|
591
|
+
| `agents:write` | Saving agents; listing agents |
|
|
592
|
+
|
|
593
|
+
No scope reaches the sandbox tool routes; call them without `as()`. `tenant:settings` is retired (protocol 8): it grants
|
|
594
|
+
nothing, and no subject reaches the Management API (`/v1/tenant/*`). Vaults are
|
|
595
|
+
the installation's, created through the Management API with a management key
|
|
596
|
+
(`admin.vaults.create({ scope: "installation", … })` in
|
|
597
|
+
[`@nylorun/admin`](../admin/README.md)); a session attaches them with
|
|
598
|
+
`vaultIds`, and a person's own credentials come from your credential resolver
|
|
529
599
|
([DEPLOYMENT.md](../DEPLOYMENT.md#credentials)). A subject is 1–200 visible ASCII
|
|
530
600
|
characters (spaces only inside) and `host` is reserved. Your server must drop
|
|
531
601
|
any `Nylorun-*` header its own clients send, and only an application key can act
|
|
532
602
|
for a subject.
|
|
533
603
|
|
|
534
|
-
The Tenant's signing keys sign
|
|
535
|
-
`app.access.
|
|
536
|
-
|
|
537
|
-
|
|
604
|
+
The Tenant's signing keys sign capability links and run tokens.
|
|
605
|
+
`app.access.jwks()` reads the public keys (`GET /v1/access/jwks`, no key
|
|
606
|
+
needed). Listing, rotating
|
|
607
|
+
and revoking them is management: `admin.signingKeys.list()`, `.rotate()`
|
|
608
|
+
(`{ force: true }` for incidents) and `.revoke(kid)` in `@nylorun/admin`, or
|
|
609
|
+
`nylo access signing-keys …` from the terminal.
|
|
538
610
|
|
|
539
611
|
## In the browser
|
|
540
612
|
|