@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
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ModelUsageQuerySchema, PutModelBudgetsRequestSchema, PutToolPolicyRequestSchema, PutModelInputsRequestSchema, PutHostModelRequestSchema, PutTenantEnvironmentsRequestSchema, ResetTenantRequestSchema, SeedTenantConfigRequestSchema, SelectHostModelRequestSchema, } from "@nylorun/core/contracts";
|
|
3
|
-
import { HostModelCatalog, HostModelView, ListProvidersResponse, ModelBudgets, ModelInputsView, ModelUsageTotals, PutModelBudgetsRequest, PutToolPolicyRequest, PutModelInputsRequest, ToolPolicy, PutHostModelRequest, PutTenantEnvironmentsRequest, ResetTenantRequest, ResetTenantResponse, SeedTenantConfigRequest, SeedTenantConfigResponse, SelectHostModelRequest, TenantSandboxView, TenantStatus, } from "../../components.js";
|
|
2
|
+
import { ModelUsageQuerySchema, PutModelBudgetsRequestSchema, PutToolPolicyRequestSchema, PutModelInputsRequestSchema, PutHostModelRequestSchema, PutTenantEnvironmentsRequestSchema, PutTenantLimitsRequestSchema, RUNTIME_LIMIT_CEILINGS, RUNTIME_LIMIT_DEFAULTS, ResetTenantRequestSchema, runtimeLimitIssues, runtimeLimitsOf, SeedTenantConfigRequestSchema, SelectHostModelRequestSchema, } from "@nylorun/core/contracts";
|
|
3
|
+
import { HostModelCatalog, HostModelView, ListProvidersResponse, ModelBudgets, ModelInputsView, ModelUsageTotals, PutModelBudgetsRequest, PutToolPolicyRequest, PutModelInputsRequest, ToolPolicy, PutHostModelRequest, PutTenantEnvironmentsRequest, PutTenantLimitsRequest, ResetTenantRequest, ResetTenantResponse, SeedTenantConfigRequest, SeedTenantConfigResponse, SelectHostModelRequest, TenantLimitsView, TenantSandboxView, TenantStatus, } from "../../components.js";
|
|
4
|
+
import { readRuntimeLimits, writeLimitsConfig } from "../../../tenant/runtime-limits.js";
|
|
4
5
|
import { periodStart } from "../../../gates/meter.js";
|
|
5
|
-
import { readToolPolicy, TOOL_POLICY_SETTING } from "../../../gates/policy.js";
|
|
6
|
+
import { readToolPolicy, TOOL_POLICY_SETTING, ToolPolicyUnreadable } from "../../../gates/policy.js";
|
|
6
7
|
import { addableInputs, capabilitiesOf, inputsError } from "../../../model/capabilities.js";
|
|
7
8
|
import { catalogModel, hostModelCatalog } from "../../../model/catalog.js";
|
|
8
9
|
import { sandboxConfigErrors } from "../../../sandbox/resolve.js";
|
|
@@ -17,9 +18,15 @@ import { tenantReset, streamsStatus, } from "../../../tenant/streams.js";
|
|
|
17
18
|
import { readJson } from "../body.js";
|
|
18
19
|
import { pathSegments, tenantRoute } from "../define.js";
|
|
19
20
|
import { jsonResponse } from "../respond.js";
|
|
20
|
-
import { rearmPodTimers } from "../../../tenant/
|
|
21
|
+
import { rearmPodTimers } from "../../../tenant/agents.js";
|
|
22
|
+
import { hostTuning } from "../../../tuning.js";
|
|
23
|
+
import { budgetIssues, toolPolicyIssues } from "../../../tenant/limits.js";
|
|
21
24
|
/** Every Management API route (`/v1/tenant/*`): a management key, acting as itself (protocol 8). */
|
|
22
25
|
const MANAGEMENT = { credentials: ["management"], scopes: "never" };
|
|
26
|
+
/** Each Runtime limit's default and ceiling, for the limits routes' descriptions. */
|
|
27
|
+
const LIMITS_TABLE = `Defaults and ceilings: ${Object.entries(RUNTIME_LIMIT_CEILINGS)
|
|
28
|
+
.map(([name, ceiling]) => `\`${name}\` ${RUNTIME_LIMIT_DEFAULTS[name]} ${ceiling.unit}, at most ${ceiling.value} (${ceiling.why})`)
|
|
29
|
+
.join("; ")}.`;
|
|
23
30
|
const json = (schema, description) => ({
|
|
24
31
|
description,
|
|
25
32
|
content: { "application/json": { schema } },
|
|
@@ -30,7 +37,7 @@ const body = (schema) => ({
|
|
|
30
37
|
});
|
|
31
38
|
const budgetRow = (budget, updatedAt) => ({
|
|
32
39
|
scope: budget.scope,
|
|
33
|
-
scopeId: budget.scope === "
|
|
40
|
+
scopeId: budget.scope === "manifest" ? budget.id : "*",
|
|
34
41
|
period: budget.period ?? null,
|
|
35
42
|
limitUsd: budget.limitUsd ?? null,
|
|
36
43
|
limitTokens: budget.limitTokens ?? null,
|
|
@@ -38,7 +45,7 @@ const budgetRow = (budget, updatedAt) => ({
|
|
|
38
45
|
});
|
|
39
46
|
const budgetView = (row) => ({
|
|
40
47
|
scope: row.scope,
|
|
41
|
-
...(row.scope === "
|
|
48
|
+
...(row.scope === "manifest" ? { id: row.scopeId } : {}),
|
|
42
49
|
...(row.period ? { period: row.period } : {}),
|
|
43
50
|
...(row.limitUsd !== null ? { limitUsd: row.limitUsd } : {}),
|
|
44
51
|
...(row.limitTokens !== null ? { limitTokens: row.limitTokens } : {}),
|
|
@@ -94,7 +101,7 @@ export function tenantRoutes(api) {
|
|
|
94
101
|
vault,
|
|
95
102
|
sandbox: ctx.sandbox,
|
|
96
103
|
closing: ctx.closing || ctx.closed,
|
|
97
|
-
modelConfigured:
|
|
104
|
+
modelConfigured: ctx.scriptedModel ||
|
|
98
105
|
(await ctx.store.tx((t) => usesFixtureModel(t))) ||
|
|
99
106
|
(await vault.getHostModel()).configured,
|
|
100
107
|
...(ctx.stuckInvocations ? { stuckInvocations: ctx.stuckInvocations } : {}),
|
|
@@ -107,16 +114,16 @@ export function tenantRoutes(api) {
|
|
|
107
114
|
path: "/v1/tenant/reset",
|
|
108
115
|
tags: ["Tenant"],
|
|
109
116
|
summary: "Reset the Tenant",
|
|
110
|
-
description: "Deletes its sessions, its
|
|
117
|
+
description: "Deletes its sessions, its Agents (with their vaults), or both, after draining or cancelling the turns in progress. The Tenant stays open.",
|
|
111
118
|
request: { body: body(ResetTenantRequest) },
|
|
112
119
|
responses: { 200: json(ResetTenantResponse, "Reset") },
|
|
113
120
|
}, async (c) => {
|
|
114
121
|
const ctx = c.env.tenant;
|
|
115
|
-
const request = ResetTenantRequestSchema.parse(await readJson(c
|
|
116
|
-
await drain(ctx, request.activeWork,
|
|
122
|
+
const request = ResetTenantRequestSchema.parse(await readJson(c));
|
|
123
|
+
await drain(ctx, request.activeWork, hostTuning().tenant.drainTimeoutMs);
|
|
117
124
|
// A sessions reset moves the Tenant to a new basin generation, so a session created
|
|
118
125
|
// again with the same id, during or after the reset, starts in an empty basin at 0.
|
|
119
|
-
const sessionsReset = request.scope !== "
|
|
126
|
+
const sessionsReset = request.scope !== "agents";
|
|
120
127
|
await resetTenant({
|
|
121
128
|
store: ctx.store,
|
|
122
129
|
sandbox: ctx.sandbox,
|
|
@@ -143,7 +150,7 @@ export function tenantRoutes(api) {
|
|
|
143
150
|
responses: { 200: json(SeedTenantConfigResponse, "What was set, and what was kept") },
|
|
144
151
|
}, async (c) => {
|
|
145
152
|
const ctx = c.env.tenant;
|
|
146
|
-
const request = SeedTenantConfigRequestSchema.parse(await readJson(c
|
|
153
|
+
const request = SeedTenantConfigRequestSchema.parse(await readJson(c));
|
|
147
154
|
return jsonResponse(200, await seedTenantConfig({ store: ctx.store, vault: ctx.vault, keys: ctx.keys }, request));
|
|
148
155
|
});
|
|
149
156
|
tenantRoute(api, MANAGEMENT, {
|
|
@@ -162,11 +169,11 @@ export function tenantRoutes(api) {
|
|
|
162
169
|
path: "/v1/tenant/models/inputs",
|
|
163
170
|
tags: ["Tenant"],
|
|
164
171
|
summary: "Set what a catalog model reads",
|
|
165
|
-
description: "Replaces the inputs the operator added to one catalog model (Tenant setting `model.inputs`): only those in its `addableInputs`, which its provider API carries. Its catalog's own inputs always stay; an empty list removes the additions.
|
|
172
|
+
description: "Replaces the inputs the operator added to one catalog model (Tenant setting `model.inputs`): only those in its `addableInputs`, which its provider API carries. Its catalog's own inputs always stay; an empty list removes the additions. The agent's harness learns them in `turn.start.model` and decides how each file reaches the model. A custom endpoint sets `settings.inputs` on `PUT /v1/tenant/model` instead.",
|
|
166
173
|
request: { body: body(PutModelInputsRequest) },
|
|
167
174
|
responses: { 200: json(ModelInputsView, "What the model reads now") },
|
|
168
175
|
}, async (c) => {
|
|
169
|
-
const { provider, model, inputs } = PutModelInputsRequestSchema.parse(await readJson(c
|
|
176
|
+
const { provider, model, inputs } = PutModelInputsRequestSchema.parse(await readJson(c));
|
|
170
177
|
if (provider === "custom")
|
|
171
178
|
fail(400, "A custom endpoint's inputs are its settings: set settings.inputs on PUT /v1/tenant/model.");
|
|
172
179
|
const found = catalogModel(provider, model);
|
|
@@ -183,24 +190,51 @@ export function tenantRoutes(api) {
|
|
|
183
190
|
inputs: capabilitiesOf(found, added).inputs,
|
|
184
191
|
});
|
|
185
192
|
});
|
|
193
|
+
tenantRoute(api, MANAGEMENT, {
|
|
194
|
+
method: "get",
|
|
195
|
+
path: "/v1/tenant/limits",
|
|
196
|
+
tags: ["Tenant"],
|
|
197
|
+
summary: "Get the Tenant's Runtime limits",
|
|
198
|
+
description: `The sizes, counts and deadlines the Runtime holds what crosses it to: the Tenant's (Tenant setting \`limits.config\`), with the default for each it leaves out. Harnesses get the ones they must respect in \`turn.start.limits\` (record entry, model call, model file, tool answer, custom harness state, Harness API chunk, folder entries). ${LIMITS_TABLE}`,
|
|
199
|
+
responses: { 200: json(TenantLimitsView, "The limits in force") },
|
|
200
|
+
}, async (c) => jsonResponse(200, { limits: await c.env.tenant.store.tx((t) => readRuntimeLimits(t)) }));
|
|
201
|
+
tenantRoute(api, MANAGEMENT, {
|
|
202
|
+
method: "put",
|
|
203
|
+
path: "/v1/tenant/limits",
|
|
204
|
+
tags: ["Tenant"],
|
|
205
|
+
summary: "Set the Tenant's Runtime limits",
|
|
206
|
+
description: `Replaces the Tenant's Runtime limits: a limit left out takes its default. A limit above its ceiling, which a dependency sets, is \`400\` naming the ceiling, and nothing is written. Each is read where it is checked, so a new value holds for the next request, write, call or segment. ${LIMITS_TABLE}`,
|
|
207
|
+
request: { body: body(PutTenantLimitsRequest) },
|
|
208
|
+
responses: {
|
|
209
|
+
200: json(TenantLimitsView, "The limits now in force"),
|
|
210
|
+
400: { description: "A limit above its ceiling" },
|
|
211
|
+
},
|
|
212
|
+
}, async (c) => {
|
|
213
|
+
const { requestId: _requestId, ...config } = PutTenantLimitsRequestSchema.parse(await readJson(c));
|
|
214
|
+
const issues = runtimeLimitIssues(config.limits);
|
|
215
|
+
if (issues.length > 0)
|
|
216
|
+
fail(400, issues.join(" "));
|
|
217
|
+
await c.env.tenant.store.tx((t) => writeLimitsConfig(t, config));
|
|
218
|
+
return jsonResponse(200, { limits: runtimeLimitsOf(config.limits) });
|
|
219
|
+
});
|
|
186
220
|
tenantRoute(api, MANAGEMENT, {
|
|
187
221
|
method: "get",
|
|
188
222
|
path: "/v1/tenant/sandbox",
|
|
189
223
|
tags: ["Tenant"],
|
|
190
|
-
summary: "Get the Tenant's sandbox backend and
|
|
224
|
+
summary: "Get the Tenant's sandbox backend and Agent compute settings",
|
|
191
225
|
responses: { 200: json(TenantSandboxView, "The backend in use and the configuration in force") },
|
|
192
226
|
}, async (c) => jsonResponse(200, await sandboxView(c.env.tenant)));
|
|
193
227
|
tenantRoute(api, MANAGEMENT, {
|
|
194
228
|
method: "put",
|
|
195
229
|
path: "/v1/tenant/sandbox",
|
|
196
230
|
tags: ["Tenant"],
|
|
197
|
-
summary: "Set the Tenant's
|
|
198
|
-
description: "The limits every
|
|
231
|
+
summary: "Set the Tenant's Agent compute settings",
|
|
232
|
+
description: "The limits every Agent's runtime must fit, the pods' stop grace and where harnesses may run (Tenant setting `environments.config`).",
|
|
199
233
|
request: { body: body(PutTenantEnvironmentsRequest) },
|
|
200
234
|
responses: { 200: json(TenantSandboxView, "The configuration now in force") },
|
|
201
235
|
}, async (c) => {
|
|
202
236
|
const ctx = c.env.tenant;
|
|
203
|
-
const { requestId: _requestId, ...config } = PutTenantEnvironmentsRequestSchema.parse(await readJson(c
|
|
237
|
+
const { requestId: _requestId, ...config } = PutTenantEnvironmentsRequestSchema.parse(await readJson(c));
|
|
204
238
|
const errors = sandboxConfigErrors(effectiveSandboxConfig(config));
|
|
205
239
|
if (errors.length > 0)
|
|
206
240
|
fail(400, errors.join(" "));
|
|
@@ -257,9 +291,12 @@ export function tenantRoutes(api) {
|
|
|
257
291
|
request: { body: body(PutModelBudgetsRequest) },
|
|
258
292
|
responses: { 200: json(ModelBudgets, "The budgets now in force") },
|
|
259
293
|
}, async (c) => {
|
|
260
|
-
const { budgets } = PutModelBudgetsRequestSchema.parse(await readJson(c
|
|
294
|
+
const { budgets } = PutModelBudgetsRequestSchema.parse(await readJson(c));
|
|
261
295
|
const updatedAt = new Date().toISOString();
|
|
262
296
|
const rows = await c.env.tenant.store.tx(async (t) => {
|
|
297
|
+
const issues = budgetIssues(budgets, await readRuntimeLimits(t));
|
|
298
|
+
if (issues.length > 0)
|
|
299
|
+
fail(400, issues.join(" "));
|
|
263
300
|
await t.putModelBudgets(budgets.map((budget) => budgetRow(budget, updatedAt)));
|
|
264
301
|
return t.listModelBudgets();
|
|
265
302
|
});
|
|
@@ -271,7 +308,18 @@ export function tenantRoutes(api) {
|
|
|
271
308
|
tags: ["Tenant"],
|
|
272
309
|
summary: "Get the Tenant's tool policy",
|
|
273
310
|
responses: { 200: json(ToolPolicy, "The rules the Tool Gate applies to every MCP and HTTP tool call") },
|
|
274
|
-
}, async (c) =>
|
|
311
|
+
}, async (c) => {
|
|
312
|
+
try {
|
|
313
|
+
return jsonResponse(200, await c.env.tenant.store.tx((t) => readToolPolicy(t)));
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
// A stored rule this Runtime refuses (an MCP tool named `server__tool`, protocol 15):
|
|
317
|
+
// every call is denied until the policy is set again.
|
|
318
|
+
if (error instanceof ToolPolicyUnreadable)
|
|
319
|
+
return fail(409, error.message, { code: "request_rejected" });
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
275
323
|
tenantRoute(api, MANAGEMENT, {
|
|
276
324
|
method: "put",
|
|
277
325
|
path: "/v1/tenant/tool-policy",
|
|
@@ -281,9 +329,14 @@ export function tenantRoutes(api) {
|
|
|
281
329
|
request: { body: body(PutToolPolicyRequest) },
|
|
282
330
|
responses: { 200: json(ToolPolicy, "The policy now in force") },
|
|
283
331
|
}, async (c) => {
|
|
284
|
-
const { rules } = PutToolPolicyRequestSchema.parse(await readJson(c
|
|
332
|
+
const { rules } = PutToolPolicyRequestSchema.parse(await readJson(c));
|
|
285
333
|
const policy = { rules, updatedAt: new Date().toISOString() };
|
|
286
|
-
await c.env.tenant.store.tx((t) =>
|
|
334
|
+
await c.env.tenant.store.tx(async (t) => {
|
|
335
|
+
const issues = toolPolicyIssues(rules, await readRuntimeLimits(t));
|
|
336
|
+
if (issues.length > 0)
|
|
337
|
+
fail(400, issues.join(" "));
|
|
338
|
+
await t.putSetting(TOOL_POLICY_SETTING, JSON.stringify(policy));
|
|
339
|
+
});
|
|
287
340
|
return jsonResponse(200, policy);
|
|
288
341
|
});
|
|
289
342
|
tenantRoute(api, MANAGEMENT, {
|
|
@@ -309,7 +362,7 @@ export function tenantRoutes(api) {
|
|
|
309
362
|
responses: { 200: json(HostModelView, "The model now in force") },
|
|
310
363
|
}, async (c) => {
|
|
311
364
|
const ctx = c.env.tenant;
|
|
312
|
-
return jsonResponse(200, await ctx.keys.putHostModel(PutHostModelRequestSchema.parse(await readJson(c
|
|
365
|
+
return jsonResponse(200, await ctx.keys.putHostModel(PutHostModelRequestSchema.parse(await readJson(c))));
|
|
313
366
|
});
|
|
314
367
|
tenantRoute(api, MANAGEMENT, {
|
|
315
368
|
method: "put",
|
|
@@ -320,6 +373,6 @@ export function tenantRoutes(api) {
|
|
|
320
373
|
responses: { 200: json(HostModelView, "The model now in force") },
|
|
321
374
|
}, async (c) => {
|
|
322
375
|
const ctx = c.env.tenant;
|
|
323
|
-
return jsonResponse(200, await ctx.keys.selectHostModel(SelectHostModelRequestSchema.parse(await readJson(c
|
|
376
|
+
return jsonResponse(200, await ctx.keys.selectHostModel(SelectHostModelRequestSchema.parse(await readJson(c))));
|
|
324
377
|
});
|
|
325
378
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Agent's triggers and their runs (track T4, D74): read them, pause and resume one, run one now
|
|
3
|
+
* (keyed by `Idempotency-Key`), and page the runs; make a webhook trigger's signing secret, and
|
|
4
|
+
* take a sender's delivery at its endpoint (D75), an anonymous, unversioned route. What a trigger is lives in the Agent's manifest
|
|
5
|
+
* (`runtime.triggers`); these routes change only what the Agent owns, its status.
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
8
|
+
import type { TenantEnv } from "../app.js";
|
|
9
|
+
export declare function triggerRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
10
|
+
export declare function webhookRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isAgentId } from "@nylorun/core/contracts";
|
|
3
|
+
import { RunTriggerResponse, TriggerList, TriggerRunPage, WebhookAcceptedResponse, WebhookSecretResponse, } from "../../components.js";
|
|
4
|
+
import { assertReaches } from "../../../tenant/agents.js";
|
|
5
|
+
import { fail } from "../../../tenant/http.js";
|
|
6
|
+
import { listRuns, listTriggers, receiveWebhook, rotateWebhookSecret, runTriggerNow, setTriggerStatus, } from "../../../tenant/triggers.js";
|
|
7
|
+
import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
|
|
8
|
+
import { readBytes } from "../body.js";
|
|
9
|
+
import { tenantRoute } from "../define.js";
|
|
10
|
+
import { pageQuery, pageSize, parseQuery } from "./reads.js";
|
|
11
|
+
import { jsonResponse } from "../respond.js";
|
|
12
|
+
const READ = {
|
|
13
|
+
credentials: ["application", "subject", "token"],
|
|
14
|
+
scopes: ["sessions:own", "agents:read", "agents:write"],
|
|
15
|
+
};
|
|
16
|
+
const WRITE = {
|
|
17
|
+
credentials: ["application", "subject", "token"],
|
|
18
|
+
scopes: ["agents:write"],
|
|
19
|
+
};
|
|
20
|
+
const json = (schema, description) => ({
|
|
21
|
+
description,
|
|
22
|
+
content: { "application/json": { schema } },
|
|
23
|
+
});
|
|
24
|
+
const agentId = z.object({
|
|
25
|
+
agentId: z.string().meta({ description: "The Agent id, percent-encoded" }),
|
|
26
|
+
});
|
|
27
|
+
const triggerPath = agentId.extend({
|
|
28
|
+
triggerId: z.string().meta({ description: "The trigger's id in the manifest's `runtime.triggers`" }),
|
|
29
|
+
});
|
|
30
|
+
function idOf(value) {
|
|
31
|
+
if (!isAgentId(value))
|
|
32
|
+
return fail(400, "An Agent id is up to 200 characters: /-separated segments of letters, digits, '.', '_' and '-'");
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
export function triggerRoutes(api) {
|
|
36
|
+
tenantRoute(api, READ, {
|
|
37
|
+
method: "get",
|
|
38
|
+
path: "/v1/agents/{agentId}/triggers",
|
|
39
|
+
tags: ["Triggers"],
|
|
40
|
+
summary: "List an Agent's triggers",
|
|
41
|
+
description: "Each trigger its manifest declares, with what the Agent holds of it: its status (`active`, `paused` with a reason, `completed` for an `at` that ran), when it runs next and last ran.",
|
|
42
|
+
request: { params: agentId },
|
|
43
|
+
responses: { 200: json(TriggerList, "The triggers") },
|
|
44
|
+
}, async (c) => {
|
|
45
|
+
const id = idOf(c.req.param("agentId"));
|
|
46
|
+
assertReaches(c.get("scope"), id);
|
|
47
|
+
return jsonResponse(200, await listTriggers(c.env.tenant, id, originOf(c.req.url)));
|
|
48
|
+
});
|
|
49
|
+
for (const action of ["pause", "resume"])
|
|
50
|
+
tenantRoute(api, WRITE, {
|
|
51
|
+
method: "post",
|
|
52
|
+
path: `/v1/agents/{agentId}/triggers/{triggerId}/${action}`,
|
|
53
|
+
tags: ["Triggers"],
|
|
54
|
+
summary: action === "pause" ? "Pause a trigger" : "Resume a trigger",
|
|
55
|
+
description: action === "pause"
|
|
56
|
+
? "It stops firing until it is resumed; a run already started or queued goes on."
|
|
57
|
+
: "It fires again from its next time after now; missed times are not run. An `at` whose time has passed is refused (`trigger_expired`).",
|
|
58
|
+
request: { params: triggerPath },
|
|
59
|
+
responses: {
|
|
60
|
+
200: json(TriggerList, "The Agent's triggers"),
|
|
61
|
+
409: { description: "An `at` whose time has passed (`trigger_expired`)" },
|
|
62
|
+
},
|
|
63
|
+
}, async (c) => {
|
|
64
|
+
const id = idOf(c.req.param("agentId"));
|
|
65
|
+
assertReaches(c.get("scope"), id);
|
|
66
|
+
return jsonResponse(200, await setTriggerStatus(c.env.tenant, id, c.req.param("triggerId"), action, originOf(c.req.url)));
|
|
67
|
+
});
|
|
68
|
+
tenantRoute(api, WRITE, {
|
|
69
|
+
method: "post",
|
|
70
|
+
path: "/v1/agents/{agentId}/triggers/{triggerId}/run",
|
|
71
|
+
tags: ["Triggers"],
|
|
72
|
+
summary: "Run a trigger now",
|
|
73
|
+
description: "Runs it once now, paused or not, as if it had fired: a turn on its session, or a queued message when a turn runs there. A retried request with the same `Idempotency-Key` answers the same run.",
|
|
74
|
+
request: {
|
|
75
|
+
params: triggerPath,
|
|
76
|
+
headers: z.object({ "Idempotency-Key": z.string().min(1).max(200) }),
|
|
77
|
+
},
|
|
78
|
+
responses: { 200: json(RunTriggerResponse, "The run") },
|
|
79
|
+
}, async (c) => {
|
|
80
|
+
const id = idOf(c.req.param("agentId"));
|
|
81
|
+
assertReaches(c.get("scope"), id);
|
|
82
|
+
const key = c.req.header("idempotency-key")?.trim();
|
|
83
|
+
if (!key || key.length > 200)
|
|
84
|
+
fail(400, "Idempotency-Key is required: 1-200 characters");
|
|
85
|
+
return jsonResponse(200, { run: await runTriggerNow(c.env.tenant, id, c.req.param("triggerId"), key) });
|
|
86
|
+
});
|
|
87
|
+
tenantRoute(api, READ, {
|
|
88
|
+
method: "get",
|
|
89
|
+
path: "/v1/agents/{agentId}/runs",
|
|
90
|
+
tags: ["Triggers"],
|
|
91
|
+
summary: "List an Agent's runs",
|
|
92
|
+
description: "Each time one of its triggers fired or was run by hand, newest first: when it was due, whether it was late, and what came of it (`started`, `queued`, `skipped` or `failed`, with a reason), with the session and turn.",
|
|
93
|
+
request: {
|
|
94
|
+
params: agentId,
|
|
95
|
+
query: pageQuery.extend({
|
|
96
|
+
triggerId: z.string().optional().meta({ description: "Only this trigger's runs" }),
|
|
97
|
+
}),
|
|
98
|
+
},
|
|
99
|
+
responses: { 200: json(TriggerRunPage, "A page of runs") },
|
|
100
|
+
}, async (c) => {
|
|
101
|
+
const id = idOf(c.req.param("agentId"));
|
|
102
|
+
assertReaches(c.get("scope"), id);
|
|
103
|
+
const triggerId = c.req.query("triggerId");
|
|
104
|
+
const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
|
|
105
|
+
return jsonResponse(200, await listRuns(c.env.tenant, id, {
|
|
106
|
+
...(triggerId ? { triggerId } : {}),
|
|
107
|
+
...(cursor ? { cursor } : {}),
|
|
108
|
+
limit: await pageSize(c.env.tenant, limit, { fallback: 50 }),
|
|
109
|
+
}));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** A delivery: no credential, no protocol header, any body; the endpoint id and the signature are the grant. */
|
|
113
|
+
const DELIVERY = {
|
|
114
|
+
credentials: ["application", "subject", "token"],
|
|
115
|
+
scopes: "any",
|
|
116
|
+
anonymous: true,
|
|
117
|
+
unversioned: true,
|
|
118
|
+
bytes: true,
|
|
119
|
+
};
|
|
120
|
+
export function webhookRoutes(api) {
|
|
121
|
+
tenantRoute(api, WRITE, {
|
|
122
|
+
method: "post",
|
|
123
|
+
path: "/v1/agents/{agentId}/triggers/{triggerId}/secret",
|
|
124
|
+
tags: ["Triggers"],
|
|
125
|
+
summary: "Make a webhook trigger's signing secret",
|
|
126
|
+
description: "A new Standard Webhooks secret (`whsec_…`) for a webhook trigger, shown this once; the one before stops working at once. Give it to the sender with the trigger's `webhookUrl`.",
|
|
127
|
+
request: { params: triggerPath },
|
|
128
|
+
responses: {
|
|
129
|
+
200: json(WebhookSecretResponse, "The secret, this once"),
|
|
130
|
+
400: { description: "Not a webhook trigger" },
|
|
131
|
+
},
|
|
132
|
+
}, async (c) => {
|
|
133
|
+
const id = idOf(c.req.param("agentId"));
|
|
134
|
+
assertReaches(c.get("scope"), id);
|
|
135
|
+
return jsonResponse(200, await rotateWebhookSecret(c.env.tenant, id, c.req.param("triggerId"), originOf(c.req.url)));
|
|
136
|
+
});
|
|
137
|
+
tenantRoute(api, DELIVERY, {
|
|
138
|
+
method: "post",
|
|
139
|
+
path: "/v1/webhooks/{endpointId}",
|
|
140
|
+
tags: ["Triggers"],
|
|
141
|
+
summary: "Deliver to a webhook trigger",
|
|
142
|
+
description: "A sender's delivery, signed with Standard Webhooks (`webhook-id`, `webhook-timestamp` within 5 minutes by default, `webhook-signature`): no credential and no `Nylorun-Protocol`. The body, any media type, at most the Runtime limit `webhookBodyBytes`, is read as bytes and verified before anything else. It runs the trigger once per `webhook-id`: a retry answers the first run. The body reaches the model as data under the trigger's prompt. Other senders (GitHub, Stripe, Slack) are relayed by an app.",
|
|
143
|
+
request: {
|
|
144
|
+
params: z.object({ endpointId: z.string().meta({ description: "The trigger's endpoint id, `wh_…`" }) }),
|
|
145
|
+
headers: z.object({
|
|
146
|
+
"webhook-id": z.string().optional().meta({ description: "The delivery's id; a retry sends the same" }),
|
|
147
|
+
"webhook-timestamp": z.string().optional().meta({ description: "Seconds since the epoch" }),
|
|
148
|
+
"webhook-signature": z.string().optional().meta({ description: "`v1,<base64>`, space-separated" }),
|
|
149
|
+
}),
|
|
150
|
+
body: {
|
|
151
|
+
required: true,
|
|
152
|
+
description: "The payload, of any media type",
|
|
153
|
+
content: { "*/*": { schema: z.string().meta({ format: "binary" }) } },
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
responses: {
|
|
157
|
+
202: json(WebhookAcceptedResponse, "The run it made: started, queued, skipped or failed"),
|
|
158
|
+
401: { description: "Not signed with the endpoint's secret, or a timestamp out of tolerance" },
|
|
159
|
+
404: { description: "No endpoint has this id" },
|
|
160
|
+
409: { description: "The trigger is paused (`trigger_paused`)" },
|
|
161
|
+
413: { description: "Over `webhookBodyBytes`" },
|
|
162
|
+
},
|
|
163
|
+
}, async (c) => {
|
|
164
|
+
const tenant = c.env.tenant;
|
|
165
|
+
const { webhookBodyBytes } = await tenant.store.tx((t) => readRuntimeLimits(t));
|
|
166
|
+
const body = await readBytes(c.req.raw, webhookBodyBytes, "webhookBodyBytes");
|
|
167
|
+
const header = (name) => c.req.header(name)?.trim() || undefined;
|
|
168
|
+
return jsonResponse(202, await receiveWebhook(tenant, c.req.param("endpointId"), {
|
|
169
|
+
id: header("webhook-id"),
|
|
170
|
+
timestamp: header("webhook-timestamp"),
|
|
171
|
+
signature: header("webhook-signature"),
|
|
172
|
+
contentType: header("content-type"),
|
|
173
|
+
body,
|
|
174
|
+
}));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/** The origin a request reached: where its webhook URLs live. */
|
|
178
|
+
function originOf(url) {
|
|
179
|
+
return new URL(url).origin;
|
|
180
|
+
}
|
|
@@ -11,13 +11,6 @@
|
|
|
11
11
|
import type { MessagePart } from "@nylorun/core/contracts";
|
|
12
12
|
import { type ArtifactAccess } from "../artifacts/service.js";
|
|
13
13
|
import type { TenantContext } from "../tenant/context.js";
|
|
14
|
-
/** The largest file a message may carry inline, decoded. */
|
|
15
|
-
export declare const INLINE_FILE_MAX_BYTES: number;
|
|
16
|
-
/**
|
|
17
|
-
* The request body of an endpoint that takes inline files: one file at the cap, base64-encoded
|
|
18
|
-
* (a third larger), and the rest of the request.
|
|
19
|
-
*/
|
|
20
|
-
export declare const INLINE_BODY_MAX_BYTES: number;
|
|
21
14
|
/** A file sent inline: its name, declared media type and base64 bytes. */
|
|
22
15
|
export interface InlineFile {
|
|
23
16
|
readonly name: string;
|
|
@@ -40,8 +33,9 @@ export declare function refuseUrl(): never;
|
|
|
40
33
|
/** A name for a file its client did not name: its place in the message and its type's extension. */
|
|
41
34
|
export declare function inlineFileName(mediaType: string, index: number): string;
|
|
42
35
|
/**
|
|
43
|
-
* Stores `file` as a new artifact of `sessionId`, within the
|
|
44
|
-
* artifact limits: `400` for bad base64 or a bad
|
|
36
|
+
* Stores `file` as a new artifact of `sessionId`, within the Tenant's Runtime limit
|
|
37
|
+
* `inlineFileBytes` (read for the file) and its artifact limits: `400` for bad base64 or a bad
|
|
38
|
+
* media type, `413 limit_exceeded` past a limit.
|
|
45
39
|
*/
|
|
46
40
|
export declare function storeInlineFile(ctx: TenantContext, sessionId: string, file: InlineFile, access: ArtifactAccess): Promise<{
|
|
47
41
|
artifactId: string;
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import { MAX_MESSAGE_PARTS } from "@nylorun/core/contracts";
|
|
2
1
|
import { commandKey } from "../core/flow-host.js";
|
|
3
|
-
import { extensionFor, normalizeContentType } from "
|
|
2
|
+
import { extensionFor, normalizeContentType } from "@nylorun/core/contracts";
|
|
4
3
|
import { deleteArtifact, uploadArtifact } from "../artifacts/service.js";
|
|
5
4
|
import { fail } from "../tenant/http.js";
|
|
6
|
-
|
|
7
|
-
export const INLINE_FILE_MAX_BYTES = 20 * 1024 * 1024;
|
|
8
|
-
/**
|
|
9
|
-
* The request body of an endpoint that takes inline files: one file at the cap, base64-encoded
|
|
10
|
-
* (a third larger), and the rest of the request.
|
|
11
|
-
*/
|
|
12
|
-
export const INLINE_BODY_MAX_BYTES = 28 * 1024 * 1024;
|
|
5
|
+
import { readRuntimeLimits } from "../tenant/runtime-limits.js";
|
|
13
6
|
const BASE64 = /^[A-Za-z0-9+/_-]*={0,2}$/;
|
|
14
7
|
/** The 400 for a file sent by URL. */
|
|
15
8
|
export function refuseUrl() {
|
|
@@ -23,26 +16,26 @@ export function inlineFileName(mediaType, index) {
|
|
|
23
16
|
return `file-${index + 1}${extension ? `.${extension}` : ""}`;
|
|
24
17
|
}
|
|
25
18
|
/**
|
|
26
|
-
* Stores `file` as a new artifact of `sessionId`, within the
|
|
27
|
-
* artifact limits: `400` for bad base64 or a bad
|
|
19
|
+
* Stores `file` as a new artifact of `sessionId`, within the Tenant's Runtime limit
|
|
20
|
+
* `inlineFileBytes` (read for the file) and its artifact limits: `400` for bad base64 or a bad
|
|
21
|
+
* media type, `413 limit_exceeded` past a limit.
|
|
28
22
|
*/
|
|
29
23
|
export async function storeInlineFile(ctx, sessionId, file, access) {
|
|
30
24
|
const data = file.data.replace(/\s+/gu, "");
|
|
31
25
|
if (!BASE64.test(data) || data.length % 4 === 1)
|
|
32
26
|
fail(400, `File "${file.name}" is not valid base64`, { code: "invalid_request" });
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
const { inlineFileBytes } = await ctx.store.tx((t) => readRuntimeLimits(t));
|
|
28
|
+
const tooLarge = () => fail(413, `A file sent inline may hold at most ${inlineFileBytes} bytes (the Runtime limit inlineFileBytes)`, {
|
|
29
|
+
code: "limit_exceeded",
|
|
30
|
+
details: { limitBytes: inlineFileBytes },
|
|
31
|
+
});
|
|
32
|
+
// Three bytes per four characters, before decoding a byte; padding may take up to two.
|
|
33
|
+
if (Math.floor((data.length * 3) / 4) > inlineFileBytes + 2)
|
|
34
|
+
tooLarge();
|
|
39
35
|
// Node's base64 decoder reads both alphabets.
|
|
40
36
|
const bytes = Buffer.from(data, "base64");
|
|
41
|
-
if (bytes.byteLength >
|
|
42
|
-
|
|
43
|
-
code: "limit_exceeded",
|
|
44
|
-
details: { limitBytes: INLINE_FILE_MAX_BYTES },
|
|
45
|
-
});
|
|
37
|
+
if (bytes.byteLength > inlineFileBytes)
|
|
38
|
+
tooLarge();
|
|
46
39
|
if (bytes.byteLength === 0)
|
|
47
40
|
fail(400, `File "${file.name}" is empty`, { code: "invalid_request" });
|
|
48
41
|
const contentType = normalizeContentType(file.mediaType) ??
|
|
@@ -73,8 +66,9 @@ export async function priorParts(ctx, sessionId, idempotencyKey) {
|
|
|
73
66
|
*/
|
|
74
67
|
export async function messageParts(ctx, sessionId, idempotencyKey, inbound, access) {
|
|
75
68
|
const parts = inbound.filter((part) => part.type !== "text" || part.text !== "");
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
const { messageParts: most } = await ctx.store.tx((t) => readRuntimeLimits(t));
|
|
70
|
+
if (parts.length > most)
|
|
71
|
+
fail(400, `A message may carry at most ${most} parts (the Runtime limit messageParts)`, { code: "invalid_request" });
|
|
78
72
|
const prior = parts.some((part) => part.type === "inline")
|
|
79
73
|
? (await priorParts(ctx, sessionId, idempotencyKey))?.filter((part) => part.type === "file")
|
|
80
74
|
: undefined;
|