@nylorun/agents 0.13.0-beta → 0.14.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 +27 -0
- package/README.md +36 -123
- package/dist/access.d.ts +6 -77
- package/dist/access.js +2 -79
- package/dist/ag-ui/handler.d.ts +3 -6
- package/dist/ag-ui/handler.js +2 -2
- package/dist/artifacts.d.ts +1 -1
- package/dist/delivery-token.js +3 -3
- package/dist/http.d.ts +6 -8
- package/dist/http.js +4 -8
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -2
- package/dist/session-client.d.ts +19 -14
- package/dist/session-client.js +15 -12
- package/dist/sse.js +1 -1
- package/dist/studio-embed.d.ts +1 -1
- package/dist/studio-embed.js +1 -1
- package/package.json +2 -6
- package/dist/browser.d.ts +0 -104
- package/dist/browser.js +0 -281
- package/dist/token-endpoint.d.ts +0 -23
- package/dist/token-endpoint.js +0 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
+
## 0.14.0-beta
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- bd478ee: **Subject tokens, browser keys and derived principals leave open source (F9 I3, protocol 7).** Upgrade these with the Runtime: they speak protocol 7, which this Runtime serves beside 4, 5 and 6; protocol 6 clients keep working on every route that remains. Browsers and apps present a trusted issuer's token (F9 I2), servers an operator key (F9 I1), and a person's own credentials come from the operator's credential resolver (F9 C1). See MIGRATION.md.
|
|
8
|
+
|
|
9
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): subject tokens are gone.** `POST /v1/tokens`, `POST /v1/access/revocations`, subject-token verification, revocation epochs and the `subject.revoked` stream signal are removed; the routes answer `404`, and a JWT no trusted issuer signed is the opaque `404`. A stream opened with a token now ends only at its expiry (`event: nylorun.closed`, reason `token_expired`; `StreamClosedFrame` loses `revoked`). Migration `0010_oss_auth_removals` drops the `subject_epochs`, `subject_usage` and `publishable_keys` tables. The `token` caller is a trusted issuer's token only: it loses `role`, `limits` and `epoch`, and `issuer` is always set; `GET /v1/me` no longer reports `via: token`. Core drops `SUBJECT_TOKEN_TYPE`, `SUBJECT_TOKEN_AUDIENCE`, `subjectTokenIssuer` (the Runtime's own tokens use `tenantTokenIssuer`, same value), `CreateTokenRequest`/`Response`, `RevokeSubject*`, `SubjectTokenClaims`, `TOKEN_TTL_MIN_SECONDS` and `TOKEN_TTL_DEFAULT_SECONDS`; `TOKEN_SCOPES` is `agents:read`, `sessions:own`, `sandboxes:write`.
|
|
10
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): the access policy and role limits are gone.** `GET`/`PUT /v1/access/policy` answer `404`, a turn is never refused with `429 limit_exceeded` for a role (limit requests at your proxy), and an existing `access.policy` setting is ignored. Core drops `AccessPolicy*`, `AccessRole*`, `RoleLimits*`, `DEFAULT_ACCESS_POLICY`, `PutAccessPolicyRequest` and `ROLE_NAME_PATTERN`.
|
|
11
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): publishable keys and the Runtime's CORS are gone.** `/v1/access/publishable-keys*` answer `404`, `Nylorun-Key` is ignored, `NYLORUN_BROWSER_ACCESS` and `browserAccess` (host.json, `createHost`, `startEphemeralRuntime`) are removed, and the Runtime sends no CORS headers. A request with `Origin` reaches the Tenant routes of the public listener with no toggle: a trusted issuer's token is served, an application key or delivery token is `403 origin_rejected`; admin routes, `/health`, `/ready` and the operator listener still refuse `Origin`. Any `OPTIONS` request is `204` with `Allow` and no CORS header: the operator's proxy answers preflights. Route declarations lose `browser` (`x-nylorun-browser` leaves the OpenAPI document) and the `publishable` credential; the token security scheme is `issuerToken`. Core drops `PUBLISHABLE_KEY_HEADER`, `PUBLISHABLE_KEY_PATTERN`, `PUBLISHABLE_KEY_ID_PATTERN`, `tenantOfPublishableKey`, `newPublishableKey`, `newPublishableKeyId`, `PublishableKey*`, `OriginEntrySchema`, `originAllowed` and `LOOPBACK_ORIGIN_WILDCARDS`.
|
|
12
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/agents`): vault routes are application-only, and `vaults:own` is retired.** Every `/v1/vaults` route takes an application key acting for no one (operator keys, Studio); a request acting for a subject or a trusted issuer's token gets `403 scope_required`. `vaults:own` leaves `SUBJECT_SCOPES`, `TOKEN_SCOPES` and the issuer scopes; `Nylorun-Scopes` may still name it and it grants nothing. Existing user vaults stay attachable to their own owner's sessions. `client.createVault` takes `{ scope: "installation" }` or `ownerUserId`, and `client.listVaults()` takes an optional owner.
|
|
13
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/admin`, `nylorun`): derived principals are gone.** Only Studio's key is derived from the admin key. `NYLORUN_DERIVED_PRINCIPALS` is ignored and no longer written, `hostPrincipals` takes no `derived`, `startEphemeralRuntime` no `derivedPrincipals`, and `@nylorun/admin` drops `deriveTenantKey`, `PROJECT_PRINCIPAL_ID` and `admin.deriveTenantKey`. Keys an earlier Host derived stay in the database and keep working as ordinary keys; replace them with operator keys. Core renames `DERIVED_PRINCIPAL_ID_PATTERN` to `APPLICATION_KEY_ID_PATTERN`.
|
|
14
|
+
- **Breaking (`@nylorun/agents`):** `createTokenEndpoint`, `createBrowserClient` and the `@nylorun/agents/browser` entry, `client.tokens`, `TokensClient`, `PublishableKeysClient`, `client.access.getPolicy`/`putPolicy`/`revokeSubject`/`publishableKeys` and `Destination.publishableKey` are removed. `client.access.signingKeys` and `client.access.jwks()` stay, and `Destination.token` takes a trusted issuer's tokens.
|
|
15
|
+
- **Breaking (`@nylorun/cli`):** `nylo access policy|keys|revoke|token` are removed and name what replaces them; `nylo access signing-keys list|rotate|revoke` stays.
|
|
16
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`, `@nylorun/studio`): the Studio embed message `open.babai` is now `open.session`** (`{ sessionId }`): it asks the embedding app to open that session in its own UI. Studio sends no such message itself.
|
|
17
|
+
- **Breaking (`nylorun`): Studio embedding is opt-in.** No origin may frame Studio by default; list your app's origins with `nylorun start --studio-embed-origin <origin>`. A Tenant's `.env` from an earlier nylorun keeps the origins it had until `--studio-embed-origin-reset`.
|
|
18
|
+
- `PROTOCOL_VERSION` is 7 and `HOST_PROTOCOL` 4–7; the Host features `subject-tokens`, `browser-access` and `derived-principals` are removed. `@nylorun/studio` and `@nylorun/create-agent` speak protocol 7.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Pin core to the tested release.
|
|
23
|
+
- Updated dependencies [8773586]
|
|
24
|
+
- Updated dependencies [e1bfb4b]
|
|
25
|
+
- Updated dependencies [5cfaed9]
|
|
26
|
+
- Updated dependencies [bd478ee]
|
|
27
|
+
- Updated dependencies [c0b604e]
|
|
28
|
+
- @nylorun/core@0.13.0-beta
|
|
29
|
+
|
|
3
30
|
## 0.13.0-beta
|
|
4
31
|
|
|
5
32
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -171,7 +171,7 @@ await client.sandboxes.ensure("team-a/proj-42", { labels: { project: "acme" } })
|
|
|
171
171
|
await client.createSession({ agentId: "analyst", ownerUserId, sandbox: { id: "team-a/proj-42" } });
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
Sessions attached to one sandbox share its `/workspace`, and one turn runs in it at a time: a second session's turn is refused with `409 sandbox_busy` until the first ends. Deleting a session only detaches it. A spec is fixed once the sandbox exists; `labels` can change. `client.sandboxes.list({ labels })`, `get(id)` and `delete(id)` manage them, and `npx nylorun sandbox ls | rm` does the same on a local Tenant. A
|
|
174
|
+
Sessions attached to one sandbox share its `/workspace`, and one turn runs in it at a time: a second session's turn is refused with `409 sandbox_busy` until the first ends. Deleting a session only detaches it. A spec is fixed once the sandbox exists; `labels` can change. `client.sandboxes.list({ labels })`, `get(id)` and `delete(id)` manage them, and `npx nylorun sandbox ls | rm` does the same on a local Tenant. A trusted issuer's token reaches only the sandboxes its issuer grants (the identity file's `sandboxes` templates, exact ids or prefixes ending in `/*`), checked at every turn start; creating and deleting through one needs `sandboxes:write`. The Tenant holds at most `limits.sandboxes` of them (`PUT /v1/tenant/sandbox`, default 100).
|
|
175
175
|
|
|
176
176
|
Add an agent with `.subagents()` to let the model delegate to it:
|
|
177
177
|
|
|
@@ -313,9 +313,10 @@ thread is one session per person, agent and thread. There are two ways in:
|
|
|
313
313
|
- **From your own server**, with `@nylorun/agents/ag-ui` (below): your server
|
|
314
314
|
signs people in and the handler forwards each request to the Runtime acting
|
|
315
315
|
for that person. The browser never sees the Runtime.
|
|
316
|
-
- **From the page itself**, with `@
|
|
317
|
-
|
|
318
|
-
through your
|
|
316
|
+
- **From the page itself**, with `@ag-ui/client`'s `HttpAgent` and a `fetch`
|
|
317
|
+
that sends your identity provider's token
|
|
318
|
+
([In the browser](#in-the-browser)). No chat traffic passes through your
|
|
319
|
+
server.
|
|
319
320
|
|
|
320
321
|
Both reach the same threads: one started through the handler continues from
|
|
321
322
|
the page.
|
|
@@ -362,8 +363,7 @@ created, on its first run; later runs keep them. Whatever the browser sends in
|
|
|
362
363
|
- A busy or paused thread ends the run with `RUN_ERROR` code `session_busy`.
|
|
363
364
|
- The handler calls the Runtime as each person (`client.as(subject, { scopes })`,
|
|
364
365
|
below), so the Runtime itself keeps one person out of another's threads.
|
|
365
|
-
`scopes` defaults to `["sessions:own"]
|
|
366
|
-
attaches the person's vaults. A `subject` the Runtime cannot name (see below)
|
|
366
|
+
`scopes` defaults to `["sessions:own"]`. A `subject` the Runtime cannot name (see below)
|
|
367
367
|
answers `500` (`subject_invalid`).
|
|
368
368
|
- The handler needs a Runtime with the optional feature `ag-ui-endpoint` and
|
|
369
369
|
answers `502` (`runtime_feature_missing`) without it. It loads no AG-UI
|
|
@@ -376,8 +376,8 @@ Limitations: assistant text arrives once per model step (no token streaming);
|
|
|
376
376
|
no reasoning, state, activity or subagent events, and an agent used as a tool
|
|
377
377
|
shows only its result; frontend tools in `RunAgentInput.tools` are rejected
|
|
378
378
|
(`400`); one text part per user message; earlier messages cannot be edited or
|
|
379
|
-
regenerated. A browser reaches the Runtime only with a
|
|
380
|
-
|
|
379
|
+
regenerated. A browser reaches the Runtime only with a trusted issuer's token,
|
|
380
|
+
never with a Tenant key.
|
|
381
381
|
|
|
382
382
|
## A2A
|
|
383
383
|
|
|
@@ -467,7 +467,7 @@ made as an artifact of the session; each new artifact or version appears in the
|
|
|
467
467
|
session's events as `artifact.created` or `artifact.version.created`. The Tenant's
|
|
468
468
|
limits (`PUT /v1/tenant/artifacts`: 100 MiB per file and 10 GiB in all by default)
|
|
469
469
|
refuse a larger upload with `413 limit_exceeded`, and nothing is stored. Acting for
|
|
470
|
-
a person (`as()`, a
|
|
470
|
+
a person (`as()`, or a trusted issuer's token), a client reaches only the artifacts of that
|
|
471
471
|
person's sessions, and an upload names one of them.
|
|
472
472
|
|
|
473
473
|
### Outputs: folder artifacts
|
|
@@ -503,147 +503,58 @@ import { createClient } from "@nylorun/agents";
|
|
|
503
503
|
const app = createClient(); // the Tenant key, on the server only
|
|
504
504
|
|
|
505
505
|
// Per request, after your own sign-in:
|
|
506
|
-
const person = app.as(`app:${user.id}`, { scopes: ["sessions:own"
|
|
506
|
+
const person = app.as(`app:${user.id}`, { scopes: ["sessions:own"] });
|
|
507
507
|
await person.createSession({ agentId: "support", ownerUserId: `app:${user.id}` });
|
|
508
508
|
await person.listSessions(); // only this person's sessions
|
|
509
509
|
```
|
|
510
510
|
|
|
511
511
|
`as()` sends `Nylorun-Subject` and `Nylorun-Scopes` on every call, event
|
|
512
512
|
streams included, and the Runtime (optional feature `subject-headers`)
|
|
513
|
-
enforces both: another person's sessions
|
|
514
|
-
|
|
513
|
+
enforces both: another person's sessions answer the same `404` as missing
|
|
514
|
+
ones, and a route outside the scopes answers `403` (`scope_required`).
|
|
515
515
|
Nothing is minted, cached or refreshed, and the copy shares the client's
|
|
516
516
|
compatibility check, so calling `as()` per request is cheap.
|
|
517
517
|
|
|
518
518
|
| Scope | Allows |
|
|
519
519
|
| --- | --- |
|
|
520
520
|
| `sessions:own` | The person's own sessions: create, list, read, stream, message, approve, respond, cancel; and their artifacts |
|
|
521
|
-
| `vaults:own` | The person's own vaults and credentials |
|
|
522
521
|
| `agents:read` | Listing the Tenant's agents |
|
|
523
522
|
| `agents:write` | Saving agents; listing agents, models and providers |
|
|
524
523
|
| `tenant:settings` | The Tenant's status, model provider and sandbox settings |
|
|
525
524
|
|
|
526
|
-
No scope reaches Tenant reset, config seed, Action endpoints, actions or
|
|
527
|
-
tool routes; call those without `as()`.
|
|
525
|
+
No scope reaches Tenant reset, config seed, Action endpoints, actions, vaults or
|
|
526
|
+
the sandbox tool routes; call those without `as()`. Vaults are the
|
|
527
|
+
installation's (`createVault({ scope: "installation", … })`); a person's own
|
|
528
|
+
credentials come from your credential resolver
|
|
529
|
+
([DEPLOYMENT.md](../DEPLOYMENT.md#credentials)). A subject is 1–200 visible ASCII
|
|
528
530
|
characters (spaces only inside) and `host` is reserved. Your server must drop
|
|
529
531
|
any `Nylorun-*` header its own clients send, and only an application key can act
|
|
530
532
|
for a subject.
|
|
531
533
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
(optional feature `subject-tokens`). What a token may do comes from the Tenant's
|
|
537
|
-
access policy, not from the caller:
|
|
538
|
-
|
|
539
|
-
```ts
|
|
540
|
-
import { createClient } from "@nylorun/agents";
|
|
541
|
-
|
|
542
|
-
const app = createClient(); // the Tenant key, on the server only
|
|
543
|
-
|
|
544
|
-
// Once: roles, their agents and limits (or `nylo access policy init`).
|
|
545
|
-
await app.access.putPolicy({
|
|
546
|
-
version: 1,
|
|
547
|
-
roles: {
|
|
548
|
-
user: {
|
|
549
|
-
scopes: ["sessions:own", "agents:read"],
|
|
550
|
-
agents: ["support"],
|
|
551
|
-
limits: { turnsPerHour: 60, concurrentTurns: 2 },
|
|
552
|
-
},
|
|
553
|
-
},
|
|
554
|
-
anon: { scopes: [], agents: [] },
|
|
555
|
-
tokens: { maxTtlSeconds: 600 },
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
// Per signed-in person, from a same-origin POST route:
|
|
559
|
-
const { token, expiresAt } = await app.tokens.create({
|
|
560
|
-
subject: `app:${user.id}`,
|
|
561
|
-
role: "user",
|
|
562
|
-
});
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
The client sends it as `Authorization: Bearer <token>`.
|
|
566
|
-
Tokens carry only `sessions:own`, `vaults:own` and `agents:read`, live at most
|
|
567
|
-
15 minutes, and see only `{ agentId, name, description }` of their role's
|
|
568
|
-
agents. A token that expired or was revoked answers `401` with
|
|
569
|
-
`code: "token_expired"`: fetch a new one and retry. Starting more turns than the
|
|
570
|
-
role allows answers `429` with `code: "limit_exceeded"` and `Retry-After`.
|
|
571
|
-
|
|
572
|
-
| Call | Does |
|
|
573
|
-
| --- | --- |
|
|
574
|
-
| `app.access.revokeSubject(subject)` | Ends every token minted so far for the person and their open event streams |
|
|
575
|
-
| `app.access.signingKeys.rotate()` | Rotates the Tenant's signing keys without signing anyone out (`{ force: true }` for incidents) |
|
|
576
|
-
| `app.access.signingKeys.list()`, `.revoke(kid)`, `app.access.jwks()` | Inspect and retire keys; the public keys |
|
|
577
|
-
|
|
578
|
-
Keep tokens in memory on the client, never in `localStorage`, and serve the
|
|
579
|
-
minting route without CORS. `nylo access …` does the same from the terminal.
|
|
580
|
-
|
|
581
|
-
`createTokenEndpoint` is that route, ready to mount (Next.js, Hono or any
|
|
582
|
-
`Request` → `Response` handler):
|
|
583
|
-
|
|
584
|
-
```ts
|
|
585
|
-
import { createTokenEndpoint } from "@nylorun/agents";
|
|
586
|
-
|
|
587
|
-
export const POST = createTokenEndpoint({
|
|
588
|
-
client: app,
|
|
589
|
-
role: "user",
|
|
590
|
-
subject: (request) => userFromCookie(request)?.id,
|
|
591
|
-
});
|
|
592
|
-
```
|
|
534
|
+
The Tenant's signing keys sign delivery tokens and capability links:
|
|
535
|
+
`app.access.signingKeys.list()`, `.rotate()` (`{ force: true }` for incidents),
|
|
536
|
+
`.revoke(kid)` and `app.access.jwks()`, or `nylo access signing-keys …` from the
|
|
537
|
+
terminal.
|
|
593
538
|
|
|
594
539
|
## In the browser
|
|
595
540
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
token: () => fetch("/api/nylorun/token", { method: "POST" }).then((r) => r.json()),
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
const session = await nylo.createSession({ agentId: "support" }); // owned by the token's subject
|
|
610
|
-
await session.input("Where is my order?", { idempotencyKey: crypto.randomUUID() });
|
|
611
|
-
for await (const event of session.observe()) console.log(event.type);
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
For a chat UI, `agUi()` gives `@ag-ui/client`'s `HttpAgent` a `fetch` with the
|
|
615
|
-
key and a current token:
|
|
616
|
-
|
|
617
|
-
```ts
|
|
618
|
-
import { HttpAgent } from "@ag-ui/client";
|
|
619
|
-
|
|
620
|
-
const { url, fetch } = nylo.agUi("support");
|
|
621
|
-
const agent = new HttpAgent({
|
|
622
|
-
url,
|
|
623
|
-
fetch,
|
|
624
|
-
threadId,
|
|
625
|
-
initialMessages: await nylo.agUiHistory("support", threadId),
|
|
626
|
-
});
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
When the Runtime ends a run's stream because the token expired or was revoked,
|
|
630
|
-
that `fetch` reattaches from the last event with a new token, so the agent sees
|
|
631
|
-
one run. A person's token may attach their own vaults to a new thread
|
|
632
|
-
(`forwardedProps: { nylorun: { session: { vaultIds } } }`) but not set `info`.
|
|
633
|
-
|
|
634
|
-
The client keeps the token in memory, fetches a new one a minute before it
|
|
635
|
-
expires or when the Runtime answers `401 token_expired`, and never asks for two
|
|
636
|
-
at once. Event streams that the Runtime ends at token expiry or revocation
|
|
637
|
-
reconnect from their last event with a new token. Create a publishable key per
|
|
638
|
-
app with the origins that serve it (`http://localhost:*` for development);
|
|
639
|
-
requests from other origins get the opaque `404`.
|
|
541
|
+
A web page or an app calls the Runtime directly with the JWT your identity
|
|
542
|
+
provider gave the person: list the provider in the Runtime's identity file
|
|
543
|
+
([Trusted issuers](../DEPLOYMENT.md#trusted-issuers)), and the Runtime takes the
|
|
544
|
+
token's subject, scopes, agents and sandbox grants from it. Nylorun mints no
|
|
545
|
+
token and ships no browser client: use your provider's SDK for sign-in and send
|
|
546
|
+
the token as `Authorization: Bearer <token>` with `Nylorun-Protocol`, through a
|
|
547
|
+
reverse proxy that answers CORS (the Runtime sends no CORS headers). An expired
|
|
548
|
+
token answers `401` with `code: "token_expired"`; `GET /v1/me` shows what a token
|
|
549
|
+
renders to. For a chat UI, give `@ag-ui/client`'s `HttpAgent` a `fetch` that adds
|
|
550
|
+
those headers.
|
|
640
551
|
|
|
641
|
-
The SDK depends only on core within the Nylorun packages; installing it does not install harness or any AG-UI or A2A package. Use `/define`, `/client`, `/ag-ui
|
|
552
|
+
The SDK depends only on core within the Nylorun packages; installing it does not install harness or any AG-UI or A2A package. Use `/define`, `/client`, `/ag-ui` or `/a2a` for focused imports, or the root for convenience. Studio uses `/client`. See [the adopted host contract](../harness/HOST_CONTRACT.md).
|
|
642
553
|
|
|
643
554
|
## Embedding Studio (desktop apps)
|
|
644
555
|
|
|
645
556
|
`@nylorun/agents/studio-embed` is the contract between Studio and an app that
|
|
646
|
-
shows it in an iframe
|
|
557
|
+
shows it in an iframe. It exports the message schema
|
|
647
558
|
(`StudioEmbedMessageSchema`, envelope `{ type: "nylorun.studio", protocol, kind }`),
|
|
648
559
|
the login-token and session schemas, `STUDIO_EMBED_PROTOCOLS` and
|
|
649
560
|
`parseFrameAncestors`.
|
|
@@ -662,4 +573,6 @@ window.addEventListener("message", (event) => {
|
|
|
662
573
|
The embedder's backend mints the login token with the admin key
|
|
663
574
|
(`mintStudioLoginToken` in `@nylorun/admin`) and the page passes it to Studio in
|
|
664
575
|
`init`. No key reaches the page. Studio's origin allowlist is
|
|
665
|
-
`NYLORUN_STUDIO_FRAME_ANCESTORS
|
|
576
|
+
`NYLORUN_STUDIO_FRAME_ANCESTORS`, empty by default: list your app's origins with
|
|
577
|
+
`nylorun start --studio-embed-origin <origin>`. The message `open.session`
|
|
578
|
+
(`{ sessionId }`) asks the embedding app to open that session in its own UI.
|
package/dist/access.d.ts
CHANGED
|
@@ -1,35 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* revocations. Each call checks the Host feature before sending anything.
|
|
2
|
+
* The Tenant's signing keys and public keys, for app servers on the application key. The
|
|
3
|
+
* Runtime signs delivery tokens (Action endpoints) and capability links with them; an Action
|
|
4
|
+
* endpoint verifies delivery tokens with the public keys (`jwks`).
|
|
6
5
|
*/
|
|
7
|
-
import type {
|
|
6
|
+
import type { Jwks, SigningKeyView } from "@nylorun/core/contracts";
|
|
8
7
|
import { type Transport } from "./http.js";
|
|
9
|
-
export interface CreateTokenOptions {
|
|
10
|
-
/** The person the token is for, e.g. `app:42`. */
|
|
11
|
-
subject: string;
|
|
12
|
-
/** A role of the Tenant's access policy. */
|
|
13
|
-
role: string;
|
|
14
|
-
/** Narrow the role's scopes. Default: all of the role's scopes. */
|
|
15
|
-
scopes?: readonly TokenScope[];
|
|
16
|
-
/** Narrow the role's agents. Default: all of the role's agents. */
|
|
17
|
-
agents?: readonly string[];
|
|
18
|
-
/**
|
|
19
|
-
* The sandboxes the token reaches (its `sbx` claim): exact ids, or prefixes ending in `/*`
|
|
20
|
-
* (`team-a/*`). Default: none (Host feature `sandboxes`).
|
|
21
|
-
*/
|
|
22
|
-
sandboxes?: readonly string[];
|
|
23
|
-
/** 60 to 900 seconds, at most the policy's `maxTtlSeconds`. Default: that maximum. */
|
|
24
|
-
ttlSeconds?: number;
|
|
25
|
-
signal?: AbortSignal;
|
|
26
|
-
}
|
|
27
|
-
export declare class TokensClient {
|
|
28
|
-
private readonly transport;
|
|
29
|
-
constructor(transport: Transport);
|
|
30
|
-
/** Mints a subject token. Only the application key may; never acting for a subject. */
|
|
31
|
-
create(options: CreateTokenOptions): Promise<CreateTokenResponse>;
|
|
32
|
-
}
|
|
33
8
|
export declare class SigningKeysClient {
|
|
34
9
|
private readonly transport;
|
|
35
10
|
constructor(transport: Transport);
|
|
@@ -38,7 +13,7 @@ export declare class SigningKeysClient {
|
|
|
38
13
|
}): Promise<SigningKeyView[]>;
|
|
39
14
|
/**
|
|
40
15
|
* standby → current → previous → revoked, and a new standby. Refused while the previous key
|
|
41
|
-
* may still verify live tokens; `force` skips that and
|
|
16
|
+
* may still verify live tokens; `force` skips that and ends those tokens.
|
|
42
17
|
*/
|
|
43
18
|
rotate(options?: {
|
|
44
19
|
force?: boolean;
|
|
@@ -49,57 +24,11 @@ export declare class SigningKeysClient {
|
|
|
49
24
|
signal?: AbortSignal;
|
|
50
25
|
}): Promise<SigningKeyView>;
|
|
51
26
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Publishable keys (Host feature `browser-access`): shipped in a web page or an app, they name
|
|
54
|
-
* the Tenant and the app, and list the origins a browser may use them from.
|
|
55
|
-
*/
|
|
56
|
-
export declare class PublishableKeysClient {
|
|
57
|
-
private readonly transport;
|
|
58
|
-
constructor(transport: Transport);
|
|
59
|
-
list(options?: {
|
|
60
|
-
signal?: AbortSignal;
|
|
61
|
-
}): Promise<PublishableKey[]>;
|
|
62
|
-
/**
|
|
63
|
-
* A new key. `origins` are exact origins (`https://app.example.com`) or
|
|
64
|
-
* `http://localhost:*`; `[]` allows native apps only.
|
|
65
|
-
*/
|
|
66
|
-
create(options: {
|
|
67
|
-
name: string;
|
|
68
|
-
origins: readonly string[];
|
|
69
|
-
signal?: AbortSignal;
|
|
70
|
-
}): Promise<PublishableKey>;
|
|
71
|
-
/** Replaces the key's origins. */
|
|
72
|
-
update(keyId: string, options: {
|
|
73
|
-
origins: readonly string[];
|
|
74
|
-
signal?: AbortSignal;
|
|
75
|
-
}): Promise<PublishableKey>;
|
|
76
|
-
/** Revokes the key: every request that sends it gets the opaque 404. */
|
|
77
|
-
revoke(keyId: string, options?: {
|
|
78
|
-
signal?: AbortSignal;
|
|
79
|
-
}): Promise<PublishableKey>;
|
|
80
|
-
}
|
|
81
27
|
export declare class AccessClient {
|
|
82
28
|
private readonly transport;
|
|
83
29
|
readonly signingKeys: SigningKeysClient;
|
|
84
|
-
readonly publishableKeys: PublishableKeysClient;
|
|
85
30
|
constructor(transport: Transport);
|
|
86
|
-
|
|
87
|
-
signal?: AbortSignal;
|
|
88
|
-
}): Promise<AccessPolicy>;
|
|
89
|
-
putPolicy(policy: AccessPolicy, options?: {
|
|
90
|
-
signal?: AbortSignal;
|
|
91
|
-
}): Promise<AccessPolicy>;
|
|
92
|
-
/**
|
|
93
|
-
* Ends every token minted so far for `subject` and its open streams. Running turns continue;
|
|
94
|
-
* cancel them separately if they must stop.
|
|
95
|
-
*/
|
|
96
|
-
revokeSubject(subject: string, options?: {
|
|
97
|
-
signal?: AbortSignal;
|
|
98
|
-
}): Promise<{
|
|
99
|
-
subject: string;
|
|
100
|
-
epoch: number;
|
|
101
|
-
}>;
|
|
102
|
-
/** The public keys that verify the Tenant's subject tokens. */
|
|
31
|
+
/** The public keys that verify the Tenant's delivery tokens. */
|
|
103
32
|
jwks(options?: {
|
|
104
33
|
signal?: AbortSignal;
|
|
105
34
|
}): Promise<Jwks>;
|
package/dist/access.js
CHANGED
|
@@ -1,112 +1,35 @@
|
|
|
1
1
|
import { id, segment } from "./http.js";
|
|
2
|
-
const FEATURE = "subject-tokens";
|
|
3
|
-
export class TokensClient {
|
|
4
|
-
transport;
|
|
5
|
-
constructor(transport) {
|
|
6
|
-
this.transport = transport;
|
|
7
|
-
}
|
|
8
|
-
/** Mints a subject token. Only the application key may; never acting for a subject. */
|
|
9
|
-
async create(options) {
|
|
10
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
11
|
-
return this.transport.json("/v1/tokens", "POST", {
|
|
12
|
-
requestId: id(),
|
|
13
|
-
subject: options.subject,
|
|
14
|
-
role: options.role,
|
|
15
|
-
...(options.scopes ? { scopes: [...options.scopes] } : {}),
|
|
16
|
-
...(options.agents ? { agents: [...options.agents] } : {}),
|
|
17
|
-
...(options.sandboxes ? { sandboxes: [...options.sandboxes] } : {}),
|
|
18
|
-
...(options.ttlSeconds === undefined ? {} : { ttlSeconds: options.ttlSeconds }),
|
|
19
|
-
}, options.signal);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
2
|
export class SigningKeysClient {
|
|
23
3
|
transport;
|
|
24
4
|
constructor(transport) {
|
|
25
5
|
this.transport = transport;
|
|
26
6
|
}
|
|
27
7
|
async list(options = {}) {
|
|
28
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
29
8
|
const reply = await this.transport.json("/v1/access/signing-keys", "GET", undefined, options.signal);
|
|
30
9
|
return reply.keys;
|
|
31
10
|
}
|
|
32
11
|
/**
|
|
33
12
|
* standby → current → previous → revoked, and a new standby. Refused while the previous key
|
|
34
|
-
* may still verify live tokens; `force` skips that and
|
|
13
|
+
* may still verify live tokens; `force` skips that and ends those tokens.
|
|
35
14
|
*/
|
|
36
15
|
async rotate(options = {}) {
|
|
37
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
38
16
|
const reply = await this.transport.json("/v1/access/signing-keys/rotate", "POST", { requestId: id(), ...(options.force ? { force: true } : {}) }, options.signal);
|
|
39
17
|
return reply.keys;
|
|
40
18
|
}
|
|
41
19
|
/** Revokes a previous or standby key; the current key must be rotated first. */
|
|
42
20
|
async revoke(keyId, options = {}) {
|
|
43
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
44
21
|
return this.transport.json(`/v1/access/signing-keys/${segment(keyId)}/revoke`, "POST", { requestId: id() }, options.signal);
|
|
45
22
|
}
|
|
46
23
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Publishable keys (Host feature `browser-access`): shipped in a web page or an app, they name
|
|
49
|
-
* the Tenant and the app, and list the origins a browser may use them from.
|
|
50
|
-
*/
|
|
51
|
-
export class PublishableKeysClient {
|
|
52
|
-
transport;
|
|
53
|
-
constructor(transport) {
|
|
54
|
-
this.transport = transport;
|
|
55
|
-
}
|
|
56
|
-
async list(options = {}) {
|
|
57
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
58
|
-
const reply = await this.transport.json("/v1/access/publishable-keys", "GET", undefined, options.signal);
|
|
59
|
-
return reply.keys;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* A new key. `origins` are exact origins (`https://app.example.com`) or
|
|
63
|
-
* `http://localhost:*`; `[]` allows native apps only.
|
|
64
|
-
*/
|
|
65
|
-
async create(options) {
|
|
66
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
67
|
-
return this.transport.json("/v1/access/publishable-keys", "POST", { requestId: id(), name: options.name, origins: [...options.origins] }, options.signal);
|
|
68
|
-
}
|
|
69
|
-
/** Replaces the key's origins. */
|
|
70
|
-
async update(keyId, options) {
|
|
71
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
72
|
-
return this.transport.json(`/v1/access/publishable-keys/${segment(keyId)}`, "PUT", { requestId: id(), origins: [...options.origins] }, options.signal);
|
|
73
|
-
}
|
|
74
|
-
/** Revokes the key: every request that sends it gets the opaque 404. */
|
|
75
|
-
async revoke(keyId, options = {}) {
|
|
76
|
-
await this.transport.requireFeature("browser-access", options.signal);
|
|
77
|
-
return this.transport.json(`/v1/access/publishable-keys/${segment(keyId)}`, "DELETE", undefined, options.signal);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
24
|
export class AccessClient {
|
|
81
25
|
transport;
|
|
82
26
|
signingKeys;
|
|
83
|
-
publishableKeys;
|
|
84
27
|
constructor(transport) {
|
|
85
28
|
this.transport = transport;
|
|
86
29
|
this.signingKeys = new SigningKeysClient(transport);
|
|
87
|
-
this.publishableKeys = new PublishableKeysClient(transport);
|
|
88
|
-
}
|
|
89
|
-
async getPolicy(options = {}) {
|
|
90
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
91
|
-
const reply = await this.transport.json("/v1/access/policy", "GET", undefined, options.signal);
|
|
92
|
-
return reply.policy;
|
|
93
|
-
}
|
|
94
|
-
async putPolicy(policy, options = {}) {
|
|
95
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
96
|
-
const reply = await this.transport.json("/v1/access/policy", "PUT", { requestId: id(), policy }, options.signal);
|
|
97
|
-
return reply.policy;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Ends every token minted so far for `subject` and its open streams. Running turns continue;
|
|
101
|
-
* cancel them separately if they must stop.
|
|
102
|
-
*/
|
|
103
|
-
async revokeSubject(subject, options = {}) {
|
|
104
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
105
|
-
return this.transport.json("/v1/access/revocations", "POST", { requestId: id(), subject }, options.signal);
|
|
106
30
|
}
|
|
107
|
-
/** The public keys that verify the Tenant's
|
|
31
|
+
/** The public keys that verify the Tenant's delivery tokens. */
|
|
108
32
|
async jwks(options = {}) {
|
|
109
|
-
await this.transport.requireFeature(FEATURE, options.signal);
|
|
110
33
|
return this.transport.json("/v1/access/jwks", "GET", undefined, options.signal);
|
|
111
34
|
}
|
|
112
35
|
}
|
package/dist/ag-ui/handler.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* person, so the Runtime keeps one person out of another's threads and does all the protocol
|
|
6
6
|
* work. The browser never sees the Tenant key, the Runtime's URL or the Tenant id.
|
|
7
7
|
*
|
|
8
|
-
* The same threads are reachable directly from a browser with a
|
|
9
|
-
* one session per subject, agent and thread on both paths.
|
|
8
|
+
* The same threads are reachable directly from a browser with a trusted issuer's token (through
|
|
9
|
+
* the operator's proxy): each thread is one session per subject, agent and thread on both paths.
|
|
10
10
|
*/
|
|
11
11
|
import { type SubjectScope } from "@nylorun/core/contracts";
|
|
12
12
|
import type { BuiltWorkflow } from "@nylorun/core/define";
|
|
@@ -27,10 +27,7 @@ export interface AgUiHandlerOptions {
|
|
|
27
27
|
basePath?: string;
|
|
28
28
|
/** Application client. Default: `createClient()`, from the environment or the Project link. */
|
|
29
29
|
client?: AgentsClient | Promise<AgentsClient>;
|
|
30
|
-
/**
|
|
31
|
-
* What each subject may do through this endpoint. Default `["sessions:own"]`; add
|
|
32
|
-
* `vaults:own` if `session()` attaches the person's vaults.
|
|
33
|
-
*/
|
|
30
|
+
/** What each subject may do through this endpoint. Default `["sessions:own"]`. */
|
|
34
31
|
scopes?: readonly SubjectScope[];
|
|
35
32
|
/** Optional per-session parameters, e.g. the person's vault for connected accounts. */
|
|
36
33
|
session?(subject: string, agentId: string): AgUiSessionOptions | Promise<AgUiSessionOptions>;
|
package/dist/ag-ui/handler.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* person, so the Runtime keeps one person out of another's threads and does all the protocol
|
|
6
6
|
* work. The browser never sees the Tenant key, the Runtime's URL or the Tenant id.
|
|
7
7
|
*
|
|
8
|
-
* The same threads are reachable directly from a browser with a
|
|
9
|
-
* one session per subject, agent and thread on both paths.
|
|
8
|
+
* The same threads are reachable directly from a browser with a trusted issuer's token (through
|
|
9
|
+
* the operator's proxy): each thread is one session per subject, agent and thread on both paths.
|
|
10
10
|
*/
|
|
11
11
|
import { parseSubjectHeaders } from "@nylorun/core/contracts";
|
|
12
12
|
import { createClient, } from "../client.js";
|
package/dist/artifacts.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* session's sandbox as a version of its `outputs` folder. Read one as a tree, one file by path,
|
|
10
10
|
* a diff between versions or a zip.
|
|
11
11
|
*
|
|
12
|
-
* Acting for a person (`client.as`, a
|
|
12
|
+
* Acting for a person (`client.as`, or a trusted issuer's token), only the artifacts of their own sessions.
|
|
13
13
|
*/
|
|
14
14
|
import type { ArtifactDiff, ArtifactLink, ArtifactTree, ArtifactView, DeleteArtifactResponse, UploadArtifactResponse } from "@nylorun/core/contracts";
|
|
15
15
|
import { type Transport } from "./http.js";
|
package/dist/delivery-token.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* WebCrypto's ECDSA verifies.
|
|
6
6
|
*/
|
|
7
7
|
import { PROTOCOL_HEADER, PROTOCOL_VERSION, isTenantId } from "@nylorun/core/compatibility";
|
|
8
|
-
import { DELIVERY_TOKEN_TYPE,
|
|
8
|
+
import { DELIVERY_TOKEN_TYPE, tenantTokenIssuer } from "@nylorun/core/contracts";
|
|
9
9
|
/** The issuer prefix of a Tenant's tokens: `urn:nylorun:tenant:<tenantId>`. */
|
|
10
|
-
const ISSUER_PREFIX =
|
|
10
|
+
const ISSUER_PREFIX = tenantTokenIssuer("");
|
|
11
11
|
/** Why a delivery was refused; `code` is sent back to the Runtime. */
|
|
12
12
|
export class DeliveryVerificationError extends Error {
|
|
13
13
|
code;
|
|
@@ -60,7 +60,7 @@ export async function verifyDeliveryToken(token, options) {
|
|
|
60
60
|
if (!claims.iss.startsWith(ISSUER_PREFIX) ||
|
|
61
61
|
!isTenantId(claims.iss.slice(ISSUER_PREFIX.length)))
|
|
62
62
|
throw invalid("The token was not issued by a Tenant");
|
|
63
|
-
if (options.tenantId !== undefined && claims.iss !==
|
|
63
|
+
if (options.tenantId !== undefined && claims.iss !== tenantTokenIssuer(options.tenantId))
|
|
64
64
|
throw invalid("The token is for another Tenant");
|
|
65
65
|
if (options.audience !== undefined && claims.aud !== options.audience)
|
|
66
66
|
throw invalid(`The token is for ${claims.aud}, not ${options.audience}`);
|
package/dist/http.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type Compatibility, type ProtocolRange } from "@nylorun/core/compatibility";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
* drops the cached one after the Runtime answered
|
|
3
|
+
* Bearer tokens for a client that holds no Tenant key: a trusted issuer's tokens (Host feature
|
|
4
|
+
* `trusted-issuers`), from the operator's identity provider. `get` returns a current token and
|
|
5
|
+
* may fetch a new one; `invalidate` drops the cached one after the Runtime answered
|
|
6
|
+
* `401 token_expired`.
|
|
6
7
|
*/
|
|
7
8
|
export interface TokenSource {
|
|
8
9
|
get(signal?: AbortSignal): Promise<string>;
|
|
@@ -16,10 +17,8 @@ export interface Destination {
|
|
|
16
17
|
url?: string;
|
|
17
18
|
key?: string;
|
|
18
19
|
fetch?: typeof fetch;
|
|
19
|
-
/** Instead of `key`:
|
|
20
|
+
/** Instead of `key`: a trusted issuer's tokens. The client then skips the `/health` check. */
|
|
20
21
|
token?: TokenSource;
|
|
21
|
-
/** A publishable key (Host feature `browser-access`): names the app and its origins. */
|
|
22
|
-
publishableKey?: string;
|
|
23
22
|
}
|
|
24
23
|
export declare function env(name: string): string | undefined;
|
|
25
24
|
export declare class RuntimeError extends Error {
|
|
@@ -39,10 +38,9 @@ export declare class IncompatibleRuntimeError extends Error {
|
|
|
39
38
|
}
|
|
40
39
|
export declare class Transport {
|
|
41
40
|
readonly url: string;
|
|
42
|
-
/** The Tenant key; empty for a client that uses
|
|
41
|
+
/** The Tenant key; empty for a client that uses issuer tokens. */
|
|
43
42
|
readonly key: string;
|
|
44
43
|
readonly token: TokenSource | undefined;
|
|
45
|
-
readonly publishableKey: string | undefined;
|
|
46
44
|
readonly fetcher: typeof fetch;
|
|
47
45
|
/** Sent on every request, e.g. `Nylorun-Subject` and `Nylorun-Scopes` (`withHeaders`). */
|
|
48
46
|
readonly headers: Readonly<Record<string, string>>;
|