@nylorun/runtime 0.14.0-beta → 0.15.1-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 +115 -0
- package/README.md +82 -40
- package/dist/adapters/execution/restate.js +2 -2
- package/dist/adapters/replication/pgoutput.d.ts +5 -0
- package/dist/adapters/replication/pgoutput.js +4 -3
- package/dist/admin-openapi.json +185 -686
- package/dist/api/components.d.ts +308 -68
- package/dist/api/components.js +4 -5
- package/dist/api/gate/keys.d.ts +14 -0
- package/dist/api/gate/keys.js +59 -0
- package/dist/api/gate/routes.d.ts +34 -0
- package/dist/api/gate/routes.js +235 -0
- package/dist/api/http/define.js +0 -8
- package/dist/api/http/routes/access.js +25 -18
- package/dist/api/http/routes/tenant.d.ts +2 -1
- package/dist/api/http/routes/tenant.js +77 -5
- package/dist/api/http/routes/vaults.js +2 -2
- package/dist/api/openapi.js +6 -7
- package/dist/gates/contract.d.ts +51 -0
- package/dist/gates/contract.js +37 -0
- package/dist/gates/handler.d.ts +21 -0
- package/dist/gates/handler.js +55 -0
- package/dist/gates/http-client.d.ts +12 -0
- package/dist/gates/http-client.js +160 -0
- package/dist/gates/in-process.d.ts +32 -0
- package/dist/gates/in-process.js +42 -0
- package/dist/gates/inflight.d.ts +39 -0
- package/dist/gates/inflight.js +70 -0
- package/dist/gates/mcp-handler.d.ts +35 -0
- package/dist/gates/mcp-handler.js +142 -0
- package/dist/gates/meter.d.ts +24 -0
- package/dist/gates/meter.js +165 -0
- package/dist/gates/model-gate.d.ts +45 -0
- package/dist/gates/model-gate.js +1 -0
- package/dist/gates/tenant-vaults.d.ts +64 -0
- package/dist/gates/tenant-vaults.js +94 -0
- package/dist/gates/tool-calls.d.ts +51 -0
- package/dist/gates/tool-calls.js +64 -0
- package/dist/gates/tool-client.d.ts +12 -0
- package/dist/gates/tool-client.js +201 -0
- package/dist/gates/tool-contract.d.ts +116 -0
- package/dist/gates/tool-contract.js +64 -0
- package/dist/gates/tool-gate.d.ts +45 -0
- package/dist/gates/tool-gate.js +10 -0
- package/dist/host/admin-api.d.ts +7 -6
- package/dist/host/admin-api.js +9 -113
- package/dist/host/app.d.ts +1 -1
- package/dist/host/app.js +20 -24
- package/dist/host/config-for.d.ts +1 -1
- package/dist/host/config-for.js +2 -2
- package/dist/host/create-host.d.ts +5 -5
- package/dist/host/create-host.js +5 -15
- package/dist/host/execution.d.ts +20 -18
- package/dist/host/execution.js +2 -2
- package/dist/host/gates.d.ts +58 -0
- package/dist/host/gates.js +127 -0
- package/dist/host/http.d.ts +6 -1
- package/dist/host/http.js +17 -0
- package/dist/host/index.d.ts +1 -1
- package/dist/host/main.js +151 -71
- package/dist/host/stack-config.d.ts +71 -19
- package/dist/host/stack-config.js +192 -18
- package/dist/infra/database.d.ts +2 -2
- package/dist/infra/execution.d.ts +5 -5
- package/dist/infra/execution.js +8 -6
- package/dist/infra/index.d.ts +1 -1
- package/dist/infra/workers.d.ts +17 -17
- package/dist/infra/workers.js +9 -9
- package/dist/keys/client.d.ts +9 -0
- package/dist/keys/client.js +70 -0
- package/dist/keys/contract.d.ts +24 -0
- package/dist/keys/contract.js +12 -0
- package/dist/keys/keys.d.ts +41 -0
- package/dist/keys/keys.js +50 -0
- package/dist/mcp/connect.d.ts +43 -3
- package/dist/mcp/connect.js +12 -5
- package/dist/mcp/pool.d.ts +21 -3
- package/dist/mcp/pool.js +15 -2
- package/dist/openapi.json +888 -695
- package/dist/record/append.d.ts +51 -0
- package/dist/record/append.js +20 -0
- package/dist/{store/event.js → record/envelope.js} +1 -1
- package/dist/record/index.d.ts +11 -0
- package/dist/record/index.js +11 -0
- package/dist/store/postgres/connect.d.ts +15 -12
- package/dist/store/postgres/connect.js +24 -12
- package/dist/store/postgres/db.d.ts +16 -0
- package/dist/store/postgres/db.js +28 -0
- package/dist/store/postgres/drizzle/0000_foundation.sql +22 -0
- package/dist/store/postgres/drizzle/0001_baseline.sql +255 -0
- package/dist/store/postgres/drizzle/0002_stream_relay.sql +4 -0
- package/dist/store/postgres/drizzle/0003_tool_crossings.sql +9 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +34 -0
- package/dist/store/postgres/migrate.d.ts +68 -0
- package/dist/store/postgres/migrate.js +183 -0
- package/dist/store/postgres/record-writer.d.ts +4 -0
- package/dist/store/postgres/record-writer.js +34 -0
- package/dist/store/postgres/record.d.ts +2 -8
- package/dist/store/postgres/record.js +50 -54
- package/dist/store/postgres/schema.d.ts +3096 -0
- package/dist/store/postgres/schema.js +363 -0
- package/dist/store/postgres/store.d.ts +2 -4
- package/dist/store/postgres/store.js +481 -567
- package/dist/store/postgres/tenant.d.ts +56 -0
- package/dist/store/postgres/tenant.js +154 -0
- package/dist/store/types.d.ts +43 -87
- package/dist/store/types.js +0 -1
- package/dist/streams/control.d.ts +1 -1
- package/dist/streams/control.js +6 -2
- package/dist/streams/relay/types.d.ts +2 -1
- package/dist/streams/relay/types.js +2 -1
- package/dist/streams/types.d.ts +5 -0
- package/dist/tenant/advance.d.ts +7 -2
- package/dist/tenant/advance.js +95 -16
- package/dist/tenant/cause.d.ts +25 -0
- package/dist/tenant/cause.js +45 -0
- package/dist/tenant/commands.js +4 -2
- package/dist/tenant/context.d.ts +26 -3
- package/dist/tenant/delivery-token.js +17 -18
- package/dist/tenant/delivery.d.ts +1 -1
- package/dist/tenant/delivery.js +18 -13
- package/dist/tenant/effects.d.ts +15 -1
- package/dist/tenant/effects.js +93 -17
- package/dist/tenant/ephemeral.d.ts +16 -7
- package/dist/tenant/ephemeral.js +45 -111
- package/dist/tenant/history.d.ts +64 -0
- package/dist/tenant/history.js +120 -0
- package/dist/tenant/model-setting.d.ts +2 -2
- package/dist/tenant/module.d.ts +14 -28
- package/dist/tenant/module.js +131 -271
- package/dist/tenant/paths.d.ts +11 -16
- package/dist/tenant/paths.js +24 -68
- package/dist/tenant/pool.d.ts +1 -1
- package/dist/tenant/pool.js +1 -1
- package/dist/tenant/principals.d.ts +23 -11
- package/dist/tenant/principals.js +61 -49
- package/dist/tenant/runtime.d.ts +19 -1
- package/dist/tenant/runtime.js +40 -26
- package/dist/tenant/scheduler.d.ts +4 -2
- package/dist/tenant/scheduler.js +4 -4
- package/dist/tenant/session-streams.d.ts +2 -0
- package/dist/tenant/session-streams.js +8 -3
- package/dist/tenant/status.d.ts +3 -0
- package/dist/tenant/status.js +1 -1
- package/dist/tenant/store-pg.d.ts +9 -6
- package/dist/tenant/store-pg.js +60 -125
- package/dist/tenant/streams.d.ts +9 -25
- package/dist/tenant/streams.js +7 -22
- package/dist/tenant/tokens.js +16 -14
- package/dist/tenant/types.d.ts +41 -92
- package/dist/tenant/types.js +4 -15
- package/dist/tenant/worker.js +4 -4
- package/dist/vault/host-model.d.ts +31 -0
- package/dist/vault/host-model.js +57 -0
- package/dist/vault/service.d.ts +26 -15
- package/dist/vault/service.js +70 -109
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +9 -5
- package/dist/store/memory.d.ts +0 -69
- package/dist/store/memory.js +0 -810
- package/dist/store/postgres/migrations/001_initial.d.ts +0 -27
- package/dist/store/postgres/migrations/001_initial.js +0 -196
- package/dist/store/postgres/migrations/002_session_owner.d.ts +0 -6
- package/dist/store/postgres/migrations/002_session_owner.js +0 -13
- package/dist/store/postgres/migrations/003_subject_tokens.d.ts +0 -8
- package/dist/store/postgres/migrations/003_subject_tokens.js +0 -42
- package/dist/store/postgres/migrations/004_publishable_keys.d.ts +0 -6
- package/dist/store/postgres/migrations/004_publishable_keys.js +0 -18
- package/dist/store/postgres/migrations/005_action_endpoints.d.ts +0 -6
- package/dist/store/postgres/migrations/005_action_endpoints.js +0 -32
- package/dist/store/postgres/migrations/006_drop_executors.d.ts +0 -11
- package/dist/store/postgres/migrations/006_drop_executors.js +0 -32
- package/dist/store/postgres/migrations/007_event_time.d.ts +0 -7
- package/dist/store/postgres/migrations/007_event_time.js +0 -14
- package/dist/store/postgres/migrations/008_durable_streams.d.ts +0 -13
- package/dist/store/postgres/migrations/008_durable_streams.js +0 -35
- package/dist/store/postgres/migrations/index.d.ts +0 -53
- package/dist/store/postgres/migrations/index.js +0 -96
- package/dist/store/postgres/migrations/shared/index.d.ts +0 -31
- package/dist/store/postgres/migrations/shared/index.js +0 -92
- package/dist/store/postgres/names.d.ts +0 -11
- package/dist/store/postgres/names.js +0 -42
- package/dist/store/postgres/tenants.d.ts +0 -90
- package/dist/store/postgres/tenants.js +0 -228
- package/dist/streams/relay/memory.d.ts +0 -69
- package/dist/streams/relay/memory.js +0 -176
- package/dist/tenant/envelope.d.ts +0 -7
- package/dist/tenant/envelope.js +0 -22
- package/dist/tenant/quarantine-error.d.ts +0 -6
- package/dist/tenant/quarantine-error.js +0 -9
- package/dist/tenant/quarantine.d.ts +0 -27
- package/dist/tenant/quarantine.js +0 -72
- package/dist/tenant/store-memory.d.ts +0 -16
- package/dist/tenant/store-memory.js +0 -111
- /package/dist/{store → record}/cursor.d.ts +0 -0
- /package/dist/{store → record}/cursor.js +0 -0
- /package/dist/{store/event.d.ts → record/envelope.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,120 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.1-beta
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Pin core to the tested release.
|
|
8
|
+
- Pin harness to the tested release.
|
|
9
|
+
- Updated dependencies [4b9906f]
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @nylorun/core@0.11.0-beta
|
|
12
|
+
- @nylorun/harness@0.21.2-beta
|
|
13
|
+
|
|
14
|
+
## 0.15.0-beta
|
|
15
|
+
|
|
16
|
+
### Major Changes
|
|
17
|
+
|
|
18
|
+
- 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.
|
|
19
|
+
|
|
20
|
+
- **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.
|
|
21
|
+
- **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.
|
|
22
|
+
- **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).
|
|
23
|
+
- **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.
|
|
24
|
+
- **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.
|
|
25
|
+
- **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).
|
|
26
|
+
- **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`.
|
|
27
|
+
|
|
28
|
+
### Minor Changes
|
|
29
|
+
|
|
30
|
+
- ee9e471: **The vault key leaves the runtime container (F4.2).** A new `keys` service, run in the gateway's process (`--service gates,keys`), is the only process that reads the vault key. Vault writes that touch a secret (creating and rotating a credential, setting and selecting the host model) and all token signing (subject tokens, delivery tokens, signing-key rotation) run there. A Runtime with `NYLORUN_KEYS_URL`, which defaults to `NYLORUN_GATES_URL`, never reads, creates or holds the key. The Tenant API answers as before, with the same statuses, codes and details.
|
|
31
|
+
|
|
32
|
+
- The vault key file moves to `<Host root>/keys/vault-kek`. A gateway that runs keys is not ready until the file is there, and it never creates one.
|
|
33
|
+
- The anonymous `GET /v1/access/jwks` reads the public keys, and asks the keys service only when the current or standby key is missing.
|
|
34
|
+
- While the keys service is down, vault writes and token minting answer `503 keys_unavailable`.
|
|
35
|
+
|
|
36
|
+
- fed780d: **Hard caps on model spend.** A Tenant can cap what its model calls use, per turn, per agent per UTC day or month, or for the whole Tenant per day or month, in USD, tokens or both. Before each call the model gate checks the scope's recorded spend, plus its calls in flight, against the cap. Once a cap is reached the call fails with the new `budget_exhausted` code, which is never retried, and the turn fails with `model.budget_exhausted`. A runaway loop stops there, at most one call over its cap.
|
|
37
|
+
|
|
38
|
+
- `PUT /v1/tenant/budgets` replaces the budgets and `GET /v1/tenant/budgets` reads them. Both need the application key or `tenant:settings`.
|
|
39
|
+
- `@nylorun/core` adds `budget_exhausted` to `ModelFailureCode` and `MODEL_FAILURE_CODES`, plus `ModelBudgetSchema`, `PutModelBudgetsRequestSchema` and `ModelBudgetsSchema`. Code that switches over failure codes exhaustively needs the new case.
|
|
40
|
+
- Custom endpoints are priced at $0, so only a token limit stops them.
|
|
41
|
+
- Budgets survive a `sessions` reset. A reset of scope `all` clears them.
|
|
42
|
+
|
|
43
|
+
- 744208d: **A runtime that dies or restarts mid-call no longer strands the session (P1.2).** The loop sends each model call with its effect id as the `Idempotency-Key`, and the gate runs a keyed call under its own control: if the caller disconnects, the call finishes and its outcome is kept for 30 minutes. The runtime that takes the session over re-sends the journaled call and joins it, or collects its outcome, so the turn completes with one provider call instead of becoming `uncertain`. A shutdown no longer marks the call `uncertain` either.
|
|
44
|
+
|
|
45
|
+
- A re-send with the same key and a different request answers `409 gate_conflict`.
|
|
46
|
+
- A user cancel sends `POST /nylorun/v1/model-calls/{key}/cancel`, which stops the provider request, and marks the turn's model call `uncertain`.
|
|
47
|
+
- Outcomes live in the gateway's memory: a gateway restart forgets them. A Runtime that calls models in its own process (embedding, tests) keeps the previous behaviour.
|
|
48
|
+
|
|
49
|
+
- 744208d: **Model calls leave the loop through the Model Gate (P1.1).** Every vault-backed model call of the loop goes through one `ModelGate` (`runtime/src/gates/`). `--service gates` serves it over HTTP: one listener (`NYLORUN_GATES_LISTEN_HOST`, `NYLORUN_GATES_LISTEN_PORT`, default port 4100, `NYLORUN_GATES_ALLOWED_HOSTS`) answering `POST /nylorun/v1/model-calls` to callers presenting `NYLORUN_GATES_TOKEN`, with one JSON body once the call has finished. The gate reads the Tenant's host model from its vault and calls the provider with the same adapter, retries, idle watchdog, failure classification and redaction as before.
|
|
50
|
+
|
|
51
|
+
- **Breaking:** in a container, a Runtime that runs `loop` refuses to start without `NYLORUN_GATES_URL` and `NYLORUN_GATES_TOKEN`; it then never reads a model credential. Outside a container (embedding, `startEphemeralRuntime`), a loop without `NYLORUN_GATES_URL` runs the gate in its own process, as before. See `DEPLOYMENT.md`.
|
|
52
|
+
- **Breaking:** the `gateway` model kind is removed from `TenantConfig.model` and `StartEphemeralRuntimeOptions.model`. Nothing set it, and it read the Tenant's model credential inside the loop. The exported `gatewayModel` provider is unchanged.
|
|
53
|
+
- The gate needs only `NYLORUN_DATABASE_URL` and the Host's Tenant directory (`tenant/`), which it never writes: it runs no migration and opens no Tenant runtime. It refuses a Tenant whose schema is at another version, so the gateway and the runtime must run the same build. gates never shares a process with core or loop: `--service core,gates` is refused.
|
|
54
|
+
- The client speaks `node:http` with a 630 s idle timeout, so calls longer than five minutes are not cut off. It never retries; the gate does. A failure of the hop is a failure outcome: an unreachable gate, a connection lost mid-call, a timeout or a 5xx is `transient` and retryable; a refused token is `auth`, naming `NYLORUN_GATES_TOKEN`.
|
|
55
|
+
- The `host_stack_config` startup log names the gate (`modelGate`).
|
|
56
|
+
|
|
57
|
+
- fed780d: **Every model call is recorded in the Tenant's usage ledger.** The model gate writes one row per call that answers: the session, turn and agent, the provider and model, the tokens (input, output, cached, cache write, reasoning) and pi-ai's price in USD. Custom endpoints count as $0. A call the gateway ran twice after a restart is recorded twice and flagged as a duplicate, since the provider billed both.
|
|
58
|
+
|
|
59
|
+
- `GET /v1/tenant/usage?scope=tenant|agent|turn&id=&period=day|month|total` totals the ledger. It needs the application key or `tenant:settings`, like the other Tenant settings.
|
|
60
|
+
- `@nylorun/core/contracts` adds `ModelUsageScopeSchema`, `ModelUsageQuerySchema` and `ModelUsageTotalsSchema`.
|
|
61
|
+
- The ledger survives a `sessions` reset. A reset of scope `all` clears it.
|
|
62
|
+
- The gateway and the runtime must run the same build, as before.
|
|
63
|
+
|
|
64
|
+
- 7f4c3f1: **One history: a session's transcript is folded from its record.** The own loop's model-facing transcript is no longer stored on the session row, where up to three copies of it lived (`state`, `turnStartState` and the checkpoint). After each segment that keeps its state, the Runtime records the change as an internal `transcript.updated` event: the new entries, or a snapshot after compaction. Each segment folds the transcript back from the record, and a cancelled or failed turn's entries are undone, as before.
|
|
65
|
+
|
|
66
|
+
- **Internal events.** `transcript.updated` is in the event catalog with `visibility: "internal"`. SSE, history, AG-UI and A2A never serve it. Served events can therefore skip the seq numbers internal events hold; cursors resume as before. `TranscriptUpdatedPayloadSchema` is exported from `@nylorun/core/contracts`, and catalog entries may declare `visibility`.
|
|
67
|
+
- **No checkpoints table.** Every settle used to write a copy of the session's checkpoint to a `checkpoints` table that nothing read; it is gone. The checkpoint a session resumes from stays on the session row.
|
|
68
|
+
- **Storage.** A long session's row no longer grows with its transcript (a 10-turn, 300-step session on a 16k window: under 16 KB instead of up to 196 KB).
|
|
69
|
+
|
|
70
|
+
- 7bd38d6: **`--service` names what a Runtime process runs.** The image now starts as `--service core,loop` (the default without a flag): `core` serves the Tenant and Admin APIs and runs the stream relay, and `loop` runs the agent loop and serves the Worker endpoint Restate calls. A container may run several services, which is how the local stack packs them.
|
|
71
|
+
|
|
72
|
+
- `--role api|worker|all` still works for one release as a deprecated alias of `--service core`, `loop` and `core,loop`, and logs `deprecated_flag` at startup.
|
|
73
|
+
- `--service all` is refused: name the services, e.g. `--service core,loop`.
|
|
74
|
+
- The `host_stack_config` startup log names `services` instead of `role`.
|
|
75
|
+
|
|
76
|
+
- 5ca1923: **Drizzle defines the Session Store's schema, migrations and queries.** An internal storage change: the tables, columns and indexes of a Tenant database are the same as before.
|
|
77
|
+
|
|
78
|
+
- The tables are defined in `src/store/postgres/schema.ts`; drizzle-kit generates the migrations from it, and they ship in the package (`dist/store/postgres/drizzle/`). At startup the Host applies the missing ones in one transaction under an advisory lock and records them in `nylorun.__drizzle_migrations` (Drizzle's journal format). A database whose journal holds a migration this Runtime does not ship still fails readiness with `schema-too-new`. The schema version reported by `/ready` and Admin status is the number of applied migrations.
|
|
79
|
+
- Statements are prepared again (one Tenant per database makes every statement the same for the whole pool).
|
|
80
|
+
- `drizzle-orm` is a new dependency.
|
|
81
|
+
|
|
82
|
+
- 7bd38d6: **The local stack runs a gateway container: model calls leave the Runtime.** `nylorun up` now runs the Runtime image twice, the combined packing: `runtime` (`--service core,loop`: the APIs and the agent loop) and `gateway` (`--service gates,keys`: the Model Gate, the Tool Gate and the keys service). Every model call, remote MCP call and Action delivery of the loop crosses the gateway, which alone reads the Tenant's credentials and the vault key. A new stack starts with the gateway.
|
|
83
|
+
|
|
84
|
+
- **Breaking for hand-written Compose files:** in a container, a Runtime that runs `loop` refuses to start without `NYLORUN_GATES_URL` and `NYLORUN_GATES_TOKEN`. Run the image a second time with `--service gates,keys` (see `DEPLOYMENT.md`). The image's default command is now `--service core,loop`.
|
|
85
|
+
- The gateway has no published port, mounts only the Host's Tenant directory (`tenant/`) and `keys/`, both read-only, and reaches model servers on this machine at `host.docker.internal`. `docker/.env` holds `NYLORUN_GATES_TOKEN`, generated once and kept across starts.
|
|
86
|
+
- `nylorun status` shows a Gateway line, `nylorun doctor` fails when the gateway is unhealthy and names `nylorun logs gateway`, and `nylorun logs gateway` is accepted.
|
|
87
|
+
- An image set with `NYLORUN_RUNTIME_IMAGE` must be this release or newer: older Runtimes don't know `--service`.
|
|
88
|
+
|
|
89
|
+
- 31cfec0: **Action deliveries leave through the gateway (F4.1).** With the gates service, every delivery and endpoint ping is POSTed by the gateway (`POST /nylorun/v1/deliveries`) under the gateway's own `NYLORUN_ENDPOINT_*` policy. The delivery state machine is unchanged. A gateway that cannot be reached counts as a delivery that was not sent, so it is retried, and its failure code is `gateway.unreachable`.
|
|
90
|
+
|
|
91
|
+
- `nylorun`: the `gateway` container now sets `NYLORUN_ENDPOINT_LOOPBACK=docker-host`, so Action endpoints on this machine stay reachable.
|
|
92
|
+
- A process that runs only `core` also reads `NYLORUN_GATES_URL`, for endpoint pings.
|
|
93
|
+
|
|
94
|
+
- 31cfec0: **Remote MCP servers run behind the Tool Gate (F4.1).** With the gates service (the local stack's `gateway` container), the gateway holds each session's connection to a `streamable-http` or `sse` MCP server, authorizes it from the session's attached vaults (OAuth refresh included), and runs `tools/list` and `tools/call`. The runtime names the server and never sees its credential. Stdio MCP servers still run beside the loop.
|
|
95
|
+
|
|
96
|
+
- New internal routes on the gates service: `POST /nylorun/v1/mcp/connect`, `/mcp/list`, `/mcp/close` and `/tool-calls`.
|
|
97
|
+
- The loop now passes its abort signal to every MCP call, in and out of process.
|
|
98
|
+
|
|
99
|
+
- 31cfec0: **Remote MCP calls outlive the runtime that sent them, and never run twice (F4.1).** The loop sends each remote MCP call with its effect id as the `Idempotency-Key`. The gateway keeps a keyed call running after its caller goes away, and a restarted or new owner re-sends the journaled call and joins it, so the turn completes with one call to the server and nothing `uncertain`.
|
|
100
|
+
|
|
101
|
+
- The gateway records each keyed call before it reaches the server and stores the answer after. After a gateway restart, a call that was in flight answers `uncertain` and is never run again. Rows are deleted a day after they settle.
|
|
102
|
+
- A user cancel stops the call at the gateway (`POST /nylorun/v1/tool-calls/{key}/cancel`).
|
|
103
|
+
|
|
104
|
+
### Patch Changes
|
|
105
|
+
|
|
106
|
+
- 1a38e0e: **A late cancel signal no longer stops the next turn.** The `session.cancel` signal on `tenant/control` now names the turn it cancelled, and a Worker aborts only an advance of that turn. Before, a signal delivered after S2 came back (an append the SDK retried, or a control reader catching up) aborted whatever advance the session was running, which could be a turn started after the cancel.
|
|
107
|
+
- Pin core to the tested release.
|
|
108
|
+
- Pin harness to the tested release.
|
|
109
|
+
- Updated dependencies [fed780d]
|
|
110
|
+
- Updated dependencies [fed780d]
|
|
111
|
+
- Updated dependencies [7f4c3f1]
|
|
112
|
+
- Updated dependencies [5ca1923]
|
|
113
|
+
- Updated dependencies [5ca1923]
|
|
114
|
+
- Updated dependencies
|
|
115
|
+
- @nylorun/core@0.10.0-beta
|
|
116
|
+
- @nylorun/harness@0.21.1-beta
|
|
117
|
+
|
|
3
118
|
## 0.14.0-beta
|
|
4
119
|
|
|
5
120
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The independent OSS **Runtime Host** consumes `@nylorun/harness/run` and
|
|
4
4
|
`@nylorun/core/contracts`. Cloud installs published `@nylorun/harness` from npm
|
|
5
5
|
and does not import this package. Client authoring and sessions belong to
|
|
6
|
-
`@nylorun/agents`;
|
|
6
|
+
`@nylorun/agents`; the Host's status and derived keys belong to `@nylorun/admin`.
|
|
7
7
|
Vocabulary: [src/CONTEXT.md](./src/CONTEXT.md).
|
|
8
8
|
|
|
9
9
|
Requires Node 24+. Build from the repository root:
|
|
@@ -18,21 +18,39 @@ npm run build --workspace @nylorun/runtime
|
|
|
18
18
|
## Running the Runtime
|
|
19
19
|
|
|
20
20
|
The Runtime runs as the `ghcr.io/nylorun/runtime` image, next to Postgres,
|
|
21
|
-
Restate and S2: `nylorun start` runs
|
|
21
|
+
Restate and S2: `nylorun start` runs them, as a local Tenant, on a developer machine. The
|
|
22
22
|
package is a library with no bin; its Host entry is `@nylorun/runtime/server`
|
|
23
23
|
(`dist/host/main.js`), which requires `NYLORUN_DATABASE_URL`. For tests and
|
|
24
24
|
ephemeral embeds, use `startEphemeralRuntime()` from `@nylorun/runtime/core`.
|
|
25
25
|
See [MIGRATION.md](../MIGRATION.md).
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
Postgres
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
A Runtime serves one **Tenant**: an installation is one Runtime with its own
|
|
28
|
+
Postgres database, Restate and S2 basin, and two Tenants are two installations. No
|
|
29
|
+
Tenant state lives only in the Runtime process. The Tenant's data is its Postgres
|
|
30
|
+
database, in the fixed schemas `nylorun` (its state: the Session Store) and
|
|
31
|
+
`nylorun_streams` (the record of its session events). Drizzle defines the tables
|
|
32
|
+
(`src/store/postgres/schema.ts`) and generates the migrations, which ship in the package
|
|
33
|
+
(`dist/store/postgres/drizzle/`). At startup the Host applies the missing ones in one
|
|
34
|
+
transaction under an advisory lock, records them in `nylorun.__drizzle_migrations`, and
|
|
35
|
+
refuses a database holding a migration it does not ship (`schema-too-new`); then, on
|
|
36
|
+
first start, it creates the Tenant there: its id (`NYLORUN_TENANT_ID`, default a
|
|
37
|
+
new one), its name (`NYLORUN_TENANT_NAME`, default `default`), its Studio principal and
|
|
38
|
+
the derived principals (`NYLORUN_DERIVED_PRINCIPALS`, default `project`) whose keys the
|
|
39
|
+
admin key derives. A database written by a Runtime that kept several Tenants in one
|
|
40
|
+
database (`tenant_<id>` schemas), or by a pre-release build of one Tenant per database
|
|
41
|
+
(`schema_version` tables), is refused: this release starts fresh on a new database. Restate runs one advance of a session at a time and holds the Tenant's sweep
|
|
42
|
+
timer (Durable Session Execution); every session's events are relayed from the record to
|
|
43
|
+
its own S2 stream, which history and SSE read (Durable Streams). One image runs every **service**,
|
|
44
|
+
and `--service` picks what a process runs: `core` serves the Tenant API, Admin
|
|
45
|
+
API and SSE and runs the stream relay, `loop` runs advances (the Worker), and
|
|
46
|
+
`gates` is the Model Gate, the only process that reads a model credential and
|
|
47
|
+
calls providers. `core` and `loop` may share a process; `gates` never joins
|
|
48
|
+
them. A local Tenant packs `core,loop` into the `runtime` container and
|
|
49
|
+
`gates` into the `gateway` container (the combined packing). `--role
|
|
50
|
+
api|worker|all` is the deprecated name of `--service core`, `loop` and
|
|
51
|
+
`core,loop`.
|
|
52
|
+
|
|
53
|
+
The container is configured by its environment, which a local Tenant's Compose file
|
|
36
54
|
sets: `NYLORUN_DATABASE_URL` (required), `NYLORUN_RESTATE_INGRESS_URL`,
|
|
37
55
|
`NYLORUN_RESTATE_ADMIN_URL`, `NYLORUN_WORKER_URL` and
|
|
38
56
|
`NYLORUN_RESTATE_IDENTITY_KEY` (Restate), `NYLORUN_S2_ENDPOINT` and
|
|
@@ -40,17 +58,23 @@ sets: `NYLORUN_DATABASE_URL` (required), `NYLORUN_RESTATE_INGRESS_URL`,
|
|
|
40
58
|
`NYLORUN_LISTEN_PORT`, `NYLORUN_ALLOWED_HOSTS` and `NYLORUN_PUBLIC_URL`, plus
|
|
41
59
|
`NYLORUN_BROWSER_ACCESS` (`on` or `off`) and the operator listener
|
|
42
60
|
(`NYLORUN_ADMIN_LISTEN_PORT`, `NYLORUN_ADMIN_LISTEN_HOST`,
|
|
43
|
-
`NYLORUN_ADMIN_ALLOWED_HOSTS`).
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
`NYLORUN_ADMIN_ALLOWED_HOSTS`). A process that runs `loop` sends its model
|
|
62
|
+
calls to the gate at `NYLORUN_GATES_URL` with `NYLORUN_GATES_TOKEN`; in a
|
|
63
|
+
container it refuses to start without them. A `gates` process needs only
|
|
64
|
+
`NYLORUN_DATABASE_URL`, `NYLORUN_GATES_TOKEN`, its listener
|
|
65
|
+
(`NYLORUN_GATES_LISTEN_HOST`, `NYLORUN_GATES_LISTEN_PORT`, default 4100, and
|
|
66
|
+
`NYLORUN_GATES_ALLOWED_HOSTS`) and the Host's `tenant/` directory, which it
|
|
67
|
+
never writes; it serves the database's one Tenant. `NYLORUN_PACKING` (`combined` or `split`) is logged at startup.
|
|
68
|
+
|
|
69
|
+
With an operator listener (a local Tenant's default: container port 4001), the Host
|
|
46
70
|
serves two ports. The public one serves the Tenant API, to browsers too when
|
|
47
71
|
browser access is on, and answers admin routes with the opaque `404`. The
|
|
48
72
|
operator one serves the Admin API, Host shutdown and the Tenant API, never to
|
|
49
73
|
browsers; keep it on loopback or a private network and never proxy it. Outside
|
|
50
74
|
a container, `adminPort` in `host.json` does the same on loopback.
|
|
51
75
|
|
|
52
|
-
The Host root is `NYLORUN_HOME` or `~/.nylorun` (
|
|
53
|
-
|
|
76
|
+
The Host root is `NYLORUN_HOME` or `~/.nylorun` (for a local Tenant,
|
|
77
|
+
`~/.nylorun/tenants/<name>/`, bind-mounted at `/nylorun` in its containers). What stays on the Host is under `tenant/`.
|
|
54
78
|
|
|
55
79
|
## Layout
|
|
56
80
|
|
|
@@ -58,9 +82,8 @@ the stack). What stays on the Host is under `tenants/<tenantId>/`.
|
|
|
58
82
|
<host root>/
|
|
59
83
|
host.json # format 1: hostId, host, port, adminPort?, runtimeVersion, …
|
|
60
84
|
host-credentials.json # adminKey (0600)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
trash/ # SQLite Tenants from before the Postgres switch
|
|
85
|
+
docker/ # compose.yaml, .env (0600), Restate identity key
|
|
86
|
+
tenant/ # vault-kek, plugin-data, logs, home, tmp, sandboxes
|
|
64
87
|
```
|
|
65
88
|
|
|
66
89
|
## HTTP surface
|
|
@@ -68,25 +91,25 @@ the stack). What stays on the Host is under `tenants/<tenantId>/`.
|
|
|
68
91
|
| Route | Auth | Notes |
|
|
69
92
|
| --- | --- | --- |
|
|
70
93
|
| `GET /health` | none | `service: "nylorun-runtime"`, `hostId`, protocol `{min,max,features}`, pid |
|
|
71
|
-
| `GET /ready` | none | Listener up,
|
|
94
|
+
| `GET /ready` | none | Listener up, the Tenant open, and Postgres, Restate and S2 answer (`checks`) |
|
|
72
95
|
| `GET /openapi.json` | none | The Tenant API's OpenAPI 3.2 document (below); refuses an `Origin` |
|
|
73
|
-
| `GET /v1/admin/status` | admin key | `AdminStatusSchema
|
|
74
|
-
| `/v1/admin/tenants*` | admin key | Create / list / get / delete Tenants |
|
|
96
|
+
| `GET /v1/admin/status` | admin key | `AdminStatusSchema`: the Host, its protocol and its Tenant (`tenant`: id, name, `open` or `unavailable`, and the cause when it could not be opened); alias `GET /v1/admin/host`. On the operator listener when there is one |
|
|
75
97
|
| `POST /v1/admin/host/shutdown` | admin key | Host-private; not in `@nylorun/admin` |
|
|
76
98
|
| `GET /v1/admin/openapi.json` | admin key | The Admin API's OpenAPI 3.2 document |
|
|
77
|
-
| `/v1/*` Tenant routes | application key, subject token or delivery token | Require `Nylorun-
|
|
99
|
+
| `/v1/*` Tenant routes | application key, subject token or delivery token | Require `Nylorun-Protocol`; nothing names the Tenant |
|
|
78
100
|
|
|
79
101
|
Every route checks `Host` first (`421 host_rejected`) and rejects non-JSON bodies
|
|
80
102
|
with `415 unsupported_media_type`. An `Origin` is `403 origin_rejected` on
|
|
81
103
|
`/health`, `/ready`, admin routes, and everywhere when browser access is off.
|
|
82
|
-
With browser access on (feature `browser-access`:
|
|
104
|
+
With browser access on (feature `browser-access`: a local Tenant's default, or
|
|
83
105
|
`browserAccess` in `host.json`), the Host answers preflights for browser routes
|
|
84
106
|
from the route alone, and the Tenant admits an `Origin` only with a publishable
|
|
85
107
|
key (`Nylorun-Key`) that lists it, adding CORS headers only then; Tenant keys
|
|
86
|
-
and delivery tokens are refused from browsers before they are looked up.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
and delivery tokens are refused from browsers before they are looked up. Missing or
|
|
109
|
+
unsupported protocol → `426` before authentication (the Host serves protocols 4 and 5).
|
|
110
|
+
Protocol 5 clients name no Tenant. A protocol 4 client's `Nylorun-Tenant` naming
|
|
111
|
+
another Tenant (or malformed), a publishable key of another Tenant, a Tenant that
|
|
112
|
+
could not be opened and rejected credentials → opaque `404` with identical body. A path or method no route serves is `404 Route not found`
|
|
90
113
|
once the caller is known.
|
|
91
114
|
|
|
92
115
|
## API reference (OpenAPI)
|
|
@@ -126,10 +149,27 @@ and `api/` import Hono.
|
|
|
126
149
|
|
|
127
150
|
Tests and ephemeral embeds use `startEphemeralRuntime()` from
|
|
128
151
|
`@nylorun/runtime/core`: private Host on port 0, temporary Host root, one Tenant,
|
|
129
|
-
returns `{ url, tenantId, applicationKey, adminKey, close() }`.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
152
|
+
returns `{ url, tenantId, applicationKey, adminKey, close() }`. Its Tenant is the
|
|
153
|
+
one Tenant of the Postgres database you pass as `database` (required): a pool, which
|
|
154
|
+
you end, or a URL, for which it opens a pool and ends it on `close()`. It creates the
|
|
155
|
+
Tenant there on first start, as a Host does (with `tenantId`, `name` and an application
|
|
156
|
+
principal for `applicationKey`), and serves the Tenant a database already holds. The
|
|
157
|
+
data stays after `close()`; give each test Tenant its own database and drop it
|
|
158
|
+
afterwards. Its
|
|
159
|
+
streams and scheduling are in process and gone after `close()`. The smoke checks do
|
|
160
|
+
not use it; they reset and seed a temporary local Tenant
|
|
161
|
+
(`scripts/lib/stack-tenant.mjs`).
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
const runtime = await startEphemeralRuntime({
|
|
165
|
+
hostRoot, // a temporary directory
|
|
166
|
+
database: "postgres://nylorun:nylorun@127.0.0.1:55432/my_test_db",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The package's own tests run every Session Store on Postgres: `npm test` gives each
|
|
171
|
+
test file a database on the Docker test stack (`test/stack/compose.yaml`) and starts
|
|
172
|
+
the stack when it is down; see [CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
133
173
|
|
|
134
174
|
Register Action endpoints with `PUT /v1/endpoints` using the application principal
|
|
135
175
|
(`createActionHandler(...).register({ url })` in `@nylorun/agents` does this). The
|
|
@@ -147,7 +187,7 @@ delivery token authorizes only its own Action's heartbeat, result and sandbox ca
|
|
|
147
187
|
Session observers cannot submit action results.
|
|
148
188
|
|
|
149
189
|
Postgres transactions persist session checkpoints, command receipts, individual
|
|
150
|
-
effects/actions, waits and the
|
|
190
|
+
effects/actions, waits and the record of session events — in the Tenant's database; history is
|
|
151
191
|
read from Durable Streams (S2). An advance owns its session through a lease with
|
|
152
192
|
an epoch; a Worker that takes over after a crash marks in-flight effects
|
|
153
193
|
`uncertain`. Vault ciphertext needs that Tenant's own KEK.
|
|
@@ -157,22 +197,24 @@ Tenant owns each sandbox; backend names are prefixed `nylorun-<tenant-id>-`.
|
|
|
157
197
|
|
|
158
198
|
## Local Project workflow
|
|
159
199
|
|
|
160
|
-
A project depends on `@nylorun/agents` only. `npx nylorun
|
|
161
|
-
|
|
162
|
-
project
|
|
163
|
-
`
|
|
200
|
+
A project depends on `@nylorun/agents` only. `npx nylorun start` in the project
|
|
201
|
+
runs its local Tenant (Docker), named after the project directory, and writes
|
|
202
|
+
the Project link (outside a project it runs the Tenant `default`); the project's `npm run dev` runs `src/main.ts` under
|
|
203
|
+
`tsx watch`; `npx nylorun studio` opens Studio on that Tenant.
|
|
164
204
|
|
|
165
205
|
## Troubleshooting
|
|
166
206
|
|
|
167
207
|
| Symptom | What to do |
|
|
168
208
|
| --- | --- |
|
|
169
209
|
| `kek-missing` | Restore `vault-kek` in the Tenant directory |
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
210
|
+
| `GET /ready` is 503 and `/v1/admin/status` names a `tenant.cause` | The Tenant could not be opened; every Tenant request is the opaque `404`. Follow the cause's `repair`, then restart the Runtime |
|
|
211
|
+
| `corrupt` / `migration-failed` / `envelope-invalid` / `open-failed` / `open-timeout` | Follow the cause's `repair` string |
|
|
212
|
+
| `schema-too-new` | Run a Runtime at least as new as the one that migrated the database |
|
|
213
|
+
| `database-layout-old` | The database holds `tenant_<id>` schemas of an older Runtime, or the `schema_version` tables of a pre-release one: point the Runtime at a new database (locally, a new Tenant: `nylorun start --tenant <new name>`); the old one is left as it is |
|
|
172
214
|
| `426 protocol_unsupported` | Upgrade clients or Host to a compatible set |
|
|
173
215
|
| `421 host_rejected` / `403 origin_rejected` | In a container, list the `Host` in `NYLORUN_ALLOWED_HOSTS`. From a browser, use a subject token and a publishable key that lists the page's origin, never a Tenant key |
|
|
174
216
|
| `503` for a Tenant | Postgres or Restate is unreachable; `GET /ready` names which |
|
|
175
|
-
| Port in use | Change `NYLORUN_PORT` in
|
|
217
|
+
| Port in use | Change `NYLORUN_PORT` in `~/.nylorun/tenants/<name>/docker/.env` and run `nylorun start` |
|
|
176
218
|
| Logs | `nylorun logs runtime` |
|
|
177
219
|
|
|
178
220
|
Definitions have no `agent.run()`; applications use `@nylorun/agents`.
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* - `<prefix>NylorunTenant`, key `<tenantId>`. `arm`, `sweep` and `disarm`
|
|
13
13
|
* keep one self-re-arming sweep chain per Tenant. The chain's generation is
|
|
14
14
|
* kept in the object's state, so arming is idempotent and a disarmed or
|
|
15
|
-
* replaced chain dies at its next link. The state is rebuildable:
|
|
16
|
-
* re-
|
|
15
|
+
* replaced chain dies at its next link. The state is rebuildable: a Host
|
|
16
|
+
* re-arms its Tenant's sweep when it opens it, at every start (§14.8).
|
|
17
17
|
* - `<prefix>NylorunTimer`, key `<tenantId>:<timer key>`. `set` records the
|
|
18
18
|
* latest time and sends a delayed `fire`; a `fire` for an older time is a
|
|
19
19
|
* no-op, which is how setting a key again replaces it.
|
|
@@ -2,6 +2,11 @@ import type { ChangeSource } from "../../streams/relay/types.js";
|
|
|
2
2
|
export interface PgoutputSourceOptions {
|
|
3
3
|
/** A Postgres URL whose role may replicate (`REPLICATION`) and read `nylorun_streams`. */
|
|
4
4
|
connectionString: string;
|
|
5
|
+
/**
|
|
6
|
+
* The Tenant the database holds. The record has no Tenant column (one Tenant per
|
|
7
|
+
* database), so every row read is this Tenant's.
|
|
8
|
+
*/
|
|
9
|
+
tenantId: string;
|
|
5
10
|
/** Default `nylorun_stream_relay`. */
|
|
6
11
|
slot?: string;
|
|
7
12
|
/** Default `nylorun_stream_relay`. */
|
|
@@ -25,6 +25,7 @@ export function createPgoutputSource(options) {
|
|
|
25
25
|
const publication = options.publication ?? "nylorun_stream_relay";
|
|
26
26
|
const schema = options.schema ?? "nylorun_streams";
|
|
27
27
|
const retryMs = options.retryMs ?? 5000;
|
|
28
|
+
const { tenantId } = options;
|
|
28
29
|
const log = options.log ?? (() => { });
|
|
29
30
|
const pool = new pg.Pool({
|
|
30
31
|
connectionString: options.connectionString,
|
|
@@ -84,7 +85,7 @@ export function createPgoutputSource(options) {
|
|
|
84
85
|
if (decoding &&
|
|
85
86
|
message.relation?.schema === schema &&
|
|
86
87
|
message.relation?.name === "session_events")
|
|
87
|
-
decoding.rows.push(rowOf(message.new));
|
|
88
|
+
decoding.rows.push(rowOf(message.new, tenantId));
|
|
88
89
|
break;
|
|
89
90
|
case "commit": {
|
|
90
91
|
const tx = { endLsn: message.commitEndLsn, rows: decoding?.rows ?? [] };
|
|
@@ -158,9 +159,9 @@ export function createPgoutputSource(options) {
|
|
|
158
159
|
};
|
|
159
160
|
}
|
|
160
161
|
/** A decoded `session_events` row (`pg` parses `json`; `bigint` arrives as text). */
|
|
161
|
-
function rowOf(values) {
|
|
162
|
+
function rowOf(values, tenantId) {
|
|
162
163
|
return {
|
|
163
|
-
tenantId
|
|
164
|
+
tenantId,
|
|
164
165
|
sessionId: values.session_id,
|
|
165
166
|
seq: Number(values.seq),
|
|
166
167
|
generation: Number(values.generation),
|