@nylorun/runtime 0.26.0-beta → 0.28.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 +171 -0
- package/README.md +18 -14
- package/dist/adapters/execution/restate.d.ts +15 -18
- package/dist/adapters/execution/restate.js +31 -27
- package/dist/adapters/replication/pgoutput.d.ts +1 -1
- package/dist/adapters/replication/pgoutput.js +3 -2
- package/dist/adapters/sandbox/local.js +8 -5
- package/dist/adapters/sandbox/virtual.js +2 -2
- package/dist/adapters/streams/s2.d.ts +1 -1
- package/dist/adapters/streams/s2.js +18 -14
- package/dist/api/a2a/card.d.ts +4 -3
- package/dist/api/a2a/card.js +4 -4
- package/dist/api/a2a/endpoint.js +3 -4
- package/dist/api/a2a/protocol.js +4 -0
- package/dist/api/a2a/routes.d.ts +2 -6
- package/dist/api/a2a/routes.js +30 -25
- package/dist/api/ag-ui/endpoint.js +2 -3
- package/dist/api/ag-ui/routes.js +8 -11
- package/dist/api/components.d.ts +6789 -3405
- package/dist/api/components.js +43 -30
- package/dist/api/gate/keys.js +7 -4
- package/dist/api/gate/routes.d.ts +6 -2
- package/dist/api/gate/routes.js +15 -11
- package/dist/api/http/app.js +9 -4
- package/dist/api/http/body.d.ts +17 -3
- package/dist/api/http/body.js +35 -7
- package/dist/api/http/respond.js +6 -2
- package/dist/api/http/routes/access.js +5 -4
- package/dist/api/http/routes/agent-manifests.d.ts +10 -0
- package/dist/api/http/routes/agent-manifests.js +135 -0
- package/dist/api/http/routes/agents.d.ts +11 -0
- package/dist/api/http/routes/agents.js +418 -0
- package/dist/api/http/routes/artifacts.js +21 -9
- package/dist/api/http/routes/coverage.d.ts +4 -4
- package/dist/api/http/routes/coverage.js +13 -7
- package/dist/api/http/routes/files.d.ts +2 -1
- package/dist/api/http/routes/files.js +31 -5
- package/dist/api/http/routes/mcp.js +3 -3
- package/dist/api/http/routes/me.d.ts +1 -1
- package/dist/api/http/routes/me.js +1 -2
- package/dist/api/http/routes/memories.d.ts +9 -0
- package/dist/api/http/routes/memories.js +152 -0
- package/dist/api/http/routes/reads.d.ts +10 -111
- package/dist/api/http/routes/reads.js +51 -29
- package/dist/api/http/routes/sessions.js +26 -54
- package/dist/api/http/routes/tenant.d.ts +2 -2
- package/dist/api/http/routes/tenant.js +77 -24
- package/dist/api/http/routes/triggers.d.ts +10 -0
- package/dist/api/http/routes/triggers.js +180 -0
- package/dist/api/inbound-files.d.ts +3 -9
- package/dist/api/inbound-files.js +18 -24
- package/dist/api/openapi.js +73 -47
- package/dist/artifacts/disk.d.ts +10 -14
- package/dist/artifacts/disk.js +99 -95
- package/dist/artifacts/files.d.ts +13 -4
- package/dist/artifacts/files.js +27 -9
- package/dist/artifacts/folder-upload.d.ts +75 -0
- package/dist/artifacts/folder-upload.js +263 -0
- package/dist/artifacts/folders.d.ts +14 -8
- package/dist/artifacts/folders.js +19 -11
- package/dist/artifacts/links.js +7 -6
- package/dist/artifacts/parts.d.ts +9 -14
- package/dist/artifacts/parts.js +11 -9
- package/dist/artifacts/pipe.d.ts +15 -0
- package/dist/artifacts/pipe.js +71 -0
- package/dist/artifacts/quota.d.ts +36 -0
- package/dist/artifacts/quota.js +44 -0
- package/dist/artifacts/service.d.ts +25 -1
- package/dist/artifacts/service.js +72 -27
- package/dist/blob/fs.js +2 -1
- package/dist/blob/s3.d.ts +6 -2
- package/dist/blob/s3.js +9 -7
- package/dist/blob/types.d.ts +1 -1
- package/dist/blob/types.js +1 -1
- package/dist/core/flow-host.d.ts +0 -1
- package/dist/core/limits.d.ts +11 -35
- package/dist/core/limits.js +5 -73
- package/dist/core/sandbox-routes.js +0 -1
- package/dist/core/turn-manifest.d.ts +1 -2
- package/dist/core/turn-manifest.js +4 -28
- package/dist/execution/memory.d.ts +8 -5
- package/dist/execution/memory.js +8 -6
- package/dist/execution/types.d.ts +1 -6
- package/dist/execution/types.js +0 -5
- package/dist/gates/contract.d.ts +3 -2
- package/dist/gates/contract.js +1 -1
- package/dist/gates/egress-credentials.js +5 -4
- package/dist/gates/egress.d.ts +13 -13
- package/dist/gates/egress.js +19 -21
- package/dist/gates/fixture-model.js +13 -2
- package/dist/gates/handler.d.ts +1 -3
- package/dist/gates/handler.js +4 -3
- package/dist/gates/http-client.d.ts +4 -3
- package/dist/gates/http-client.js +5 -7
- package/dist/gates/http-tool.d.ts +24 -4
- package/dist/gates/http-tool.js +41 -13
- package/dist/gates/in-process.d.ts +2 -1
- package/dist/gates/in-process.js +17 -9
- package/dist/gates/inflight.d.ts +2 -2
- package/dist/gates/inflight.js +3 -2
- package/dist/gates/journal.js +5 -7
- package/dist/gates/mcp-handler.d.ts +4 -3
- package/dist/gates/mcp-handler.js +15 -5
- package/dist/gates/meter.js +6 -5
- package/dist/gates/model-gate.d.ts +11 -2
- package/dist/gates/policy.d.ts +34 -6
- package/dist/gates/policy.js +66 -18
- package/dist/gates/provider-gate.d.ts +22 -0
- package/dist/gates/provider-gate.js +30 -0
- package/dist/gates/tool-calls.d.ts +1 -3
- package/dist/gates/tool-calls.js +2 -3
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +5 -6
- package/dist/gates/tool-contract.d.ts +8 -5
- package/dist/gates/tool-contract.js +1 -1
- package/dist/gates/tool-gate.d.ts +18 -7
- package/dist/gates/tool-gate.js +49 -7
- package/dist/harness/calls.d.ts +27 -25
- package/dist/harness/calls.js +40 -46
- package/dist/harness/executors.d.ts +10 -3
- package/dist/harness/executors.js +53 -23
- package/dist/harness/main.js +2 -2
- package/dist/harness/pod.d.ts +2 -2
- package/dist/harness/pod.js +7 -6
- package/dist/harness/run-tokens.d.ts +4 -1
- package/dist/harness/run-tokens.js +6 -2
- package/dist/harness/service.d.ts +17 -14
- package/dist/harness/service.js +21 -35
- package/dist/harness/setup.d.ts +0 -2
- package/dist/harness/setup.js +21 -15
- package/dist/harness/ws-client.d.ts +2 -2
- package/dist/harness/ws-client.js +7 -5
- package/dist/harness/ws-port.d.ts +3 -4
- package/dist/harness/ws-port.js +3 -4
- package/dist/harness-api/artifacts.d.ts +20 -0
- package/dist/harness-api/artifacts.js +478 -0
- package/dist/harness-api/in-process.d.ts +2 -2
- package/dist/harness-api/in-process.js +18 -16
- package/dist/harness-api/record.d.ts +10 -9
- package/dist/harness-api/record.js +113 -157
- package/dist/harness-api/renew.d.ts +1 -1
- package/dist/harness-api/renew.js +2 -2
- package/dist/harness-api/server.d.ts +1 -16
- package/dist/harness-api/server.js +86 -73
- package/dist/harness-api/start.d.ts +27 -5
- package/dist/harness-api/start.js +102 -19
- package/dist/harness-api/tool-journal.d.ts +15 -10
- package/dist/harness-api/tool-journal.js +26 -24
- package/dist/harness-api/workspace.d.ts +0 -4
- package/dist/harness-api/workspace.js +4 -47
- package/dist/harness-api/ws-server.js +10 -10
- package/dist/host/create-host.js +2 -3
- package/dist/host/execution.js +2 -3
- package/dist/host/gates.d.ts +2 -9
- package/dist/host/gates.js +15 -12
- package/dist/host/http.d.ts +2 -4
- package/dist/host/http.js +5 -29
- package/dist/host/main.js +10 -3
- package/dist/host/operate.js +12 -3
- package/dist/host/stack-config.d.ts +11 -0
- package/dist/host/stack-config.js +21 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/infra/index.js +2 -1
- package/dist/infra/readiness.d.ts +0 -2
- package/dist/infra/readiness.js +4 -3
- package/dist/keys/client.d.ts +1 -0
- package/dist/keys/client.js +2 -3
- package/dist/keys/contract.d.ts +0 -2
- package/dist/keys/contract.js +0 -2
- package/dist/keys/egress-ca.d.ts +0 -2
- package/dist/keys/egress-ca.js +2 -3
- package/dist/keys/keys.d.ts +15 -4
- package/dist/keys/keys.js +22 -1
- package/dist/keys/webhooks.d.ts +25 -0
- package/dist/keys/webhooks.js +62 -0
- package/dist/keys/x509.d.ts +8 -4
- package/dist/keys/x509.js +14 -5
- package/dist/management-openapi.json +3043 -1954
- package/dist/mcp/connect.d.ts +35 -26
- package/dist/mcp/connect.js +112 -141
- package/dist/mcp/pool.d.ts +27 -22
- package/dist/mcp/pool.js +34 -48
- package/dist/mcp/preview.d.ts +12 -5
- package/dist/mcp/preview.js +43 -26
- package/dist/mcp/snapshot.d.ts +35 -86
- package/dist/mcp/snapshot.js +93 -135
- package/dist/memory/service.d.ts +97 -0
- package/dist/memory/service.js +335 -0
- package/dist/memory/tool.d.ts +36 -0
- package/dist/memory/tool.js +84 -0
- package/dist/model/auth-store.js +5 -3
- package/dist/model/capabilities.d.ts +1 -1
- package/dist/model/catalog.d.ts +9 -36
- package/dist/model/catalog.js +6 -33
- package/dist/model/descriptor.d.ts +51 -0
- package/dist/model/descriptor.js +83 -0
- package/dist/model/models.d.ts +0 -3
- package/dist/model/models.js +3 -5
- package/dist/model/native-blocks.js +1 -1
- package/dist/model/pi-model.d.ts +16 -5
- package/dist/model/pi-model.js +86 -105
- package/dist/openapi.json +13653 -9986
- package/dist/reads/cursor.js +3 -1
- package/dist/reads/types.d.ts +3 -3
- package/dist/record/agent.d.ts +27 -0
- package/dist/record/agent.js +46 -0
- package/dist/record/append.d.ts +34 -2
- package/dist/record/append.js +50 -1
- package/dist/record/index.d.ts +2 -2
- package/dist/record/index.js +2 -2
- package/dist/redact.d.ts +1 -1
- package/dist/redact.js +3 -2
- package/dist/sandbox/egress-token.d.ts +3 -3
- package/dist/sandbox/egress-token.js +3 -3
- package/dist/sandbox/join.js +8 -7
- package/dist/sandbox/manager.d.ts +41 -41
- package/dist/sandbox/manager.js +112 -44
- package/dist/sandbox/placement.d.ts +2 -2
- package/dist/sandbox/placement.js +7 -10
- package/dist/sandbox/pods/client.d.ts +1 -10
- package/dist/sandbox/pods/client.js +8 -4
- package/dist/sandbox/pods/lifecycle.d.ts +25 -17
- package/dist/sandbox/pods/lifecycle.js +51 -29
- package/dist/sandbox/pods/network-gate.d.ts +4 -5
- package/dist/sandbox/pods/network-gate.js +7 -7
- package/dist/sandbox/pods/reconcile.js +14 -3
- package/dist/sandbox/pods/spec.js +8 -5
- package/dist/sandbox/policy.d.ts +7 -1
- package/dist/sandbox/policy.js +10 -3
- package/dist/sandbox/resolve.d.ts +11 -6
- package/dist/sandbox/resolve.js +19 -9
- package/dist/sandbox/setup.d.ts +6 -2
- package/dist/sandbox/setup.js +47 -14
- package/dist/sandbox/share.d.ts +5 -14
- package/dist/sandbox/share.js +5 -34
- package/dist/sandbox/skills.d.ts +7 -13
- package/dist/sandbox/skills.js +16 -31
- package/dist/sandbox/tenant-config.d.ts +2 -2
- package/dist/sandbox/tenant-config.js +4 -3
- package/dist/sandbox/tools.d.ts +7 -1
- package/dist/sandbox/tools.js +26 -26
- package/dist/sandbox/types.d.ts +10 -3
- package/dist/sandbox/types.js +9 -0
- package/dist/store/postgres/connect.d.ts +6 -5
- package/dist/store/postgres/connect.js +14 -11
- package/dist/store/postgres/control.js +13 -13
- package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
- package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
- package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
- package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
- package/dist/store/postgres/drizzle/0032_agents.sql +54 -0
- package/dist/store/postgres/drizzle/0033_agent_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0034_protocol_17_session_queue.sql +13 -0
- package/dist/store/postgres/drizzle/0035_t4_triggers.sql +41 -0
- package/dist/store/postgres/drizzle/0036_t5_memories.sql +30 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +63 -0
- package/dist/store/postgres/reads.js +17 -82
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/schema.d.ts +1382 -151
- package/dist/store/postgres/schema.js +191 -37
- package/dist/store/postgres/store.js +384 -105
- package/dist/store/postgres/tenant.js +1 -2
- package/dist/store/types.d.ts +172 -57
- package/dist/store/types.js +0 -1
- package/dist/streams/relay/core.d.ts +3 -3
- package/dist/streams/relay/core.js +9 -10
- package/dist/tenant/advance.js +41 -39
- package/dist/tenant/agent-manifests.d.ts +72 -0
- package/dist/tenant/agent-manifests.js +359 -0
- package/dist/tenant/agent-versions.d.ts +126 -0
- package/dist/tenant/agent-versions.js +389 -0
- package/dist/tenant/agents.d.ts +230 -0
- package/dist/tenant/{environments.js → agents.js} +493 -328
- package/dist/tenant/auth.d.ts +1 -1
- package/dist/tenant/auth.js +3 -3
- package/dist/tenant/commands.d.ts +63 -2
- package/dist/tenant/commands.js +240 -90
- package/dist/tenant/context.d.ts +57 -33
- package/dist/tenant/context.js +6 -2
- package/dist/tenant/definition-files.d.ts +25 -4
- package/dist/tenant/definition-files.js +85 -47
- package/dist/tenant/effects.js +15 -51
- package/dist/tenant/ephemeral.js +2 -1
- package/dist/tenant/history.d.ts +1 -1
- package/dist/tenant/history.js +1 -1
- package/dist/tenant/host-token.d.ts +3 -3
- package/dist/tenant/host-token.js +11 -10
- package/dist/tenant/http.d.ts +5 -8
- package/dist/tenant/http.js +9 -0
- package/dist/tenant/identity-file.d.ts +29 -6
- package/dist/tenant/identity-file.js +45 -15
- package/dist/tenant/issuers.d.ts +5 -5
- package/dist/tenant/issuers.js +34 -26
- package/dist/tenant/jwt.d.ts +8 -2
- package/dist/tenant/jwt.js +10 -2
- package/dist/tenant/limits.d.ts +87 -0
- package/dist/tenant/limits.js +172 -0
- package/dist/tenant/memories.d.ts +38 -0
- package/dist/tenant/memories.js +119 -0
- package/dist/tenant/module.d.ts +4 -1
- package/dist/tenant/module.js +9 -8
- package/dist/tenant/outbound.d.ts +11 -14
- package/dist/tenant/outbound.js +10 -15
- package/dist/tenant/reset.js +2 -2
- package/dist/tenant/run-grants.d.ts +6 -0
- package/dist/tenant/run-grants.js +7 -2
- package/dist/tenant/run-token.d.ts +0 -4
- package/dist/tenant/run-token.js +6 -11
- package/dist/tenant/runtime-limits.d.ts +24 -0
- package/dist/tenant/runtime-limits.js +27 -0
- package/dist/tenant/runtime.d.ts +1 -1
- package/dist/tenant/runtime.js +38 -43
- package/dist/tenant/session-streams.js +7 -6
- package/dist/tenant/session.d.ts +1 -1
- package/dist/tenant/session.js +1 -1
- package/dist/tenant/sessions.d.ts +28 -45
- package/dist/tenant/sessions.js +89 -209
- package/dist/tenant/signing-keys.d.ts +1 -1
- package/dist/tenant/signing-keys.js +5 -6
- package/dist/tenant/status.js +10 -10
- package/dist/tenant/streams.js +18 -20
- package/dist/tenant/sweep.d.ts +1 -21
- package/dist/tenant/sweep.js +51 -51
- package/dist/tenant/transcript.d.ts +70 -23
- package/dist/tenant/transcript.js +28 -22
- package/dist/tenant/triggers.d.ts +143 -0
- package/dist/tenant/triggers.js +715 -0
- package/dist/tenant/turn-timing.d.ts +11 -1
- package/dist/tenant/turn-timing.js +3 -1
- package/dist/tenant/types.d.ts +9 -14
- package/dist/tenant/worker.d.ts +4 -10
- package/dist/tenant/worker.js +10 -14
- package/dist/traces/ids.js +5 -1
- package/dist/traces/map.d.ts +10 -7
- package/dist/traces/map.js +16 -12
- package/dist/traces/otlp.d.ts +3 -3
- package/dist/traces/otlp.js +5 -3
- package/dist/traces/projector.d.ts +9 -4
- package/dist/traces/projector.js +13 -7
- package/dist/traces/read.js +6 -1
- package/dist/tuning.d.ts +390 -0
- package/dist/tuning.js +677 -0
- package/dist/vault/headers.js +4 -2
- package/dist/vault/service.d.ts +13 -8
- package/dist/vault/service.js +61 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +13 -12
- package/dist/api/http/routes/environment-manifests.d.ts +0 -9
- package/dist/api/http/routes/environment-manifests.js +0 -118
- package/dist/api/http/routes/environments.d.ts +0 -11
- package/dist/api/http/routes/environments.js +0 -332
- package/dist/artifacts/export.d.ts +0 -8
- package/dist/artifacts/export.js +0 -204
- package/dist/artifacts/media-types.d.ts +0 -30
- package/dist/artifacts/media-types.js +0 -137
- package/dist/artifacts/workspace.d.ts +0 -60
- package/dist/artifacts/workspace.js +0 -45
- package/dist/media.d.ts +0 -10
- package/dist/media.js +0 -58
- package/dist/record/environment.d.ts +0 -25
- package/dist/record/environment.js +0 -44
- package/dist/sandbox/runtime-tools.d.ts +0 -9
- package/dist/sandbox/runtime-tools.js +0 -16
- package/dist/sandbox/session-sandbox.d.ts +0 -16
- package/dist/sandbox/session-sandbox.js +0 -77
- package/dist/tenant/artifact-tool.d.ts +0 -13
- package/dist/tenant/artifact-tool.js +0 -243
- package/dist/tenant/environment-manifests.d.ts +0 -57
- package/dist/tenant/environment-manifests.js +0 -200
- package/dist/tenant/environments.d.ts +0 -174
- package/dist/tenant/skill-tool.d.ts +0 -20
- package/dist/tenant/skill-tool.js +0 -67
- package/dist/tenant/tool-results.d.ts +0 -57
- package/dist/tenant/tool-results.js +0 -298
- package/dist/tenant/tool-search.d.ts +0 -39
- package/dist/tenant/tool-search.js +0 -103
package/dist/tenant/sessions.js
CHANGED
|
@@ -1,108 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Session
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Session resources: `PUT /v1/sessions/:id` (create, or find an identical one), the session list
|
|
3
|
+
* and the session view. A session runs on one Agent (protocol 16) and pins the manifest version
|
|
4
|
+
* the Agent runs when it opens; each turn takes the version the Agent runs then
|
|
5
|
+
* (`agent-versions.ts`). Reads use the store's typed queries; `PUT /v1/sessions/:id` runs in
|
|
6
|
+
* one transaction with the Agent's checks.
|
|
5
7
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import { hashManifest } from "@nylorun/core/compatibility";
|
|
8
|
-
import { approvalRefusal, codeToolRefusal } from "@nylorun/core/define";
|
|
8
|
+
import {} from "@nylorun/core/contracts";
|
|
9
9
|
import { aggregateWaits, isWorkflowManifest } from "../core/flow-host.js";
|
|
10
10
|
import { canonical } from "../store/canonical.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { openEnvironment, recordAttachment } from "./environments.js";
|
|
17
|
-
import { harnessOf, } from "./context.js";
|
|
11
|
+
import { readSandboxConfig } from "../sandbox/tenant-config.js";
|
|
12
|
+
import { checkPlacement, requirePods } from "../sandbox/placement.js";
|
|
13
|
+
import { pinOf } from "./agent-versions.js";
|
|
14
|
+
import { openAgent, recordAttachment } from "./agents.js";
|
|
15
|
+
import { harnessOf, reachesAgent, } from "./context.js";
|
|
18
16
|
import { fail } from "./http.js";
|
|
19
|
-
import {
|
|
17
|
+
import { definitionFileIssues } from "./definition-files.js";
|
|
18
|
+
import { limitsInForce, readTenantLimits } from "./limits.js";
|
|
20
19
|
/** A session's creation identity: everything but the request id. */
|
|
21
20
|
const sessionIdentity = (value) => {
|
|
22
21
|
const { requestId: _requestId, ...body } = value ?? {};
|
|
23
22
|
return canonical(body);
|
|
24
23
|
};
|
|
25
|
-
export async function listDefinitions(ctx) {
|
|
26
|
-
const definitions = await ctx.store.tx((t) => t.listDefinitions());
|
|
27
|
-
return {
|
|
28
|
-
agents: definitions.map((d) => ({
|
|
29
|
-
agentId: d.manifest.id,
|
|
30
|
-
manifest: d.manifest,
|
|
31
|
-
manifestHash: d.manifestHash,
|
|
32
|
-
implementationVersion: d.implementationVersion,
|
|
33
|
-
})),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* The agents a token caller may see: id, name and description only, never
|
|
38
|
-
* instructions, tools or MCP servers, and only the agents allowed.
|
|
39
|
-
*/
|
|
40
|
-
export async function listAgentsPublic(ctx, agents) {
|
|
41
|
-
const definitions = await ctx.store.tx((t) => t.listDefinitions());
|
|
42
|
-
return {
|
|
43
|
-
agents: definitions
|
|
44
|
-
.filter((d) => agents === "*" || agents.has(d.manifest.id))
|
|
45
|
-
.map((d) => ({
|
|
46
|
-
agentId: d.manifest.id,
|
|
47
|
-
...(typeof d.manifest.name === "string" ? { name: d.manifest.name } : {}),
|
|
48
|
-
...(typeof d.manifest.description === "string"
|
|
49
|
-
? { description: d.manifest.description }
|
|
50
|
-
: {}),
|
|
51
|
-
})),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
export async function putDefinition(ctx, agentId, body, options = {}) {
|
|
55
|
-
if (body.manifest.id !== agentId)
|
|
56
|
-
fail(400, "Agent id mismatch");
|
|
57
|
-
DefinitionDocumentSchema.parse(body.manifest);
|
|
58
|
-
// The Runtime runs agents from their manifests alone (track R2): no tool may need it.
|
|
59
|
-
const code = codeToolRefusal(body.manifest);
|
|
60
|
-
if (code)
|
|
61
|
-
fail(400, code);
|
|
62
|
-
// Tool approvals are the Tenant's tool policy, decided at the Tool Gate (R5 step 2).
|
|
63
|
-
const approval = approvalRefusal(body.manifest);
|
|
64
|
-
if (approval)
|
|
65
|
-
fail(400, approval);
|
|
66
|
-
const declared = declaredSandboxes(body.manifest);
|
|
67
|
-
if (declared.length > 0)
|
|
68
|
-
fail(400, `${declared.join(", ")} declares a sandbox. Agents no longer declare one: remove .sandbox(), create an Environment with the sandbox (PUT /v1/environments/{id}) and open the session on it, createSession({ environment }). See MIGRATION.md.`);
|
|
69
|
-
const runtime = authoredRuntimeBlocks(body.manifest);
|
|
70
|
-
if (runtime.length > 0)
|
|
71
|
-
fail(400, `${runtime.join(", ")} sets runtime, which only the Runtime writes when it pins a session's agent. Remove it and register the manifest your builder makes.`);
|
|
72
|
-
const definition = {
|
|
73
|
-
...body,
|
|
74
|
-
manifestHash: hashManifest(body.manifest),
|
|
75
|
-
};
|
|
76
|
-
const files = [...definitionFilesOf(body.manifest)];
|
|
77
|
-
await ctx.store.tx(async (t) => {
|
|
78
|
-
const missing = await missingDefinitionFiles(t, body.manifest);
|
|
79
|
-
if (missing.length > 0)
|
|
80
|
-
fail(400, `The definition names ${missing.length} file(s) the Runtime does not hold; upload each with PUT /v1/files/<sha256> first: ${missing.join(", ")}`, { code: "definition_files_missing", details: { missing } });
|
|
81
|
-
if (options.dryRun)
|
|
82
|
-
return;
|
|
83
|
-
await t.put("definitions", agentId, definition);
|
|
84
|
-
await t.insertDefinitionFileUses(agentId, definition.manifestHash, files);
|
|
85
|
-
});
|
|
86
|
-
return {
|
|
87
|
-
agentId,
|
|
88
|
-
manifestHash: definition.manifestHash,
|
|
89
|
-
implementationVersion: body.implementationVersion,
|
|
90
|
-
...(options.dryRun ? { dryRun: true } : {}),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
24
|
/**
|
|
94
|
-
* `access`, when the request acts for a person, limits the list to that person's sessions
|
|
95
|
-
* the
|
|
25
|
+
* `access`, when the request acts for a person, limits the list to that person's sessions on
|
|
26
|
+
* the Agents they may use.
|
|
96
27
|
*/
|
|
97
28
|
export async function listSessions(ctx, agentId, access) {
|
|
98
29
|
const sessions = await ctx.store.tx((t) => t.listSessions({
|
|
99
30
|
...(agentId === null ? {} : { agentId }),
|
|
100
31
|
...(access === undefined ? {} : { ownerUserId: access.owner }),
|
|
101
32
|
}));
|
|
102
|
-
const allowed = access?.agents;
|
|
103
33
|
return {
|
|
104
34
|
sessions: sessions
|
|
105
|
-
.filter((s) =>
|
|
35
|
+
.filter((s) => reachesAgent(access, s.agentId))
|
|
106
36
|
.map((s) => ({
|
|
107
37
|
id: s.id,
|
|
108
38
|
agentId: s.agentId,
|
|
@@ -113,137 +43,90 @@ export async function listSessions(ctx, agentId, access) {
|
|
|
113
43
|
};
|
|
114
44
|
}
|
|
115
45
|
/**
|
|
116
|
-
* Create a session
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* another owner.
|
|
46
|
+
* Create a session on an Agent, or find an identical one. `access`, when the request acts for a
|
|
47
|
+
* subject, must be the session's owner: another owner's session id is the 404 of a missing one
|
|
48
|
+
* (not the 409 of a mismatch), and so is an Agent whose owner guard names another owner.
|
|
120
49
|
*
|
|
121
|
-
* The session
|
|
122
|
-
* the session's, with the spec of the
|
|
123
|
-
*
|
|
50
|
+
* The session runs on its Agent for its life: the Agent's sandbox (kinds `virtual` and `pod`) is
|
|
51
|
+
* the session's, with the spec of what the Agent runs pinned now, and the Agent's vault holds the
|
|
52
|
+
* session's credentials. It pins the manifest version the Agent runs (`definition`), as the loop
|
|
53
|
+
* manifest that version's harness section makes, and the harness that section names (`pinOf`);
|
|
54
|
+
* a turn's first segment pins the version the Agent runs then (`repinTurn`).
|
|
124
55
|
*/
|
|
125
56
|
export async function putSession(ctx, id, body, access, options = {}) {
|
|
126
57
|
const opaque = access !== undefined;
|
|
127
58
|
if (opaque && body.ownerUserId !== access.owner)
|
|
128
59
|
fail(403, "ownerUserId must be the subject");
|
|
129
|
-
// An
|
|
130
|
-
if (access
|
|
131
|
-
fail(404, "
|
|
132
|
-
return ctx.store.tx(
|
|
133
|
-
const prior = await t.lockSession(id);
|
|
134
|
-
if (opaque &&
|
|
135
|
-
prior &&
|
|
136
|
-
(prior.ownerUserId !== access.owner ||
|
|
137
|
-
(access.agents !== undefined && !access.agents.has(prior.agentId))))
|
|
138
|
-
fail(404, "Session not found");
|
|
139
|
-
if (prior && options.createOnly) {
|
|
140
|
-
if (prior.ownerUserId !== body.ownerUserId ||
|
|
141
|
-
prior.agentId !== body.agentId)
|
|
142
|
-
fail(404, "Session not found");
|
|
143
|
-
return prior;
|
|
144
|
-
}
|
|
145
|
-
if (prior) {
|
|
146
|
-
if (sessionIdentity(prior.creation) !== sessionIdentity(body))
|
|
147
|
-
fail(409, "Session already exists with different creation parameters");
|
|
148
|
-
return prior;
|
|
149
|
-
}
|
|
150
|
-
const definition = (await t.get("definitions", body.agentId)) ??
|
|
151
|
-
fail(404, "Definition not found");
|
|
152
|
-
const environment = body.environment === undefined
|
|
153
|
-
? undefined
|
|
154
|
-
: await openEnvironment(t, body.environment, {
|
|
155
|
-
...(options.environmentGrants === undefined ? {} : { grants: options.environmentGrants }),
|
|
156
|
-
ownerUserId: body.ownerUserId,
|
|
157
|
-
opaque,
|
|
158
|
-
});
|
|
159
|
-
if (!isWorkflowManifest(definition.manifest))
|
|
160
|
-
await checkRequirements(t, definition.manifest, environment);
|
|
161
|
-
const config = await readSandboxConfig(t);
|
|
162
|
-
// The harness the session runs for its life (R4.1): its Environment's, else ours. A flow
|
|
163
|
-
// runs in core and our engine, whatever its Environment names.
|
|
164
|
-
const harness = isWorkflowManifest(definition.manifest) || environment === undefined
|
|
165
|
-
? HARNESS_ID
|
|
166
|
-
: environment.applied.harness;
|
|
167
|
-
// Placement (D38, D52): where this session's harness may run, decided now and kept.
|
|
168
|
-
checkPlacement(config, environment?.kind, harness);
|
|
169
|
-
if (environment?.kind === "pod")
|
|
170
|
-
await requirePods(ctx.pods, `Environment ${environment.id}`);
|
|
171
|
-
const spec = environment === undefined || environment.kind === "none"
|
|
172
|
-
? undefined
|
|
173
|
-
: sandboxSpecOf(environment.applied, effectiveSandboxConfig(config).limits.idle);
|
|
174
|
-
const pinned = spec === undefined ? runtimeTools(definition) : pin(definition, spec);
|
|
175
|
-
const created = {
|
|
176
|
-
id,
|
|
177
|
-
agentId: body.agentId,
|
|
178
|
-
ownerUserId: body.ownerUserId,
|
|
179
|
-
manifest: pinned.manifest ?? definition.manifest,
|
|
180
|
-
manifestHash: pinned.manifestHash ?? definition.manifestHash,
|
|
181
|
-
definitionHash: definition.manifestHash,
|
|
182
|
-
implementationVersion: definition.implementationVersion,
|
|
183
|
-
info: body.info,
|
|
184
|
-
status: "idle",
|
|
185
|
-
activeTurnId: null,
|
|
186
|
-
creation: body,
|
|
187
|
-
harness,
|
|
188
|
-
...(environment === undefined
|
|
189
|
-
? {}
|
|
190
|
-
: { environmentId: environment.id, environmentVersion: environment.version }),
|
|
191
|
-
...(spec === undefined ? {} : { sandbox: spec }),
|
|
192
|
-
};
|
|
193
|
-
await t.put("sessions", id, created);
|
|
194
|
-
if (environment !== undefined)
|
|
195
|
-
await recordAttachment(t, id, environment.id);
|
|
196
|
-
return created;
|
|
197
|
-
});
|
|
60
|
+
// An Agent the subject may not use is the 404 of a missing one.
|
|
61
|
+
if (!reachesAgent(access, body.agent))
|
|
62
|
+
fail(404, "Agent not found");
|
|
63
|
+
return ctx.store.tx((t) => openSessionIn(ctx, t, id, body, access, options));
|
|
198
64
|
}
|
|
199
65
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* gap is named in one `409 environment_unsuitable`.
|
|
66
|
+
* `putSession`'s work in transaction `t`: also how a trigger's first run opens the session it
|
|
67
|
+
* names (track T4), in the run's transaction.
|
|
203
68
|
*/
|
|
204
|
-
async function
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
missing.push("pod");
|
|
214
|
-
if (requires.secrets?.length) {
|
|
215
|
-
const vault = environment === undefined ? undefined : await t.vaultOfEnvironment(environment.id);
|
|
216
|
-
const held = new Set(vault ? (await t.credentialsForVault(vault.id)).map((row) => row.name) : []);
|
|
217
|
-
for (const name of requires.secrets)
|
|
218
|
-
if (!held.has(name))
|
|
219
|
-
missing.push(`secret:${name}`);
|
|
69
|
+
export async function openSessionIn(ctx, t, id, body, access, options = {}) {
|
|
70
|
+
const opaque = access !== undefined;
|
|
71
|
+
const prior = await t.lockSession(id);
|
|
72
|
+
if (opaque && prior && (prior.ownerUserId !== access.owner || !reachesAgent(access, prior.agentId)))
|
|
73
|
+
fail(404, "Session not found");
|
|
74
|
+
if (prior && options.createOnly) {
|
|
75
|
+
if (prior.ownerUserId !== body.ownerUserId || prior.agentId !== body.agent)
|
|
76
|
+
fail(404, "Session not found");
|
|
77
|
+
return prior;
|
|
220
78
|
}
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
79
|
+
if (prior) {
|
|
80
|
+
if (sessionIdentity(prior.creation) !== sessionIdentity(body))
|
|
81
|
+
fail(409, "Session already exists with different creation parameters");
|
|
82
|
+
return prior;
|
|
83
|
+
}
|
|
84
|
+
const agent = await openAgent(t, body.agent, {
|
|
85
|
+
...(options.agentGrants === undefined ? {} : { grants: options.agentGrants }),
|
|
86
|
+
ownerUserId: body.ownerUserId,
|
|
87
|
+
opaque,
|
|
88
|
+
});
|
|
89
|
+
// The version the Agent runs, both sections (T3): its loop manifest, harness and sandbox spec.
|
|
90
|
+
const { pin } = await pinOf(t, agent);
|
|
91
|
+
await checkSkillLimit(t, pin.manifest, agent);
|
|
92
|
+
const config = await readSandboxConfig(t);
|
|
93
|
+
// Placement (D38, D52): where this session's harness may run, decided now and kept.
|
|
94
|
+
checkPlacement(config, agent.kind, pin.harness);
|
|
95
|
+
if (agent.kind === "pod")
|
|
96
|
+
await requirePods(ctx.pods, `Agent ${agent.id}`);
|
|
97
|
+
const created = {
|
|
98
|
+
id,
|
|
99
|
+
agentId: agent.id,
|
|
100
|
+
ownerUserId: body.ownerUserId,
|
|
101
|
+
manifest: pin.manifest,
|
|
102
|
+
manifestHash: pin.manifestHash,
|
|
103
|
+
definition: { ...pin.definition },
|
|
104
|
+
...(pin.loop === undefined ? {} : { loop: pin.loop }),
|
|
105
|
+
info: body.info,
|
|
106
|
+
status: "idle",
|
|
107
|
+
activeTurnId: null,
|
|
108
|
+
creation: body,
|
|
109
|
+
harness: pin.harness,
|
|
110
|
+
environmentId: agent.id,
|
|
111
|
+
environmentVersion: agent.version,
|
|
112
|
+
...(pin.sandbox === undefined ? {} : { sandbox: pin.sandbox }),
|
|
113
|
+
};
|
|
114
|
+
await t.put("sessions", id, created);
|
|
115
|
+
await recordAttachment(t, id, agent.id);
|
|
116
|
+
return created;
|
|
225
117
|
}
|
|
226
118
|
/**
|
|
227
|
-
*
|
|
228
|
-
* `
|
|
119
|
+
* Refuses a session whose Agent's manifest carries a skill larger than the Agent allows now: its
|
|
120
|
+
* manifest's `limits.skills.totalBytes`, else the Tenant's, never above the Tenant's, which may
|
|
121
|
+
* have been lowered since the manifest was saved. `413 limit_exceeded`, with each skill and its
|
|
122
|
+
* size in `details.skills`.
|
|
229
123
|
*/
|
|
230
|
-
function
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return { manifest: pinned.manifest, manifestHash: pinned.manifestHash };
|
|
237
|
-
}
|
|
238
|
-
/** The manifest a session with a sandbox pins: the definition with the sandbox in its `runtime` block. */
|
|
239
|
-
function pin(definition, spec) {
|
|
240
|
-
// A workflow's manifest stays as registered: its agents inherit the sandbox when they start.
|
|
241
|
-
if (isWorkflowManifest(definition.manifest))
|
|
242
|
-
return {};
|
|
243
|
-
const sandboxed = withSandbox(definition.manifest, spec);
|
|
244
|
-
if (!sandboxed.ok)
|
|
245
|
-
return fail(400, sandboxed.message);
|
|
246
|
-
return { manifest: sandboxed.manifest, manifestHash: sandboxed.manifestHash };
|
|
124
|
+
async function checkSkillLimit(t, manifest, agent) {
|
|
125
|
+
const limitBytes = limitsInForce(await readTenantLimits(t), agent.applied.limits).skills.totalBytes;
|
|
126
|
+
const { oversized } = await definitionFileIssues(t, manifest, limitBytes);
|
|
127
|
+
if (oversized.length === 0)
|
|
128
|
+
return;
|
|
129
|
+
fail(413, `Agent ${agent.id} allows a skill's files at most ${limitBytes} bytes together, and its manifest carries ${oversized.map((skill) => `'${skill.name}' (${skill.bytes})`).join(", ")}.`, { code: "limit_exceeded", details: { limitBytes, skills: oversized } });
|
|
247
130
|
}
|
|
248
131
|
/** The session resource returned by `GET`/`PUT /v1/sessions/:id`. */
|
|
249
132
|
export async function sessionView(t, s) {
|
|
@@ -267,14 +150,11 @@ export async function sessionView(t, s) {
|
|
|
267
150
|
id: s.id,
|
|
268
151
|
agentId: s.agentId,
|
|
269
152
|
ownerUserId: s.ownerUserId,
|
|
153
|
+
manifest: s.definition ?? null,
|
|
270
154
|
manifestHash: s.manifestHash,
|
|
271
|
-
...(s.definitionHash === undefined ? {} : { definitionHash: s.definitionHash }),
|
|
272
|
-
implementationVersion: s.implementationVersion,
|
|
273
155
|
status: s.status,
|
|
274
156
|
activeTurnId: s.activeTurnId,
|
|
275
|
-
|
|
276
|
-
? null
|
|
277
|
-
: { id: s.environmentId, version: s.environmentVersion ?? 1 },
|
|
157
|
+
queuedMessages: await t.countQueuedMessages(s.id),
|
|
278
158
|
harness: harnessOf(s),
|
|
279
159
|
...(s.closedReason === undefined ? {} : { closedReason: s.closedReason }),
|
|
280
160
|
mcpSnapshot: s.mcpSnapshot ?? null,
|
|
@@ -48,7 +48,7 @@ export declare class SigningKeys {
|
|
|
48
48
|
/**
|
|
49
49
|
* Rotates: previous → revoked, current → previous, standby → current, new standby. Refused
|
|
50
50
|
* with 409 while the previous key may still verify live tokens (retired less than the
|
|
51
|
-
* longest token lifetime, `maxTtlSeconds` or `
|
|
51
|
+
* longest token lifetime, `maxTtlSeconds` or `keys.tokenTtlMaxSeconds`, plus a minute ago), unless
|
|
52
52
|
* `force`.
|
|
53
53
|
*/
|
|
54
54
|
rotate(t: Tx, kek: Buffer, maxTtlSeconds: number, force: boolean): Promise<SigningKeyRow[]>;
|
|
@@ -15,12 +15,10 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { exportJWK, exportPKCS8, generateKeyPair, importJWK, importPKCS8, } from "jose";
|
|
17
17
|
import { newSigningKeyId, SIGNING_KEY_ID_PATTERN, } from "@nylorun/core/compatibility";
|
|
18
|
-
import { TOKEN_TTL_MAX_SECONDS } from "@nylorun/core/contracts";
|
|
19
18
|
import { decryptSecret, encryptSecret } from "../vault/crypto.js";
|
|
20
19
|
import { fail } from "./http.js";
|
|
20
|
+
import { hostTuning } from "../tuning.js";
|
|
21
21
|
const ALG = "ES256";
|
|
22
|
-
/** Grace added to the longest token lifetime before a previous key may be revoked. */
|
|
23
|
-
const ROTATION_GRACE_MS = 60_000;
|
|
24
22
|
export class SigningKeys {
|
|
25
23
|
options;
|
|
26
24
|
publicKeys = new Map();
|
|
@@ -107,7 +105,7 @@ export class SigningKeys {
|
|
|
107
105
|
/**
|
|
108
106
|
* Rotates: previous → revoked, current → previous, standby → current, new standby. Refused
|
|
109
107
|
* with 409 while the previous key may still verify live tokens (retired less than the
|
|
110
|
-
* longest token lifetime, `maxTtlSeconds` or `
|
|
108
|
+
* longest token lifetime, `maxTtlSeconds` or `keys.tokenTtlMaxSeconds`, plus a minute ago), unless
|
|
111
109
|
* `force`.
|
|
112
110
|
*/
|
|
113
111
|
async rotate(t, kek, maxTtlSeconds, force) {
|
|
@@ -118,8 +116,9 @@ export class SigningKeys {
|
|
|
118
116
|
const [previous] = await t.signingKeys(["previous"]);
|
|
119
117
|
if (previous && !force) {
|
|
120
118
|
const retired = Date.parse(previous.retiredAt ?? previous.createdAt);
|
|
121
|
-
const longest = Math.max(maxTtlSeconds,
|
|
122
|
-
|
|
119
|
+
const longest = Math.max(maxTtlSeconds, hostTuning().keys.tokenTtlMaxSeconds);
|
|
120
|
+
// The grace added to the longest token lifetime before a previous key may be revoked.
|
|
121
|
+
const until = retired + longest * 1000 + hostTuning().tenant.signingKeyRotationGraceMs;
|
|
123
122
|
if (until > now.getTime())
|
|
124
123
|
fail(409, "The previous key may still verify live tokens", {
|
|
125
124
|
code: "request_rejected",
|
package/dist/tenant/status.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { FIXTURE_MODEL_SETTING, seedFixtureModel } from "./model-setting.js";
|
|
2
2
|
import { ENVIRONMENTS_CONFIG_SETTING, writeSandboxConfig } from "../sandbox/tenant-config.js";
|
|
3
|
+
import { hostTuning } from "../tuning.js";
|
|
3
4
|
/** The Tenant's harnesses, for its status and the Host's. */
|
|
4
5
|
export function harnessStatusOf(ctx) {
|
|
5
6
|
return { mode: ctx.mcp ? "in-process" : "remote", ...ctx.harness.status() };
|
|
6
7
|
}
|
|
7
|
-
/** How long status waits for the execution to list stuck invocations. */
|
|
8
|
-
const STUCK_TIMEOUT_MS = 5000;
|
|
9
8
|
/** `TenantStatus.execution`: paused and backing-off invocations, or why they are unknown. */
|
|
10
9
|
async function executionStatus(stuckInvocations) {
|
|
11
10
|
let timer;
|
|
@@ -13,7 +12,9 @@ async function executionStatus(stuckInvocations) {
|
|
|
13
12
|
const stuck = await Promise.race([
|
|
14
13
|
stuckInvocations(),
|
|
15
14
|
new Promise((_, reject) => {
|
|
16
|
-
timer = setTimeout(() => reject(new Error("Timed out listing stuck invocations")),
|
|
15
|
+
timer = setTimeout(() => reject(new Error("Timed out listing stuck invocations")),
|
|
16
|
+
// How long status waits for the execution to list stuck invocations.
|
|
17
|
+
hostTuning().tenant.statusTimeoutMs);
|
|
17
18
|
}),
|
|
18
19
|
]);
|
|
19
20
|
return {
|
|
@@ -46,9 +47,9 @@ async function executionStatus(stuckInvocations) {
|
|
|
46
47
|
/** Build `TenantStatusSchema` with secrets redacted (A14). */
|
|
47
48
|
export async function buildTenantStatus(ctx) {
|
|
48
49
|
const health = await ctx.store.health();
|
|
49
|
-
const { counts,
|
|
50
|
+
const { counts, rows } = await ctx.store.tx(async (t) => ({
|
|
50
51
|
counts: await t.counts(),
|
|
51
|
-
|
|
52
|
+
rows: await t.listEnvironments(),
|
|
52
53
|
}));
|
|
53
54
|
const [modelView, sandboxReport, execution, streams] = await Promise.all([
|
|
54
55
|
ctx.vault.getHostModel(),
|
|
@@ -56,11 +57,10 @@ export async function buildTenantStatus(ctx) {
|
|
|
56
57
|
ctx.stuckInvocations ? executionStatus(ctx.stuckInvocations) : undefined,
|
|
57
58
|
ctx.streamsStatus?.(),
|
|
58
59
|
]);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
]
|
|
60
|
+
// The Tenant's Agents; a pod Agent being deleted is none.
|
|
61
|
+
const agents = rows
|
|
62
|
+
.filter((row) => row.pod?.desired !== "deleted")
|
|
63
|
+
.map((row) => row.id)
|
|
64
64
|
.sort()
|
|
65
65
|
.map((agentId) => ({ agentId }));
|
|
66
66
|
return {
|
package/dist/tenant/streams.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { basinOf } from "../streams/basin.js";
|
|
2
2
|
import { createStreamRelay, } from "../streams/relay/core.js";
|
|
3
3
|
import { retry } from "../retry.js";
|
|
4
|
+
import { hostTuning } from "../tuning.js";
|
|
4
5
|
import { checkSessionStreams, currentBasin } from "./session-streams.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/** How long a retired basin stays for readers that have not moved yet. */
|
|
14
|
-
const RETIRE_GRACE_MS = 60_000;
|
|
6
|
+
/*
|
|
7
|
+
* Timings are the Host tuning's `streams` group (`tuning.ts`): `retry` for deletions and
|
|
8
|
+
* repairs, `basinRetryMaxMs` (the longest wait between two `ensureTenant` attempts while the
|
|
9
|
+
* basin is being repaired), `basinRepairCooldownMs` (a repair started within this long after the
|
|
10
|
+
* last one succeeded waits for the next failure), `feedCheckMs` (how often every session stream is
|
|
11
|
+
* checked against its session, the backstop for lost signals), `retireGraceMs` (how long a retired
|
|
12
|
+
* basin stays for readers that have not moved yet).
|
|
13
|
+
*/
|
|
15
14
|
const messageOf = (error) => error instanceof Error ? error.message : String(error);
|
|
16
15
|
/**
|
|
17
16
|
* Wires the Tenant to Durable Streams: reads its basin generation, checks the basin, starts
|
|
@@ -25,7 +24,7 @@ export async function wireStreams(ctx, options) {
|
|
|
25
24
|
const { store, streams, tenantId } = options;
|
|
26
25
|
const logger = ctx.config.logger;
|
|
27
26
|
const stop = new AbortController();
|
|
28
|
-
const graceMs = options.retireGraceMs ??
|
|
27
|
+
const graceMs = options.retireGraceMs ?? hostTuning().streams.retireGraceMs;
|
|
29
28
|
// Nothing is reported once the wiring stops: the Tenant (and its log directory) may be gone,
|
|
30
29
|
// and a throwing report in a detached loop would be an unhandled rejection.
|
|
31
30
|
const report = (what) => (error) => {
|
|
@@ -53,7 +52,7 @@ export async function wireStreams(ctx, options) {
|
|
|
53
52
|
});
|
|
54
53
|
relay?.start();
|
|
55
54
|
// Streams whose session was reset end on the `sessions.reset` signal; this catches lost ones.
|
|
56
|
-
const feedCheck = setInterval(() => void checkSessionStreams(ctx).catch(report("session stream check failed")),
|
|
55
|
+
const feedCheck = setInterval(() => void checkSessionStreams(ctx).catch(report("session stream check failed")), hostTuning().streams.feedCheckMs);
|
|
57
56
|
feedCheck.unref();
|
|
58
57
|
const retiring = new Set();
|
|
59
58
|
const timers = new Set();
|
|
@@ -94,9 +93,8 @@ export async function wireStreams(ctx, options) {
|
|
|
94
93
|
async function deleteRetired(generation) {
|
|
95
94
|
try {
|
|
96
95
|
await retry(() => streams.deleteTenant(basinOf(tenantId, generation)), {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
attempts: 5,
|
|
96
|
+
...hostTuning().streams.retry,
|
|
97
|
+
attempts: hostTuning().streams.retireAttempts,
|
|
100
98
|
});
|
|
101
99
|
await store.tx((t) => t.forgetRetiredGeneration(generation));
|
|
102
100
|
logger.info("retired stream basin deleted", { generation });
|
|
@@ -160,7 +158,7 @@ export async function streamsStatus(ctx, options = {}) {
|
|
|
160
158
|
const wiring = ctx.sessionStreams.wiring;
|
|
161
159
|
return {
|
|
162
160
|
reachable: wiring
|
|
163
|
-
? await probe(wiring.streams, options.probeTimeoutMs ??
|
|
161
|
+
? await probe(wiring.streams, options.probeTimeoutMs ?? hostTuning().streams.probeTimeoutMs)
|
|
164
162
|
: false,
|
|
165
163
|
basin: wiring?.basin() ?? { ready: false, failures: 0, lastError: null },
|
|
166
164
|
generation: ctx.sessionStreams.generation,
|
|
@@ -215,17 +213,17 @@ function basinKeeper(streams, basinKey, signal, onError) {
|
|
|
215
213
|
repair() {
|
|
216
214
|
if (repairing || signal.aborted)
|
|
217
215
|
return;
|
|
218
|
-
if (ready && readyFor === basinKey() && Date.now() - repairedAt <
|
|
216
|
+
if (ready && readyFor === basinKey() && Date.now() - repairedAt < hostTuning().streams.basinRepairCooldownMs)
|
|
219
217
|
return;
|
|
220
218
|
repairing = true;
|
|
221
219
|
ready = false;
|
|
222
220
|
void (async () => {
|
|
223
221
|
await retry(ensure, {
|
|
224
|
-
minMs:
|
|
225
|
-
maxMs:
|
|
222
|
+
minMs: hostTuning().streams.retry.minMs,
|
|
223
|
+
maxMs: hostTuning().streams.basinRetryMaxMs,
|
|
226
224
|
signal,
|
|
227
225
|
onError: (error) => {
|
|
228
|
-
if (failures === 1 || failures %
|
|
226
|
+
if (failures === 1 || failures % hostTuning().streams.basinLogEveryFailures === 0)
|
|
229
227
|
onError(error);
|
|
230
228
|
},
|
|
231
229
|
}).then(() => (repairedAt = Date.now()), () => undefined);
|
package/dist/tenant/sweep.d.ts
CHANGED
|
@@ -1,32 +1,12 @@
|
|
|
1
1
|
import type { PendingRequest } from "../store/types.js";
|
|
2
2
|
import type { TenantContext } from "./context.js";
|
|
3
|
-
/**
|
|
4
|
-
* How old an outbox row is before the sweep delivers it, unless its delivery after commit
|
|
5
|
-
* already failed (then it is due at once): longer than that delivery can take with its
|
|
6
|
-
* retries, so the sweep does not send again, and double the load on, an execution that is
|
|
7
|
-
* only slow. Sending one twice is harmless either way (the idempotency key).
|
|
8
|
-
*/
|
|
9
|
-
export declare const OUTBOX_GRACE_MS = 30000;
|
|
10
|
-
/**
|
|
11
|
-
* How often the orphan scan, and the stale pod sandbox check, run after the first pass of a
|
|
12
|
-
* Tenant opened on this process.
|
|
13
|
-
*/
|
|
14
|
-
export declare const ORPHAN_SCAN_MS = 60000;
|
|
15
|
-
/**
|
|
16
|
-
* How long one pass may spend draining the outbox, and paging through orphaned sessions.
|
|
17
|
-
* A backlog is worked off over several passes rather than holding one (and with it the
|
|
18
|
-
* Tenant's sweep object in the execution) for long.
|
|
19
|
-
*/
|
|
20
|
-
export declare const DRAIN_BUDGET_MS = 2000;
|
|
21
3
|
export declare function sweep(ctx: TenantContext): Promise<void>;
|
|
22
|
-
/** Failed deliveries after which the sweep parks an outbox row (`Tx.failOutbox`). */
|
|
23
|
-
export declare const MAX_OUTBOX_ATTEMPTS = 10;
|
|
24
4
|
/**
|
|
25
5
|
* Deliver the outbox rows that are due (`Tx.pendingOutbox`: older than `graceMs`, or whose
|
|
26
6
|
* delivery failed), oldest first, batch after batch until none is left or `budgetMs` is
|
|
27
7
|
* spent, and delete the delivered ones. Each row is delivered on its own: one that fails
|
|
28
8
|
* (Restate refuses it, or a Runtime that does not know a wake's reason) is tried again later,
|
|
29
|
-
* with backoff, so it never holds back the rows behind it, and after `
|
|
9
|
+
* with backoff, so it never holds back the rows behind it, and after `sweep.outboxAttempts`
|
|
30
10
|
* failures it is parked: logged once, at error, and kept in the outbox for an operator. A
|
|
31
11
|
* parked wake's session is still re-woken by the orphan scan while it is runnable, and a
|
|
32
12
|
* parked sandbox signal's pod by the stale pod check. A row the Tenant declines (it is
|