@nylorun/agents 0.10.0-beta → 0.11.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 +34 -0
- package/README.md +22 -21
- package/dist/action-handler.d.ts +0 -1
- package/dist/action-handler.js +5 -9
- package/dist/client.js +1 -4
- package/dist/connection.d.ts +4 -3
- package/dist/connection.js +15 -18
- package/dist/delivery-token.d.ts +7 -2
- package/dist/delivery-token.js +12 -3
- package/dist/http.d.ts +5 -4
- package/dist/http.js +1 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
+
## 0.11.0-beta
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 5ca1923: **Clients for one Tenant per installation: a stack per project, nothing selects a Tenant.** Upgrade these with the Runtime; they speak protocol 5. Existing stacks are left as they are: see MIGRATION.md.
|
|
8
|
+
|
|
9
|
+
- **Breaking (`nylorun`): one stack per project.** `nylorun start` in a project creates the project's stack (named after the project directory, or `--name`; Host root `~/.nylorun/stacks/<name>/`, Compose project `nylorun-<name>`, its own free ports and volumes), waits for its Runtime to create the stack's Tenant, writes the Project link (`.nylorun/link.json` format 2: `stack`, `hostUrl`, `hostId`, `tenantId`) and `.nylorun/credentials.json` (the key of the derived principal `project`, derived from the stack's admin key), and seeds the model provider from the project's `.env`. `nylorun ls` lists the machine's stacks and `nylorun delete <name>` removes one with its volumes and Host root. `nylorun status` shows the stack's Tenant; `nylorun studio` opens it. The old single stack under `~/.nylorun` is never touched: `start` notes it, and `nylorun legacy stop|delete` handles it. Every stack command takes `--name <stack>` (or `NYLORUN_STACK`, or the Project link's stack); `start --no-link` starts a stack without linking the directory; `nylorun reset` resets the selected stack only. The runtime container's healthcheck is now `/health`, so a Tenant that cannot open is reported by `start` from the Admin status at once instead of after a 300 s wait. `NYLORUN_HOME` still overrides the Host root. Stacks start and stop only when you say so.
|
|
10
|
+
- **Breaking (`@nylorun/cli`): no Tenant commands.** `nylo tenant create|use|list|current|delete` are removed; `nylo status`, `nylo reset` and `nylo endpoints` replace `nylo tenant status|reset|endpoints` on the linked installation. `nylo env` prints `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` only. `nylo` no longer writes Project links.
|
|
11
|
+
- **Breaking (`@nylorun/agents`): no Tenant to name.** The `tenant` option (`createClient`, `Transport`, `resolveConnection`, `createActionHandler({ runtime })`, `JwksCache`) and `NYLORUN_TENANT` are gone, and no request sends `Nylorun-Tenant`; a connection is a URL and a key. A Project link of format 0 or 1 is refused with `connection_missing`, naming `npx nylorun start`. `verifyDeliveryToken`'s `tenantId` is optional: without it any Tenant issuer is accepted, since the installation's keys bind it. `TENANT_HEADER` is no longer re-exported.
|
|
12
|
+
- **Breaking (`@nylorun/admin`): status only.** `createTenant`, `listTenants`, `getTenant` and `deleteTenant` are removed; `status().tenant` names the Host's Tenant, and `deriveTenantKey` / `deriveStudioToken` derive its keys. Local Host resolution reads the stack's Host root (`stack` option, `NYLORUN_STACK`, or the Project link's `stack`); `NYLORUN_HOME` and `home` still override it. `stackHostRoot(name)` is exported.
|
|
13
|
+
- **Breaking (`@nylorun/studio`): Studio serves its installation's Tenant.** The Tenant picker, list and create are gone, with `/_studio/tenants`; `/` opens `/tenants/<id>`. The `/tenants/:tenant` routes and the login token's `tenant` claim stay for embedders and must name that Tenant. The proxy sends no `Nylorun-Tenant`.
|
|
14
|
+
- **`@nylorun/create-agent`:** the next steps are `npx nylorun start`, then `npm run dev`.
|
|
15
|
+
- `@nylorun/core`: `ProjectLinkFileSchema` accepts format 2 with `stack`, and `tenantId` is optional; `ERROR_CODES` loses `tenant_conflict` and `active_work`.
|
|
16
|
+
|
|
17
|
+
- 5ca1923: **One Tenant per installation: a database per Tenant, protocol 5.** A Runtime serves exactly one Tenant, the one its Postgres database holds. Two Tenants are two installations.
|
|
18
|
+
|
|
19
|
+
- **Breaking: fresh start.** The Tenant's state is in the fixed schema `nylorun` of its own database and its record in `nylorun_streams`, keyed by session (no `tenant_id`). A database written by an earlier Runtime (`tenant_<id>` schemas, or a record keyed by Tenant) is refused: the Host stays up but not ready, and `/v1/admin/status` names the cause `database-layout-old`. Point the Runtime at a new database (with the local stack, a new stack); the old one is never changed.
|
|
20
|
+
- **The Host creates its Tenant** on first start, in the migration transaction: `NYLORUN_TENANT_ID` (default a new id), `NYLORUN_TENANT_NAME` (default `default`), the Studio principal and the derived principals of `NYLORUN_DERIVED_PRINCIPALS` (comma-separated, default `project`), whose keys the admin key derives (`deriveTenantKey`). Later starts open the same Tenant and add derived principals configured since.
|
|
21
|
+
- **Breaking: no Tenant catalog.** `/v1/admin/tenants` and `/v1/admin/tenants/{tenantId}` are gone (404). `AdminStatus.tenants[]` is replaced by `AdminStatus.tenant` (`id`, `name`, `state: open | unavailable`, `envelope`, and `cause` when it could not be opened). `CreateTenantRequestSchema`, `AdminTenantSchema`, `AdminTenantStatusSchema`, `AdminTenantListSchema` and `QuarantineSchema` leave `@nylorun/core`; `HostTenantSchema` and `TenantCauseSchema` replace them. `@nylorun/admin`'s `listTenants`, `getTenant`, `deleteTenant` and `createTenant` are removed (see below).
|
|
22
|
+
- **Readiness instead of quarantine.** A Tenant that cannot be opened (`schema-too-new`, `kek-missing`, `migration-failed`, `envelope-invalid`, `database-layout-old`, …) fails `/ready` (check `tenant`, which replaces `discovery`) and is reported with its repair in `/v1/admin/status` and the log; every Tenant request gets the opaque 404. A failure outside it (Postgres unreachable) is retried.
|
|
23
|
+
- **Protocol 5.** `PROTOCOL_VERSION = 5`; the Host serves protocols 4 and 5 for one release. Clients no longer require `runtime-tenants`; the Host still advertises it. No request needs `Nylorun-Tenant`: a request without it reaches the Host's Tenant, and one naming another Tenant (or a malformed one), or a publishable key of another Tenant, gets the opaque 404. The OpenAPI documents drop the header parameter and the Admin Tenant routes.
|
|
24
|
+
- **Paths.** The Tenant directory is `<Host root>/tenant/` (was `tenants/<id>/`); `trash/` and the SQLite move to it are gone. The gates service serves its database's Tenant, and its `Nylorun-Tenant` header is optional (when sent, it must name that Tenant).
|
|
25
|
+
- **Breaking: `startEphemeralRuntime` needs a database; the in-memory Session Store is removed.** `StartEphemeralRuntimeOptions.database` is required: a Postgres URL, for which the Runtime opens a pool and ends it on `close()`, or a pool the caller ends. It creates its Tenant in that database through the same bootstrap as a Host, or serves the Tenant the database already holds; the data stays after `close()`, so give each test Tenant a database of its own. Durable Streams and scheduling stay in process. See `MIGRATION.md`.
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Pin core to the tested release.
|
|
30
|
+
- Updated dependencies [fed780d]
|
|
31
|
+
- Updated dependencies [fed780d]
|
|
32
|
+
- Updated dependencies [7f4c3f1]
|
|
33
|
+
- Updated dependencies [5ca1923]
|
|
34
|
+
- Updated dependencies [5ca1923]
|
|
35
|
+
- @nylorun/core@0.10.0-beta
|
|
36
|
+
|
|
3
37
|
## 0.10.0-beta
|
|
4
38
|
|
|
5
39
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -24,11 +24,11 @@ The Runtime delivers each tool call, hook and workflow function of these agents
|
|
|
24
24
|
to `url`, signed with a short-lived **delivery token** that the handler checks
|
|
25
25
|
(Tenant, URL, Action, generation and body) before any code runs. `register`
|
|
26
26
|
saves the definitions, registers the URL and pings it through the Runtime. A
|
|
27
|
-
process that only serves Actions needs no key: pass `runtime: { url
|
|
28
|
-
|
|
27
|
+
process that only serves Actions needs no key: pass `runtime: { url }` and it
|
|
28
|
+
reads the Tenant's public keys. Mark a long tool
|
|
29
29
|
`tool({ …, background: true })`: the handler answers at once, heartbeats and
|
|
30
|
-
posts the result. `npx @nylorun/cli
|
|
31
|
-
|
|
30
|
+
posts the result. `npx @nylorun/cli endpoints` shows each endpoint and how its
|
|
31
|
+
deliveries are doing.
|
|
32
32
|
|
|
33
33
|
The URL must be one the Runtime can reach: `localhost` on the local stack
|
|
34
34
|
(its Runtime runs in Docker and maps `localhost` to this machine), a public URL
|
|
@@ -36,21 +36,26 @@ in production, or a tunnel (ngrok, Cloudflare Tunnel) for a remote Runtime.
|
|
|
36
36
|
|
|
37
37
|
`connectAgents` and executors were removed in protocol 3: mount
|
|
38
38
|
`createActionHandler` instead (see [MIGRATION.md](../MIGRATION.md)). The handler
|
|
39
|
-
finds the Runtime through the
|
|
40
|
-
that `npx
|
|
41
|
-
|
|
39
|
+
finds the Runtime through the two `NYLORUN_*` variables or the Project link
|
|
40
|
+
that `npx nylorun start` writes; with neither, `register` fails with
|
|
41
|
+
`connection_missing` and names those steps. See [MIGRATION.md](../MIGRATION.md#runtime-clients-and-admin-api-breaking-beta)
|
|
42
42
|
for upgrading from `nylorun serve`.
|
|
43
43
|
|
|
44
44
|
## Connection resolution
|
|
45
45
|
|
|
46
46
|
`resolveConnection` / `createClient()` / `createActionHandler({ agents })`:
|
|
47
47
|
|
|
48
|
-
1. Explicit `{ url,
|
|
49
|
-
2. Environment — if
|
|
50
|
-
|
|
51
|
-
3. Project link — `.nylorun/link.json` + `credentials.json` (the application
|
|
48
|
+
1. Explicit `{ url, key }`
|
|
49
|
+
2. Environment — if `NYLORUN_RUNTIME_URL` or `NYLORUN_SERVER_KEY` is set, both
|
|
50
|
+
must be present
|
|
51
|
+
3. Project link — `.nylorun/link.json` + `credentials.json` (the application
|
|
52
|
+
key), written by `npx nylorun start`. A link from before one Tenant per
|
|
53
|
+
installation (format 0 or 1) fails with `connection_missing`: run
|
|
54
|
+
`npx nylorun start` in the project again.
|
|
52
55
|
|
|
53
|
-
Sources never mix. Partial environment fails with `connection_missing`.
|
|
56
|
+
Sources never mix. Partial environment fails with `connection_missing`. A
|
|
57
|
+
Runtime serves one Tenant, so nothing names it: the `tenant` option and
|
|
58
|
+
`NYLORUN_TENANT` are gone (protocol 5).
|
|
54
59
|
|
|
55
60
|
```ts
|
|
56
61
|
import { Agent, createActionHandler, createClient, tool } from "@nylorun/agents";
|
|
@@ -72,7 +77,6 @@ const assistant = Agent({ id: "assistant", name: "Assistant" })
|
|
|
72
77
|
const client = createClient({
|
|
73
78
|
url: process.env.NYLORUN_RUNTIME_URL,
|
|
74
79
|
key: process.env.NYLORUN_SERVER_KEY,
|
|
75
|
-
tenant: process.env.NYLORUN_TENANT,
|
|
76
80
|
});
|
|
77
81
|
await client.saveAgent(assistant, { implementationVersion: "app-1" });
|
|
78
82
|
const session = await client.createSession({
|
|
@@ -86,10 +90,7 @@ const history = await session.history();
|
|
|
86
90
|
const actions = createActionHandler({
|
|
87
91
|
agents: [assistant],
|
|
88
92
|
implementationVersion: "app-1",
|
|
89
|
-
runtime: {
|
|
90
|
-
url: process.env.NYLORUN_RUNTIME_URL!,
|
|
91
|
-
tenant: process.env.NYLORUN_TENANT!,
|
|
92
|
-
},
|
|
93
|
+
runtime: { url: process.env.NYLORUN_RUNTIME_URL! },
|
|
93
94
|
url: "https://app.example.com/nylorun/actions",
|
|
94
95
|
onError: console.error,
|
|
95
96
|
});
|
|
@@ -102,11 +103,11 @@ await createActionHandler({ agents: [assistant], client }).register({
|
|
|
102
103
|
|
|
103
104
|
```sh
|
|
104
105
|
eval "$(npx @nylorun/cli env)"
|
|
105
|
-
# → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY
|
|
106
|
+
# → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
Every request sets `Nylorun-
|
|
109
|
-
|
|
109
|
+
Every request sets `Nylorun-Protocol` (5) and no `Nylorun-Tenant`: the Runtime
|
|
110
|
+
serves one Tenant. Before the first authenticated
|
|
110
111
|
request, `Transport` fetches `/health` once, checks protocol compatibility, and
|
|
111
112
|
throws `IncompatibleRuntimeError` / `incompatible_host` when the Host range or
|
|
112
113
|
required features do not match. Re-exports include `PROTOCOL_FEATURES`,
|
|
@@ -494,7 +495,7 @@ const { token, expiresAt } = await app.tokens.create({
|
|
|
494
495
|
});
|
|
495
496
|
```
|
|
496
497
|
|
|
497
|
-
The client sends it as `Authorization: Bearer <token
|
|
498
|
+
The client sends it as `Authorization: Bearer <token>`.
|
|
498
499
|
Tokens carry only `sessions:own`, `vaults:own` and `agents:read`, live at most
|
|
499
500
|
15 minutes, and see only `{ agentId, name, description }` of their role's
|
|
500
501
|
agents. A token that expired or was revoked answers `401` with
|
package/dist/action-handler.d.ts
CHANGED
package/dist/action-handler.js
CHANGED
|
@@ -41,13 +41,12 @@ export function createActionHandler(options) {
|
|
|
41
41
|
if (request.method !== "POST")
|
|
42
42
|
return answer(405, "method_not_allowed", "An Action endpoint accepts POST only");
|
|
43
43
|
const body = new Uint8Array(await request.arrayBuffer());
|
|
44
|
-
const {
|
|
44
|
+
const { url, fetch, keys } = await verificationOf();
|
|
45
45
|
const token = request.headers.get(SIGNATURE_HEADER);
|
|
46
46
|
let claims;
|
|
47
47
|
try {
|
|
48
48
|
claims = await verifyDeliveryToken(token, {
|
|
49
49
|
keys: keys.lookup,
|
|
50
|
-
tenantId: tenant,
|
|
51
50
|
body,
|
|
52
51
|
...(audience === undefined ? {} : { audience }),
|
|
53
52
|
});
|
|
@@ -96,7 +95,7 @@ export function createActionHandler(options) {
|
|
|
96
95
|
agent,
|
|
97
96
|
token: token,
|
|
98
97
|
sandbox: delivery.sandbox,
|
|
99
|
-
runtime: { url,
|
|
98
|
+
runtime: { url, ...(fetch ? { fetch } : {}) },
|
|
100
99
|
report,
|
|
101
100
|
});
|
|
102
101
|
options.waitUntil?.(work);
|
|
@@ -106,7 +105,7 @@ export function createActionHandler(options) {
|
|
|
106
105
|
? createActionSandbox({
|
|
107
106
|
transport: (callbacks = callbacks
|
|
108
107
|
? callbacks.withKey(token)
|
|
109
|
-
: new Transport({ url,
|
|
108
|
+
: new Transport({ url, key: token, ...(fetch ? { fetch } : {}) })),
|
|
110
109
|
actionId: action.actionId,
|
|
111
110
|
signal: request.signal,
|
|
112
111
|
})
|
|
@@ -254,22 +253,19 @@ async function runInBackground(input) {
|
|
|
254
253
|
}
|
|
255
254
|
async function resolveVerification(options, clientOf) {
|
|
256
255
|
if (options.runtime) {
|
|
257
|
-
const { url,
|
|
256
|
+
const { url, fetch } = options.runtime;
|
|
258
257
|
return {
|
|
259
|
-
tenant,
|
|
260
258
|
url,
|
|
261
259
|
...(fetch ? { fetch } : {}),
|
|
262
|
-
keys: new JwksCache(options.jwks ?? { url,
|
|
260
|
+
keys: new JwksCache(options.jwks ?? { url, ...(fetch ? { fetch } : {}) }),
|
|
263
261
|
};
|
|
264
262
|
}
|
|
265
263
|
const { transport } = await clientOf();
|
|
266
264
|
return {
|
|
267
|
-
tenant: transport.tenant,
|
|
268
265
|
url: transport.url,
|
|
269
266
|
fetch: transport.fetcher,
|
|
270
267
|
keys: new JwksCache(options.jwks ?? {
|
|
271
268
|
url: transport.url,
|
|
272
|
-
tenant: transport.tenant,
|
|
273
269
|
key: transport.key,
|
|
274
270
|
fetch: transport.fetcher,
|
|
275
271
|
}),
|
package/dist/client.js
CHANGED
|
@@ -2,15 +2,12 @@ export * from "./session-client.js";
|
|
|
2
2
|
import { AgentsClient } from "./session-client.js";
|
|
3
3
|
import { resolveConnection } from "./connection.js";
|
|
4
4
|
export function createClient(destination = {}) {
|
|
5
|
-
if (destination.url !== undefined ||
|
|
6
|
-
destination.key !== undefined ||
|
|
7
|
-
destination.tenant !== undefined) {
|
|
5
|
+
if (destination.url !== undefined || destination.key !== undefined) {
|
|
8
6
|
return new AgentsClient(destination);
|
|
9
7
|
}
|
|
10
8
|
return resolveConnection().then((connection) => new AgentsClient({
|
|
11
9
|
url: connection.url,
|
|
12
10
|
key: connection.key,
|
|
13
|
-
tenant: connection.tenant,
|
|
14
11
|
...(destination.fetch ? { fetch: destination.fetch } : {}),
|
|
15
12
|
}));
|
|
16
13
|
}
|
package/dist/connection.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ErrorCode } from "@nylorun/core/compatibility";
|
|
2
2
|
export interface ResolvedConnection {
|
|
3
3
|
url: string;
|
|
4
|
-
tenant: string;
|
|
5
4
|
key: string;
|
|
6
5
|
source: "options" | "environment" | "project-link";
|
|
7
6
|
}
|
|
@@ -9,10 +8,12 @@ export declare class ConnectionError extends Error {
|
|
|
9
8
|
readonly code: ErrorCode;
|
|
10
9
|
constructor(message: string);
|
|
11
10
|
}
|
|
12
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Resolve Tenant API connection: options → environment → project link (D§7.1). A connection is a
|
|
13
|
+
* Runtime URL and a key: the Runtime serves one Tenant, so nothing names it.
|
|
14
|
+
*/
|
|
13
15
|
export declare function resolveConnection(options?: {
|
|
14
16
|
url?: string;
|
|
15
|
-
tenant?: string;
|
|
16
17
|
key?: string;
|
|
17
18
|
cwd?: string;
|
|
18
19
|
}): Promise<ResolvedConnection>;
|
package/dist/connection.js
CHANGED
|
@@ -11,8 +11,8 @@ export class ConnectionError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
function missing(tried) {
|
|
13
13
|
throw new ConnectionError(`connection_missing: no Runtime connection found (tried ${tried.join(", ")}). ` +
|
|
14
|
-
`
|
|
15
|
-
`or set NYLORUN_RUNTIME_URL
|
|
14
|
+
`Run "npx nylorun start" in this project to start its stack and link it, ` +
|
|
15
|
+
`or set NYLORUN_RUNTIME_URL and NYLORUN_SERVER_KEY.`);
|
|
16
16
|
}
|
|
17
17
|
function stripTrailingSlash(url) {
|
|
18
18
|
return url.replace(/\/$/, "");
|
|
@@ -37,30 +37,32 @@ async function readProjectLink(startDir) {
|
|
|
37
37
|
throw error;
|
|
38
38
|
}
|
|
39
39
|
const link = ProjectLinkFileSchema.parse(JSON.parse(linkRaw));
|
|
40
|
+
// Formats 0 and 1 named a Tenant on a multi-Tenant Host of an older Runtime.
|
|
41
|
+
if (link.format < 2)
|
|
42
|
+
throw new ConnectionError(`connection_missing: the Project link at ${linkPath} is for a stack of an older ` +
|
|
43
|
+
`Runtime, before one Tenant per installation. Run "npx nylorun start" in this project ` +
|
|
44
|
+
`to start its own stack and link it again.`);
|
|
40
45
|
const credentials = ProjectCredentialsFileSchema.parse(JSON.parse(await readFile(join(nylorun, "credentials.json"), "utf8")));
|
|
41
46
|
return {
|
|
42
47
|
url: stripTrailingSlash(link.hostUrl),
|
|
43
|
-
tenant: link.tenantId,
|
|
44
48
|
key: credentials.applicationKey,
|
|
45
49
|
source: "project-link",
|
|
46
50
|
};
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Resolve Tenant API connection: options → environment → project link (D§7.1). A connection is a
|
|
55
|
+
* Runtime URL and a key: the Runtime serves one Tenant, so nothing names it.
|
|
56
|
+
*/
|
|
50
57
|
export async function resolveConnection(options) {
|
|
51
58
|
const tried = [];
|
|
52
59
|
const optionUrl = options?.url;
|
|
53
|
-
const optionTenant = options?.tenant;
|
|
54
60
|
const optionKey = options?.key;
|
|
55
|
-
const anyOption = optionUrl !== undefined ||
|
|
56
|
-
optionTenant !== undefined ||
|
|
57
|
-
optionKey !== undefined;
|
|
58
61
|
tried.push("options");
|
|
59
|
-
if (
|
|
60
|
-
if (optionUrl &&
|
|
62
|
+
if (optionUrl !== undefined || optionKey !== undefined) {
|
|
63
|
+
if (optionUrl && optionKey) {
|
|
61
64
|
return {
|
|
62
65
|
url: stripTrailingSlash(optionUrl),
|
|
63
|
-
tenant: optionTenant,
|
|
64
66
|
key: optionKey,
|
|
65
67
|
source: "options",
|
|
66
68
|
};
|
|
@@ -68,17 +70,12 @@ export async function resolveConnection(options) {
|
|
|
68
70
|
missing(tried.concat(["environment", "project-link"]));
|
|
69
71
|
}
|
|
70
72
|
const envUrl = env("NYLORUN_RUNTIME_URL");
|
|
71
|
-
const envTenant = env("NYLORUN_TENANT");
|
|
72
73
|
const envServerKey = env("NYLORUN_SERVER_KEY");
|
|
73
|
-
const anyEnv = envUrl !== undefined ||
|
|
74
|
-
envTenant !== undefined ||
|
|
75
|
-
envServerKey !== undefined;
|
|
76
74
|
tried.push("environment");
|
|
77
|
-
if (
|
|
78
|
-
if (envUrl &&
|
|
75
|
+
if (envUrl !== undefined || envServerKey !== undefined) {
|
|
76
|
+
if (envUrl && envServerKey) {
|
|
79
77
|
return {
|
|
80
78
|
url: stripTrailingSlash(envUrl),
|
|
81
|
-
tenant: envTenant,
|
|
82
79
|
key: envServerKey,
|
|
83
80
|
source: "environment",
|
|
84
81
|
};
|
package/dist/delivery-token.d.ts
CHANGED
|
@@ -22,9 +22,15 @@ export declare class DeliveryVerificationError extends Error {
|
|
|
22
22
|
}
|
|
23
23
|
/** Finds the public key for a `kid`, or `undefined` when the Tenant has none. */
|
|
24
24
|
export type KeyLookup = (kid: string) => Promise<CryptoKey | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Verifies `token` against `body`. The keys are the installation's, so a valid signature already
|
|
27
|
+
* binds the issuer to its one Tenant: any `urn:nylorun:tenant:<id>` issuer is accepted (and
|
|
28
|
+
* returned in `iss`) unless `tenantId` names the one expected.
|
|
29
|
+
*/
|
|
25
30
|
export declare function verifyDeliveryToken(token: string | null, options: {
|
|
26
31
|
keys: KeyLookup;
|
|
27
|
-
|
|
32
|
+
/** When set, `iss` must name this Tenant. */
|
|
33
|
+
tenantId?: string;
|
|
28
34
|
body: Uint8Array;
|
|
29
35
|
/** When set, `aud` must equal it: the URL this endpoint was registered with. */
|
|
30
36
|
audience?: string;
|
|
@@ -45,7 +51,6 @@ export declare class JwksCache {
|
|
|
45
51
|
private pending;
|
|
46
52
|
constructor(source: {
|
|
47
53
|
url: string;
|
|
48
|
-
tenant: string;
|
|
49
54
|
key?: string;
|
|
50
55
|
fetch?: typeof fetch;
|
|
51
56
|
} | {
|
package/dist/delivery-token.js
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* only, so the SDK takes no JWT dependency: a JWS ES256 signature is the raw `r || s` pair
|
|
5
5
|
* WebCrypto's ECDSA verifies.
|
|
6
6
|
*/
|
|
7
|
-
import { PROTOCOL_HEADER, PROTOCOL_VERSION,
|
|
7
|
+
import { PROTOCOL_HEADER, PROTOCOL_VERSION, isTenantId } from "@nylorun/core/compatibility";
|
|
8
8
|
import { DELIVERY_TOKEN_TYPE, subjectTokenIssuer } from "@nylorun/core/contracts";
|
|
9
|
+
/** The issuer prefix of a Tenant's tokens: `urn:nylorun:tenant:<tenantId>`. */
|
|
10
|
+
const ISSUER_PREFIX = subjectTokenIssuer("");
|
|
9
11
|
/** Why a delivery was refused; `code` is sent back to the Runtime. */
|
|
10
12
|
export class DeliveryVerificationError extends Error {
|
|
11
13
|
code;
|
|
@@ -20,6 +22,11 @@ const SKEW_SECONDS = 30;
|
|
|
20
22
|
const FORBIDDEN_HEADERS = ["jku", "jwk", "x5u", "x5c", "x5t", "x5t#S256", "crit"];
|
|
21
23
|
/** The largest token accepted: well above a real one, well below a request limit. */
|
|
22
24
|
const MAX_TOKEN_LENGTH = 4096;
|
|
25
|
+
/**
|
|
26
|
+
* Verifies `token` against `body`. The keys are the installation's, so a valid signature already
|
|
27
|
+
* binds the issuer to its one Tenant: any `urn:nylorun:tenant:<id>` issuer is accepted (and
|
|
28
|
+
* returned in `iss`) unless `tenantId` names the one expected.
|
|
29
|
+
*/
|
|
23
30
|
export async function verifyDeliveryToken(token, options) {
|
|
24
31
|
if (!token)
|
|
25
32
|
throw new DeliveryVerificationError("signature_missing", "No delivery token");
|
|
@@ -50,7 +57,10 @@ export async function verifyDeliveryToken(token, options) {
|
|
|
50
57
|
typeof claims.exp !== "number" ||
|
|
51
58
|
typeof claims.jti !== "string")
|
|
52
59
|
throw invalid("Missing claims");
|
|
53
|
-
if (claims.iss
|
|
60
|
+
if (!claims.iss.startsWith(ISSUER_PREFIX) ||
|
|
61
|
+
!isTenantId(claims.iss.slice(ISSUER_PREFIX.length)))
|
|
62
|
+
throw invalid("The token was not issued by a Tenant");
|
|
63
|
+
if (options.tenantId !== undefined && claims.iss !== subjectTokenIssuer(options.tenantId))
|
|
54
64
|
throw invalid("The token is for another Tenant");
|
|
55
65
|
if (options.audience !== undefined && claims.aud !== options.audience)
|
|
56
66
|
throw invalid(`The token is for ${claims.aud}, not ${options.audience}`);
|
|
@@ -111,7 +121,6 @@ export class JwksCache {
|
|
|
111
121
|
}
|
|
112
122
|
async fetchKeys(source) {
|
|
113
123
|
const headers = {
|
|
114
|
-
[TENANT_HEADER]: source.tenant,
|
|
115
124
|
[PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
|
|
116
125
|
};
|
|
117
126
|
if (source.key)
|
package/dist/http.d.ts
CHANGED
|
@@ -8,14 +8,17 @@ export interface TokenSource {
|
|
|
8
8
|
get(signal?: AbortSignal): Promise<string>;
|
|
9
9
|
invalidate(): void;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Where a client sends its requests. Nothing names a Tenant: the Runtime at `url` serves one
|
|
13
|
+
* (protocol 5).
|
|
14
|
+
*/
|
|
11
15
|
export interface Destination {
|
|
12
16
|
url?: string;
|
|
13
17
|
key?: string;
|
|
14
|
-
tenant?: string;
|
|
15
18
|
fetch?: typeof fetch;
|
|
16
19
|
/** Instead of `key`: subject tokens. The client then skips the `/health` check. */
|
|
17
20
|
token?: TokenSource;
|
|
18
|
-
/** A publishable key (Host feature `browser-access`)
|
|
21
|
+
/** A publishable key (Host feature `browser-access`): names the app and its origins. */
|
|
19
22
|
publishableKey?: string;
|
|
20
23
|
}
|
|
21
24
|
export declare function env(name: string): string | undefined;
|
|
@@ -38,8 +41,6 @@ export declare class Transport {
|
|
|
38
41
|
readonly url: string;
|
|
39
42
|
/** The Tenant key; empty for a client that uses subject tokens. */
|
|
40
43
|
readonly key: string;
|
|
41
|
-
/** The Tenant id; empty when a publishable key names it. */
|
|
42
|
-
readonly tenant: string;
|
|
43
44
|
readonly token: TokenSource | undefined;
|
|
44
45
|
readonly publishableKey: string | undefined;
|
|
45
46
|
readonly fetcher: typeof fetch;
|
package/dist/http.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROTOCOL_FEATURES, PROTOCOL_HEADER, PROTOCOL_VERSION, PUBLISHABLE_KEY_HEADER,
|
|
1
|
+
import { PROTOCOL_FEATURES, PROTOCOL_HEADER, PROTOCOL_VERSION, PUBLISHABLE_KEY_HEADER, checkCompatibility, } from "@nylorun/core/compatibility";
|
|
2
2
|
export function env(name) {
|
|
3
3
|
return typeof process !== "undefined" ? process.env[name] : undefined;
|
|
4
4
|
}
|
|
@@ -56,8 +56,6 @@ export class Transport {
|
|
|
56
56
|
url;
|
|
57
57
|
/** The Tenant key; empty for a client that uses subject tokens. */
|
|
58
58
|
key;
|
|
59
|
-
/** The Tenant id; empty when a publishable key names it. */
|
|
60
|
-
tenant;
|
|
61
59
|
token;
|
|
62
60
|
publishableKey;
|
|
63
61
|
fetcher;
|
|
@@ -68,19 +66,15 @@ export class Transport {
|
|
|
68
66
|
const url = options.url ?? env("NYLORUN_RUNTIME_URL");
|
|
69
67
|
const token = options.token;
|
|
70
68
|
const key = token ? "" : options.key ?? env("NYLORUN_SERVER_KEY");
|
|
71
|
-
const tenant = options.tenant ?? (token ? undefined : env("NYLORUN_TENANT"));
|
|
72
69
|
if (!url || (!token && !key))
|
|
73
70
|
throw new Error("Set Runtime url and server key explicitly or via NYLORUN_RUNTIME_URL / NYLORUN_SERVER_KEY");
|
|
74
71
|
if (token && options.key)
|
|
75
72
|
throw new Error("Use a Tenant key or subject tokens, not both");
|
|
76
|
-
if (!tenant && !options.publishableKey)
|
|
77
|
-
throw new Error("Set tenant explicitly or via NYLORUN_TENANT");
|
|
78
73
|
const parsed = new URL(url);
|
|
79
74
|
if (!["http:", "https:"].includes(parsed.protocol))
|
|
80
75
|
throw new Error("Runtime requires an HTTP(S) URL");
|
|
81
76
|
this.url = url.replace(/\/$/, "");
|
|
82
77
|
this.key = key;
|
|
83
|
-
this.tenant = tenant ?? "";
|
|
84
78
|
this.token = token;
|
|
85
79
|
this.publishableKey = options.publishableKey;
|
|
86
80
|
// Browsers may not call `/health` (it refuses `Origin`); token clients rely on `426`.
|
|
@@ -171,8 +165,6 @@ export class Transport {
|
|
|
171
165
|
? await this.token.get(init.signal ?? undefined)
|
|
172
166
|
: this.key;
|
|
173
167
|
headers.set("Authorization", `Bearer ${bearer}`);
|
|
174
|
-
if (this.tenant)
|
|
175
|
-
headers.set(TENANT_HEADER, this.tenant);
|
|
176
168
|
if (this.publishableKey)
|
|
177
169
|
headers.set(PUBLISHABLE_KEY_HEADER, this.publishableKey);
|
|
178
170
|
headers.set(PROTOCOL_HEADER, String(PROTOCOL_VERSION));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION,
|
|
1
|
+
export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION, PROTOCOL_HEADER, SUBJECT_HEADER, SCOPES_HEADER, TENANT_ID_PATTERN, isTenantId, newTenantId, newPrincipalId, checkCompatibility, compareVersions, ERROR_CODES, } from "@nylorun/core/compatibility";
|
|
2
2
|
export type { ProtocolFeature, ProtocolRange, Compatibility, ErrorCode, } from "@nylorun/core/compatibility";
|
|
3
3
|
export { Agent, AgentBuilder } from "./builder.js";
|
|
4
4
|
export { AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, defineSchema, ToolError, } from "@nylorun/core/define";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Definition authoring and wire contracts are the only harness runtime imports.
|
|
2
|
-
export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION,
|
|
2
|
+
export { hashManifest, PROTOCOL_VERSION, PROTOCOL_FEATURES, HOST_PROTOCOL, DEFINITION_SCHEMA_VERSION, PROTOCOL_HEADER, SUBJECT_HEADER, SCOPES_HEADER, TENANT_ID_PATTERN, isTenantId, newTenantId, newPrincipalId, checkCompatibility, compareVersions, ERROR_CODES, } from "@nylorun/core/compatibility";
|
|
3
3
|
export { Agent, AgentBuilder } from "./builder.js";
|
|
4
4
|
export { AgentBuildError, AgentLifecycleError, Loop, Chain, Switch, Parallel, Map, VerdictSchema, isVerdict, withInstructions, withoutTools, WorkflowBuildError, isBuiltWorkflow, capability, CapabilityBuilder, flow, tool, defineSchema, ToolError, } from "@nylorun/core/define";
|
|
5
5
|
export { SUBJECT_SCOPES } from "@nylorun/core/contracts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0-beta",
|
|
4
4
|
"description": "Nylorun agent definitions, session client and Action endpoint",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"test": "vitest run --passWithNoTests"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@nylorun/core": "0.
|
|
50
|
+
"@nylorun/core": "0.10.0-beta",
|
|
51
51
|
"gray-matter": "^4.0.3"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|