@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
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
* workspace request it is serving acts for; a `sandbox.state` claim's record becomes the
|
|
17
17
|
* workspace's row in the `sandboxes` table.
|
|
18
18
|
*
|
|
19
|
+
* Protocol 15: a harness reads and writes its run's session's artifacts over the artifact seam
|
|
20
|
+
* (`artifact.read`, `artifact.write`, `./artifacts.ts`); a run's open uploads end with it.
|
|
21
|
+
*
|
|
19
22
|
* F7.2: a pod sandbox's engine connects as that sandbox's *host* (`HarnessPeer.host`, from its
|
|
20
23
|
* host token): it leases only runs whose session is attached to its sandbox (`RunOffer.pod`),
|
|
21
24
|
* serves only that sandbox's workspace (`workspace(..., { pod })`), and claims events only for
|
|
@@ -25,20 +28,24 @@
|
|
|
25
28
|
* `connection.lost`.
|
|
26
29
|
*/
|
|
27
30
|
import { randomUUID } from "node:crypto";
|
|
28
|
-
import { DEFAULT_HARNESS, HARNESS_API_VERSION, HARNESS_CLAIMS,
|
|
29
|
-
import { definitionFilesOf } from "@nylorun/core/contracts";
|
|
30
|
-
import { TOOL_CALL_TOOL, TOOL_SEARCH_TOOL, delegatesOf, } from "@nylorun/core/define";
|
|
31
|
+
import { DEFAULT_HARNESS, HARNESS_API_VERSION, HARNESS_CLAIMS, isHarnessId, HarnessApiError, } from "@nylorun/core/harness-api";
|
|
32
|
+
import { definitionFilesOf, limitExceededMessage } from "@nylorun/core/contracts";
|
|
31
33
|
import { isOwnershipLost } from "../store/ownership.js";
|
|
32
34
|
import { harnessOf, ownedSession } from "../tenant/context.js";
|
|
33
|
-
import {
|
|
34
|
-
import { contextWindowOf } from "../model/catalog.js";
|
|
35
|
+
import { fitSnapshot, isSnapshot, mcpDiscovered, mcpFactsOf, } from "../mcp/snapshot.js";
|
|
35
36
|
import { turnManifestOf } from "../tenant/session.js";
|
|
37
|
+
import { readRuntimeLimits } from "../tenant/runtime-limits.js";
|
|
36
38
|
import { sandboxWorkspaceKey, workspacePrefix } from "../sandbox/records.js";
|
|
37
39
|
import { abortKind } from "../tenant/worker.js";
|
|
38
|
-
import {
|
|
40
|
+
import { BlobRangeError } from "../blob/index.js";
|
|
41
|
+
import { openDefinitionFile, readDefinitionFile } from "../tenant/definition-files.js";
|
|
39
42
|
import { recordIntent, recordOutcome } from "./record.js";
|
|
43
|
+
import { createArtifactSeam } from "./artifacts.js";
|
|
44
|
+
import { RecordEntryTooLargeError } from "../record/index.js";
|
|
40
45
|
import { redactTokens } from "./redact.js";
|
|
41
46
|
import { beat, renewEveryMs, tokenOf } from "./renew.js";
|
|
47
|
+
import { hostTuning } from "../tuning.js";
|
|
48
|
+
import { passStartCheck } from "../tenant/agent-versions.js";
|
|
42
49
|
/** No attached harness serves workspaces (or, with `pod`, that pod sandbox's). */
|
|
43
50
|
export class NoWorkspaceHarness extends Error {
|
|
44
51
|
pod;
|
|
@@ -60,11 +67,12 @@ const OUTPUTS = [
|
|
|
60
67
|
"checkpoint",
|
|
61
68
|
];
|
|
62
69
|
export function createHarnessApiServer(ctx, options = {}) {
|
|
63
|
-
const offerWaitMs = options.offerWaitMs ??
|
|
70
|
+
const offerWaitMs = options.offerWaitMs ?? hostTuning().harnessApi.offerWaitMs;
|
|
64
71
|
const connections = new Set();
|
|
65
72
|
const waiting = [];
|
|
66
73
|
const queued = [];
|
|
67
74
|
const runs = new Map();
|
|
75
|
+
const artifacts = createArtifactSeam(ctx);
|
|
68
76
|
let closed = false;
|
|
69
77
|
/**
|
|
70
78
|
* A harness may take a run of its own harness id (R4.1): a pod sandbox's host its sandbox's
|
|
@@ -81,15 +89,6 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
81
89
|
continue;
|
|
82
90
|
}
|
|
83
91
|
queued.splice(i, 1);
|
|
84
|
-
const clash = nativeToolClashes(waiting[at].connection.tools, run.offer.start);
|
|
85
|
-
if (clash.length > 0) {
|
|
86
|
-
// The harness keeps waiting for a run its tools fit; this turn fails (Harness API 3).
|
|
87
|
-
run.end({
|
|
88
|
-
kind: "refused",
|
|
89
|
-
message: `Harness '${waiting[at].connection.harness}' runs tools named like tools of this turn's agents: ${clash.join(", ")}. A tool the harness runs itself needs a name no other tool of the session has.`,
|
|
90
|
-
});
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
92
|
const lease = waiting.splice(at, 1)[0];
|
|
94
93
|
run.connection = lease.connection;
|
|
95
94
|
// The run token the advance holds now (F5): the gate calls of this run present it.
|
|
@@ -111,11 +110,18 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
111
110
|
evidence: "claimed",
|
|
112
111
|
...(runId === undefined ? {} : { runId }),
|
|
113
112
|
});
|
|
113
|
+
/** What the artifact seam serves a run: its session and turn, its limits, its signal. */
|
|
114
|
+
const artifactScope = (run) => ({
|
|
115
|
+
runId: run.grant.runId,
|
|
116
|
+
sessionId: run.grant.sessionId,
|
|
117
|
+
turnId: run.grant.turnId,
|
|
118
|
+
limits: run.offer.start.limits,
|
|
119
|
+
runSignal: run.offer.controller.signal,
|
|
120
|
+
});
|
|
114
121
|
const scope = (run) => ({
|
|
115
122
|
ctx,
|
|
116
123
|
lease: run.offer.lease,
|
|
117
124
|
signal: run.offer.controller.signal,
|
|
118
|
-
...(run.connection?.tools ? { nativeTools: run.connection.tools } : {}),
|
|
119
125
|
...(run.connection ? { writer: writerOf(run.connection, run.grant.runId) } : {}),
|
|
120
126
|
});
|
|
121
127
|
const serve = (connection) => async (method, params, signal) => {
|
|
@@ -127,8 +133,6 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
127
133
|
throw new HarnessApiError("invalid", `unsupported Harness API version ${api}: this Runtime speaks ${HARNESS_API_VERSION}`);
|
|
128
134
|
connection.harness = await harnessIdOf(connection, name);
|
|
129
135
|
connection.workspace = features.workspace !== undefined;
|
|
130
|
-
if (features.tools?.length)
|
|
131
|
-
connection.tools = new Set(features.tools.map((tool) => tool.name));
|
|
132
136
|
return {
|
|
133
137
|
api: HARNESS_API_VERSION,
|
|
134
138
|
tenantId: ctx.config.tenantId,
|
|
@@ -181,7 +185,11 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
181
185
|
case "session.mcp":
|
|
182
186
|
return recordMcp(run, p);
|
|
183
187
|
case "definition.file":
|
|
184
|
-
return definitionFile(run, p
|
|
188
|
+
return definitionFile(run, p, signal);
|
|
189
|
+
case "artifact.read":
|
|
190
|
+
return artifacts.read(artifactScope(run), p, signal);
|
|
191
|
+
case "artifact.write":
|
|
192
|
+
return artifacts.write(artifactScope(run), p, signal);
|
|
185
193
|
default:
|
|
186
194
|
throw new HarnessApiError("invalid", `Unknown request ${method}`);
|
|
187
195
|
}
|
|
@@ -204,6 +212,9 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
204
212
|
const expected = environment?.applied.harness ?? DEFAULT_HARNESS;
|
|
205
213
|
if (expected !== name)
|
|
206
214
|
throw new HarnessApiError("invalid", `Environment ${connection.host.sandboxId} runs the ${expected} harness, and this pod says ${name}`);
|
|
215
|
+
// Its pod started on the version it switched to, setup done (track T3): the start check passed.
|
|
216
|
+
if (environment?.startCheck)
|
|
217
|
+
await passStartCheck(ctx, connection.host.sandboxId, connection.host.epoch);
|
|
207
218
|
}
|
|
208
219
|
return name;
|
|
209
220
|
};
|
|
@@ -211,7 +222,8 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
211
222
|
* A `sandbox.*` event the harness claims: for a run it holds (the run's session, or the
|
|
212
223
|
* session owning its sandbox), or a session one of its workspace requests acts for. A
|
|
213
224
|
* `sandbox.state` record becomes the workspace's `sandboxes` row. Claims are best effort, as
|
|
214
|
-
* the events of core's own SandboxManager are: a session gone since is skipped.
|
|
225
|
+
* the events of core's own SandboxManager are: a session gone since is skipped. One past the
|
|
226
|
+
* Tenant's `recordEntryBytes` is refused (`limit_exceeded`).
|
|
215
227
|
*/
|
|
216
228
|
const claim = async (connection, event) => {
|
|
217
229
|
if (!HARNESS_CLAIMS.includes(event.type))
|
|
@@ -240,6 +252,9 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
240
252
|
});
|
|
241
253
|
}
|
|
242
254
|
catch (error) {
|
|
255
|
+
// Past the record entry limit is the harness's to hear (`limit_exceeded`), not a lost claim.
|
|
256
|
+
if (error instanceof RecordEntryTooLargeError)
|
|
257
|
+
throw error;
|
|
243
258
|
ctx.config.logger.warn("harness event claim not recorded", {
|
|
244
259
|
sessionId: event.sessionId,
|
|
245
260
|
type: event.type,
|
|
@@ -250,22 +265,23 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
250
265
|
};
|
|
251
266
|
/**
|
|
252
267
|
* What a harness found readying the run's MCP servers: the first snapshot recorded for the
|
|
253
|
-
* session wins,
|
|
254
|
-
*
|
|
268
|
+
* session wins, pinned as it is within the Tenant's Runtime limit `mcpSnapshotBytes` (a server
|
|
269
|
+
* past it is left out, with a diagnostic: `fitSnapshot`), with `mcp.discovered` in its log;
|
|
270
|
+
* diagnostics replace those of the same server. Answers the session's facts as the run's turn
|
|
271
|
+
* sees them (protocol 15).
|
|
255
272
|
*/
|
|
256
273
|
const recordMcp = async (run, params) => {
|
|
257
274
|
const snapshot = params.snapshot;
|
|
258
275
|
if (snapshot !== undefined && !isSnapshot(snapshot))
|
|
259
276
|
throw new HarnessApiError("invalid", "The MCP snapshot is malformed");
|
|
260
|
-
// Which MCP tools the model reaches through tool_search, decided once for the session from
|
|
261
|
-
// the Tenant's model's context window (R2b C10, Q21).
|
|
262
|
-
const contextWindow = snapshot ? contextWindowOf(await ctx.vault.getHostModel()) : 0;
|
|
263
277
|
return ctx.store.tx(async (t) => {
|
|
264
278
|
const { lease } = run.offer;
|
|
265
279
|
const current = await ownedSession(t, lease, lease.sessionId);
|
|
266
|
-
|
|
280
|
+
let diagnostics = params.diagnostics;
|
|
267
281
|
if (snapshot && !current.mcpSnapshot) {
|
|
268
|
-
|
|
282
|
+
const fitted = fitSnapshot(snapshot, diagnostics, (await readRuntimeLimits(t)).mcpSnapshotBytes);
|
|
283
|
+
diagnostics = fitted.diagnostics;
|
|
284
|
+
current.mcpSnapshot = fitted.snapshot;
|
|
269
285
|
current.mcpDiagnostics = diagnostics;
|
|
270
286
|
await t.put("sessions", current.id, current);
|
|
271
287
|
await t.event(current.id, run.grant.turnId, "mcp.discovered", mcpDiscovered(current.mcpSnapshot, diagnostics, current.manifest), run.connection ? writerOf(run.connection, run.grant.runId) : undefined);
|
|
@@ -282,27 +298,48 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
282
298
|
current.mcpDiagnostics = prior;
|
|
283
299
|
await t.put("sessions", current.id, current);
|
|
284
300
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// The turn's manifest: a variant may have disabled tools or required their approval.
|
|
288
|
-
sessionTools: [...(sessionToolsOf(current.mcpSnapshot, turnManifestOf(current)) ?? [])],
|
|
289
|
-
};
|
|
301
|
+
// The turn's manifest: a variant may have disabled tools.
|
|
302
|
+
return current.mcpSnapshot ? { mcp: mcpFactsOf(current.mcpSnapshot, turnManifestOf(current)) } : {};
|
|
290
303
|
});
|
|
291
304
|
};
|
|
292
|
-
/**
|
|
293
|
-
|
|
305
|
+
/**
|
|
306
|
+
* A definition file the run's definition names (its skills', for its sandbox), base64: whole,
|
|
307
|
+
* or the range `offset` and `length` name (none past the end), at most the run's
|
|
308
|
+
* `limits.chunkBytes`, which is also the length when the harness names none.
|
|
309
|
+
*/
|
|
310
|
+
const definitionFile = async (run, { sha256, offset, length }, signal) => {
|
|
294
311
|
if (!definitionFilesOf(run.offer.start.routing.rootManifest).has(sha256))
|
|
295
312
|
throw new HarnessApiError("invalid", `The run's definition names no file ${sha256}`);
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
|
|
313
|
+
const missing = () => new HarnessApiError("unavailable", `The Object store has no bytes for ${sha256}`);
|
|
314
|
+
if (offset === undefined && length === undefined) {
|
|
315
|
+
const bytes = await readDefinitionFile(ctx.blobs, sha256, signal);
|
|
316
|
+
if (!bytes)
|
|
317
|
+
throw missing();
|
|
318
|
+
return { base64: Buffer.from(bytes).toString("base64") };
|
|
319
|
+
}
|
|
320
|
+
const { chunkBytes } = run.offer.start.limits;
|
|
321
|
+
if (length !== undefined && length > chunkBytes)
|
|
322
|
+
throw new HarnessApiError("limit_exceeded", limitExceededMessage("The range asked for", length, "chunkBytes", chunkBytes));
|
|
323
|
+
const start = offset ?? 0;
|
|
324
|
+
const end = start + (length ?? chunkBytes) - 1;
|
|
325
|
+
let body;
|
|
326
|
+
try {
|
|
327
|
+
body = await openDefinitionFile(ctx.blobs, sha256, { range: { start, end }, signal });
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
if (error instanceof BlobRangeError)
|
|
331
|
+
return { base64: "" };
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
if (!body)
|
|
335
|
+
throw missing();
|
|
336
|
+
return { base64: Buffer.from(await new Response(body).arrayBuffer()).toString("base64") };
|
|
300
337
|
};
|
|
301
338
|
/**
|
|
302
339
|
* A custom harness's output (R4.2): its state is its own, stored as sent and never read, so it
|
|
303
|
-
* must be JSON and at most `
|
|
304
|
-
* that threw would. It cannot pause for approvals in v2 (Q14):
|
|
305
|
-
* until R5 makes them core holds.
|
|
340
|
+
* must be JSON and at most the run's `limits.harnessStateBytes`; a larger one fails the turn
|
|
341
|
+
* (`limit_exceeded`), as an engine that threw would. It cannot pause for approvals in v2 (Q14):
|
|
342
|
+
* approvals read our engine's plan until R5 makes them core holds.
|
|
306
343
|
*/
|
|
307
344
|
const checkCustomOutput = (run, method, params) => {
|
|
308
345
|
if (method === "turn.paused")
|
|
@@ -310,14 +347,16 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
310
347
|
if (params.state === undefined || run.outputs.has(method))
|
|
311
348
|
return;
|
|
312
349
|
const bytes = Buffer.byteLength(JSON.stringify(params.state) ?? "");
|
|
313
|
-
|
|
350
|
+
const { harnessStateBytes } = run.offer.start.limits;
|
|
351
|
+
if (bytes <= harnessStateBytes)
|
|
314
352
|
return;
|
|
353
|
+
const message = limitExceededMessage("The harness's state", bytes, "harnessStateBytes", harnessStateBytes);
|
|
315
354
|
output(run, "turn.failed", {
|
|
316
355
|
runId: run.grant.runId,
|
|
317
356
|
status: "failed",
|
|
318
|
-
thrown: { code: "
|
|
357
|
+
thrown: { code: "limit_exceeded", message },
|
|
319
358
|
}).catch(() => undefined);
|
|
320
|
-
throw new HarnessApiError("
|
|
359
|
+
throw new HarnessApiError("limit_exceeded", `${message} The turn failed.`);
|
|
321
360
|
};
|
|
322
361
|
const output = (run, method, params) => {
|
|
323
362
|
const known = run.outputs.get(method);
|
|
@@ -455,6 +494,8 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
455
494
|
return;
|
|
456
495
|
run.ended = true;
|
|
457
496
|
clearTimeout(timer);
|
|
497
|
+
// An upload the run left open commits nothing.
|
|
498
|
+
artifacts.endRun(run.grant.runId);
|
|
458
499
|
controller.signal.removeEventListener("abort", onAbort);
|
|
459
500
|
// An output's run stays held until core answers it, so a repeat gets the same answer.
|
|
460
501
|
if (end.kind === "output") {
|
|
@@ -501,31 +542,3 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
501
542
|
},
|
|
502
543
|
};
|
|
503
544
|
}
|
|
504
|
-
function isSnapshot(value) {
|
|
505
|
-
const snapshot = value;
|
|
506
|
-
return (typeof snapshot === "object" &&
|
|
507
|
-
snapshot !== null &&
|
|
508
|
-
snapshot.snapshotSchemaVersion === 1 &&
|
|
509
|
-
typeof snapshot.manifestHash === "string" &&
|
|
510
|
-
Array.isArray(snapshot.mcpTools));
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* The tools a harness runs itself (`features.tools`) whose names the turn already uses: a tool of
|
|
514
|
-
* the turn's agents (their own and the Runtime's `runtime` tools), a session tool, `tool_search` or
|
|
515
|
-
* `tool_call` (session tools a later step may get). Tools are known by name alone, so a native
|
|
516
|
-
* tool must not take one (Harness API 3); `hello` already refuses a name with `__`, which names an
|
|
517
|
-
* MCP server's tools. A flow turn runs no native tools.
|
|
518
|
-
*/
|
|
519
|
-
export function nativeToolClashes(tools, start) {
|
|
520
|
-
if (!tools?.size || start.engine !== "agent")
|
|
521
|
-
return [];
|
|
522
|
-
const manifest = start.manifest;
|
|
523
|
-
const taken = new Set([TOOL_SEARCH_TOOL, TOOL_CALL_TOOL]);
|
|
524
|
-
for (const agent of [manifest, ...delegatesOf(manifest).map((delegate) => delegate.manifest)])
|
|
525
|
-
for (const tool of [...(agent.tools ?? []), ...(agent.runtime?.tools ?? [])])
|
|
526
|
-
taken.add(tool.name);
|
|
527
|
-
for (const tool of (start.sessionTools ?? []))
|
|
528
|
-
if (typeof tool?.name === "string")
|
|
529
|
-
taken.add(tool.name);
|
|
530
|
-
return [...tools].filter((name) => taken.has(name)).sort();
|
|
531
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { RecordedOutcome, TurnStart } from "@nylorun/core/harness-api";
|
|
1
|
+
import type { ModelDescriptor, RecordedOutcome, RuntimeLimits, TurnAgent, TurnMemory, TurnStart } from "@nylorun/core/harness-api";
|
|
2
|
+
import { type SandboxManifest } from "@nylorun/core/define";
|
|
2
3
|
import type { SandboxPodState } from "../store/types.js";
|
|
3
4
|
import { type Lease, type Session, type TenantContext } from "../tenant/context.js";
|
|
4
5
|
import { type TraceContext } from "../traces/ids.js";
|
|
@@ -6,29 +7,47 @@ import { type TraceContext } from "../traces/ids.js";
|
|
|
6
7
|
export interface SegmentStart {
|
|
7
8
|
readonly current: Session;
|
|
8
9
|
readonly fixtureModel: boolean;
|
|
10
|
+
/** The Tenant's Runtime limits as the segment starts: what `turn.start.limits` hands the harness. */
|
|
11
|
+
readonly limits: RuntimeLimits;
|
|
9
12
|
/** The transcript the engine resumes from (agents with state; empty otherwise). */
|
|
10
13
|
readonly transcript: unknown[];
|
|
11
14
|
/** The record position of `transcript` (`foldTranscriptWithCursor`). */
|
|
12
15
|
readonly cursor: number;
|
|
13
16
|
readonly outcomes: RecordedOutcome[];
|
|
14
|
-
/** The session's sandbox workspace: the session, and the
|
|
17
|
+
/** The session's sandbox workspace: the session, and the Agent whose workspace it is. */
|
|
15
18
|
readonly sandbox: {
|
|
16
19
|
readonly ownerId: string;
|
|
17
20
|
readonly environmentId?: string;
|
|
18
21
|
/** Variables every sandbox command gets (R2c): secret names set to the sentinel, plain values. */
|
|
19
22
|
readonly environment?: Readonly<Record<string, string>>;
|
|
23
|
+
/** The sandbox spec the session pinned when it opened; absent without a sandbox. */
|
|
24
|
+
readonly spec?: SandboxManifest;
|
|
20
25
|
};
|
|
21
26
|
/**
|
|
22
|
-
* The
|
|
23
|
-
*
|
|
27
|
+
* The Agent the session runs on, as `TurnStart.agent` states it (Harness API 5): its id and
|
|
28
|
+
* kind, and its sandbox's workspace when the session has a sandbox.
|
|
29
|
+
*/
|
|
30
|
+
readonly agent?: TurnAgent;
|
|
31
|
+
/**
|
|
32
|
+
* The Agent is a pod (F7.2): its engine runs the segment. Its lifecycle state, and whether its
|
|
33
|
+
* new volume is still being seeded from a disk version (R2d step 3).
|
|
24
34
|
*/
|
|
25
35
|
readonly pod?: {
|
|
26
36
|
readonly id: string;
|
|
27
37
|
readonly pod: SandboxPodState;
|
|
28
38
|
readonly seeding?: boolean;
|
|
39
|
+
/** It starts on a new version (track T3) and has not joined yet: a failed start goes back. */
|
|
40
|
+
readonly starting?: boolean;
|
|
29
41
|
};
|
|
30
42
|
/** The turn's span context (R7.4): what `TurnStart.trace` hands the harness. */
|
|
31
43
|
readonly trace?: TraceContext;
|
|
44
|
+
/**
|
|
45
|
+
* The model the turn's calls use (protocol 15), as the segment starts: what `TurnStart.model`
|
|
46
|
+
* hands an agent's harness. Absent for a flow, and when the Tenant has no model.
|
|
47
|
+
*/
|
|
48
|
+
readonly model?: ModelDescriptor;
|
|
49
|
+
/** The Agent's memory (track T5): its access, instructions and the index the harness pins. */
|
|
50
|
+
readonly memory?: TurnMemory;
|
|
32
51
|
}
|
|
33
52
|
/** The segment's starting transaction and fold. */
|
|
34
53
|
export declare function startSegment(ctx: TenantContext, lease: Lease,
|
|
@@ -38,7 +57,10 @@ options?: {
|
|
|
38
57
|
}): Promise<SegmentStart>;
|
|
39
58
|
/** The run's `turn.start`. */
|
|
40
59
|
export declare function buildTurnStart(ctx: TenantContext, segment: SegmentStart): TurnStart;
|
|
41
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* The engine's yield budget for a segment: the Tenant's `rollover`, else the Host tuning's
|
|
62
|
+
* (`harnessApi.rolloverSteps`, `rolloverMs`), well inside the advance deadline.
|
|
63
|
+
*/
|
|
42
64
|
export declare function yieldAfterOf(ctx: TenantContext): {
|
|
43
65
|
steps: number;
|
|
44
66
|
ms: number;
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a segment starts from (§10.5): in one transaction the session's state is rebased onto
|
|
3
|
+
* the turn's manifest, a transcript still on the row is recorded, and the segment's completed
|
|
4
|
+
* outcomes are read; then the transcript is folded from the record (P0.3). `buildTurnStart`
|
|
5
|
+
* turns that into the run's `turn.start`: the checkpoint goes without its transcript, which the
|
|
6
|
+
* harness holds at the fold's cursor or reads once.
|
|
7
|
+
*/
|
|
8
|
+
import { harnessLimitsOf } from "@nylorun/core/contracts";
|
|
9
|
+
import { SANDBOX_WORKSPACE } from "@nylorun/core/define";
|
|
1
10
|
import { isWorkflowManifest } from "../core/flow-host.js";
|
|
2
11
|
import { sandboxWorkspaceOf } from "../sandbox/share.js";
|
|
3
12
|
import { ownedTx } from "../store/ownership.js";
|
|
4
13
|
import { harnessOf } from "../tenant/context.js";
|
|
14
|
+
import { repinTurn } from "../tenant/agent-versions.js";
|
|
5
15
|
import { HARNESS_ID } from "../sandbox/placement.js";
|
|
6
16
|
import { checkParity, foldTranscriptWithCursor, leanState, transcriptOf, transcriptUpdates, withTranscript, } from "../tenant/history.js";
|
|
7
17
|
import { usesFixtureModel } from "../tenant/model-setting.js";
|
|
8
|
-
import {
|
|
18
|
+
import { currentModelDescriptor } from "../model/descriptor.js";
|
|
19
|
+
import { readRuntimeLimits } from "../tenant/runtime-limits.js";
|
|
20
|
+
import { flowLimitsOf } from "../core/limits.js";
|
|
21
|
+
import { turnManifestOf } from "../tenant/session.js";
|
|
22
|
+
import { mcpFactsOf } from "../mcp/snapshot.js";
|
|
9
23
|
import { bulkOutcomes } from "./record.js";
|
|
24
|
+
import { renderMemoryIndex } from "../memory/service.js";
|
|
25
|
+
import { memorySettingsOf } from "../memory/tool.js";
|
|
10
26
|
import { traceKey } from "../traces/key.js";
|
|
27
|
+
import { hostTuning } from "../tuning.js";
|
|
11
28
|
import { traceparentOf, turnSpanOf, turnTraceIdOf, } from "../traces/ids.js";
|
|
12
|
-
/** Segment rollover defaults (Model Calls §10), well inside the advance deadline. */
|
|
13
|
-
const ROLLOVER_STEPS = 50;
|
|
14
|
-
const ROLLOVER_MS = 20 * 60_000;
|
|
15
29
|
/** The segment's starting transaction and fold. */
|
|
16
30
|
export async function startSegment(ctx, lease,
|
|
17
31
|
/** For a harness: also the segment's outcomes and the sandbox's owner. */
|
|
@@ -19,34 +33,58 @@ options = {}) {
|
|
|
19
33
|
const id = lease.sessionId;
|
|
20
34
|
// Read before the transaction: the first read of the Tenant may create the key.
|
|
21
35
|
const key = options.harness ? await traceKey(ctx.store) : undefined;
|
|
22
|
-
const
|
|
36
|
+
const opened = await ownedTx(ctx.store, id, lease.epoch, async (t, current) => {
|
|
37
|
+
// A turn's first segment runs the version its Agent runs now (T3, D73).
|
|
38
|
+
if (options.harness && (await repinTurn(t, current)))
|
|
39
|
+
await t.put("sessions", id, current);
|
|
23
40
|
// A transcript left on our engine's state by an older Runtime is recorded once; another
|
|
24
41
|
// harness's state is its own (R4.2).
|
|
42
|
+
const limits = await readRuntimeLimits(t);
|
|
25
43
|
if (!isWorkflowManifest(current.manifest) && current.checkpoint && harnessOf(current) === HARNESS_ID) {
|
|
26
|
-
await adoptStoredTranscript(t, current);
|
|
44
|
+
await adoptStoredTranscript(t, current, limits.recordEntryBytes);
|
|
27
45
|
const cp = current.checkpoint;
|
|
28
46
|
current.checkpoint = { ...cp, state: current.state };
|
|
29
47
|
await t.put("sessions", id, current);
|
|
30
48
|
}
|
|
31
49
|
const fixtureModel = await usesFixtureModel(t);
|
|
32
50
|
if (!options.harness)
|
|
33
|
-
return { current, fixtureModel, outcomes: [], sandbox: { ownerId: id } };
|
|
51
|
+
return { current, fixtureModel, limits, outcomes: [], sandbox: { ownerId: id } };
|
|
34
52
|
const workspace = sandboxWorkspaceOf(current);
|
|
35
53
|
const resource = workspace.environmentId === undefined ? undefined : await t.environment(workspace.environmentId);
|
|
36
54
|
const environment = await ctx.vault.environmentVariables(t, current.environmentId);
|
|
37
|
-
const sandbox =
|
|
55
|
+
const sandbox = {
|
|
56
|
+
...workspace,
|
|
57
|
+
...(Object.keys(environment).length > 0 ? { environment } : {}),
|
|
58
|
+
...(current.sandbox === undefined ? {} : { spec: current.sandbox }),
|
|
59
|
+
};
|
|
38
60
|
const turnId = current.activeTurnId;
|
|
61
|
+
const memory = isWorkflowManifest(current.manifest) ? undefined : await turnMemoryOf(t, current, limits);
|
|
39
62
|
return {
|
|
40
63
|
current,
|
|
41
64
|
fixtureModel,
|
|
65
|
+
limits,
|
|
66
|
+
...(memory ? { memory } : {}),
|
|
42
67
|
outcomes: current.checkpoint ? await bulkOutcomes(t, current, current.checkpoint) : [],
|
|
43
68
|
sandbox,
|
|
69
|
+
...(resource ? { agent: agentOf(resource, current.sandbox, await selfWakeOf(t, current)) } : {}),
|
|
44
70
|
...(key && turnId ? { trace: turnContextOf(key, ctx.store.tenantId, current, turnId) } : {}),
|
|
45
71
|
...(resource?.pod
|
|
46
|
-
? {
|
|
72
|
+
? {
|
|
73
|
+
pod: {
|
|
74
|
+
id: resource.id,
|
|
75
|
+
pod: resource.pod,
|
|
76
|
+
...(resource.diskSeed ? { seeding: true } : {}),
|
|
77
|
+
...(resource.startCheck ? { starting: true } : {}),
|
|
78
|
+
},
|
|
79
|
+
}
|
|
47
80
|
: {}),
|
|
48
81
|
};
|
|
49
82
|
});
|
|
83
|
+
// The model an agent's harness decides files by, read outside the session's transaction.
|
|
84
|
+
const model = options.harness && !isWorkflowManifest(opened.current.manifest)
|
|
85
|
+
? await currentModelDescriptor(ctx)
|
|
86
|
+
: undefined;
|
|
87
|
+
const started = model ? { ...opened, model } : opened;
|
|
50
88
|
// One history (P0.3): the engine resumes from the transcript folded from the record.
|
|
51
89
|
const { current } = started;
|
|
52
90
|
const cp = current.checkpoint;
|
|
@@ -76,24 +114,66 @@ export function buildTurnStart(ctx, segment) {
|
|
|
76
114
|
checkpoint: !flow && cp.state && harnessOf(current) === HARNESS_ID
|
|
77
115
|
? { ...cp, state: withTranscript(cp.state, []) }
|
|
78
116
|
: cp,
|
|
79
|
-
// The turn's manifest: a variant may
|
|
80
|
-
...(flow
|
|
117
|
+
// The session's MCP discovery as the turn's manifest sees it: a variant may disable tools.
|
|
118
|
+
...(!flow && current.mcpSnapshot ? { mcp: mcpFactsOf(current.mcpSnapshot, turnManifestOf(current)) } : {}),
|
|
81
119
|
outcomes: segment.outcomes,
|
|
82
120
|
transcript: { cursor: segment.cursor },
|
|
83
121
|
options: {
|
|
84
122
|
...(flow
|
|
85
|
-
? { flowLimits:
|
|
123
|
+
? { flowLimits: flowLimitsOf(segment.limits) }
|
|
86
124
|
: { yieldAfter: yieldAfterOf(ctx) }),
|
|
87
125
|
fixtureModel: segment.fixtureModel,
|
|
88
126
|
},
|
|
89
127
|
routing: {
|
|
90
128
|
rootManifest: current.manifest,
|
|
91
|
-
...(current.mcpSnapshot ? { mcpSnapshot: current.mcpSnapshot } : {}),
|
|
92
129
|
sandbox: segment.sandbox,
|
|
93
130
|
},
|
|
94
131
|
...(segment.trace ? { trace: segment.trace } : {}),
|
|
132
|
+
limits: harnessLimitsOf(segment.limits),
|
|
133
|
+
...(segment.model && !flow ? { model: segment.model } : {}),
|
|
134
|
+
...(segment.agent && !flow ? { agent: segment.agent } : {}),
|
|
135
|
+
// The agent manifest version the session pinned, and its harness's own settings (protocol 16).
|
|
136
|
+
...(current.definition === undefined ? {} : { definition: current.definition }),
|
|
137
|
+
...(current.loop === undefined || flow ? {} : { loop: current.loop }),
|
|
138
|
+
...(segment.memory && !flow ? { memory: segment.memory } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The Agent's memory as the segment starts (track T5, D72), when the version the session runs sets
|
|
143
|
+
* `harness.memory`: its access (the same in every turn), the agent's instructions, and the index of
|
|
144
|
+
* its memories, newest first, within the Tenant's index limits.
|
|
145
|
+
*/
|
|
146
|
+
async function turnMemoryOf(t, s, limits) {
|
|
147
|
+
const settings = await memorySettingsOf(t, s);
|
|
148
|
+
if (!settings)
|
|
149
|
+
return undefined;
|
|
150
|
+
const { index, truncated } = await renderMemoryIndex(t, s.agentId, limits);
|
|
151
|
+
return {
|
|
152
|
+
access: settings.access ?? "read_write",
|
|
153
|
+
...(settings.instructions === undefined ? {} : { instructions: settings.instructions }),
|
|
154
|
+
index,
|
|
155
|
+
truncated,
|
|
95
156
|
};
|
|
96
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* The facts of the Agent a session runs on (Harness API 5): its id and kind, and, with the
|
|
160
|
+
* session's sandbox, the workspace its commands start in. The harness words them.
|
|
161
|
+
*/
|
|
162
|
+
function agentOf(resource, spec, selfWake) {
|
|
163
|
+
return {
|
|
164
|
+
id: resource.id,
|
|
165
|
+
kind: resource.kind,
|
|
166
|
+
...(spec === undefined ? {} : { sandbox: { workspace: SANDBOX_WORKSPACE } }),
|
|
167
|
+
...(selfWake ? { selfWake: true } : {}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/** Whether the manifest version the session runs sets `runtime.selfWake` (track T4, D77). */
|
|
171
|
+
async function selfWakeOf(t, s) {
|
|
172
|
+
if (!s.definition)
|
|
173
|
+
return false;
|
|
174
|
+
const version = await t.agentManifest(s.definition.name, s.definition.version);
|
|
175
|
+
return version?.body.runtime?.selfWake === true;
|
|
176
|
+
}
|
|
97
177
|
/**
|
|
98
178
|
* The context of turn `turnId`'s span (R7.4): its trace (the caller's when its message carried a
|
|
99
179
|
* `traceparent`) and its span, as the trace projector derives them, with the caller's
|
|
@@ -106,18 +186,21 @@ function turnContextOf(key, tenantId, s, turnId) {
|
|
|
106
186
|
...(s.turnTrace?.tracestate ? { tracestate: s.turnTrace.tracestate } : {}),
|
|
107
187
|
};
|
|
108
188
|
}
|
|
109
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* The engine's yield budget for a segment: the Tenant's `rollover`, else the Host tuning's
|
|
191
|
+
* (`harnessApi.rolloverSteps`, `rolloverMs`), well inside the advance deadline.
|
|
192
|
+
*/
|
|
110
193
|
export function yieldAfterOf(ctx) {
|
|
111
194
|
return {
|
|
112
|
-
steps: ctx.config.rollover?.steps ??
|
|
113
|
-
ms: ctx.config.rollover?.ms ??
|
|
195
|
+
steps: ctx.config.rollover?.steps ?? hostTuning().harnessApi.rolloverSteps,
|
|
196
|
+
ms: ctx.config.rollover?.ms ?? hostTuning().harnessApi.rolloverMs,
|
|
114
197
|
};
|
|
115
198
|
}
|
|
116
199
|
/**
|
|
117
200
|
* A session written before transcripts were recorded keeps its transcript on its row: record
|
|
118
201
|
* it once (the turn's starting transcript, then the turn so far), and store the row lean.
|
|
119
202
|
*/
|
|
120
|
-
async function adoptStoredTranscript(t, s) {
|
|
203
|
+
async function adoptStoredTranscript(t, s, recordEntryBytes) {
|
|
121
204
|
if (s.history)
|
|
122
205
|
return;
|
|
123
206
|
const now = transcriptOf(s.state);
|
|
@@ -131,9 +214,9 @@ async function adoptStoredTranscript(t, s) {
|
|
|
131
214
|
first ??= event.seq;
|
|
132
215
|
}
|
|
133
216
|
};
|
|
134
|
-
await write(null, transcriptUpdates([], start));
|
|
217
|
+
await write(null, transcriptUpdates([], start, recordEntryBytes));
|
|
135
218
|
if (s.activeTurnId)
|
|
136
|
-
await write(s.activeTurnId, transcriptUpdates(start, now));
|
|
219
|
+
await write(s.activeTurnId, transcriptUpdates(start, now, recordEntryBytes));
|
|
137
220
|
s.history = { from: first ?? 0, snapshot: first ?? 0 };
|
|
138
221
|
s.state = leanState(s.state);
|
|
139
222
|
s.turnStartState = leanState(s.turnStartState);
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
* Delivery (R5.3, R5.4). A tool call is sent at least once, and every send carries its effect
|
|
6
6
|
* id as the key. After a crash, a shutdown or a lost gate hop, a row still `invoking` is sent
|
|
7
7
|
* again: an MCP or HTTP tool call (it crosses the Tool Gate, which hands the tool the key) up to
|
|
8
|
-
* `
|
|
8
|
+
* the Tenant's Runtime limit `toolAttempts` sends, then it fails to the model as
|
|
9
|
+
* `tool.interrupted`. A sandbox or
|
|
9
10
|
* core-served call has no key to dedupe on, so a crash fails it to the model at once, and
|
|
10
11
|
* nothing runs it again (Q2). No tool call leaves its session `uncertain`.
|
|
11
12
|
*
|
|
12
|
-
* The row body keeps the journal's facts: `toolKind`, `server`, `
|
|
13
|
-
* `settledAt`. A row written before R5 has none of them.
|
|
13
|
+
* The row body keeps the journal's facts: `toolKind`, `server`, `tool` (the identity, protocol
|
|
14
|
+
* 15), `attempts`, `startedAt` and `settledAt`. A row written before R5 has none of them.
|
|
14
15
|
*
|
|
15
16
|
* Spans (R7.1). `tool.completed` also carries the call's effect id, the Tool Gate's own start
|
|
16
17
|
* and end of its last send (`gate`, from its `tool_crossings` row: MCP and HTTP calls through
|
|
@@ -23,8 +24,6 @@ import type { HostEffect } from "@nylorun/harness/run";
|
|
|
23
24
|
import type { Session } from "../tenant/context.js";
|
|
24
25
|
import { type GateTimes, type ToolCallFacts, type ToolCallKind, type ToolCallStatus, type ToolPolicyFact } from "../tenant/transcript.js";
|
|
25
26
|
import type { EffectDoc, Tx } from "../store/types.js";
|
|
26
|
-
/** How many times a tool call is sent before it fails to the model as `tool.interrupted`. */
|
|
27
|
-
export declare const MAX_TOOL_ATTEMPTS = 3;
|
|
28
27
|
/** A tool row's journal facts (R5), kept in its body. */
|
|
29
28
|
export interface ToolRowFacts {
|
|
30
29
|
/** Why the Tool Gate held the call for approval, and since when (R5 step 2). */
|
|
@@ -40,6 +39,8 @@ export interface ToolRowFacts {
|
|
|
40
39
|
};
|
|
41
40
|
toolKind?: ToolCallKind;
|
|
42
41
|
server?: string;
|
|
42
|
+
/** The tool's identity: an MCP tool's name on `server`, an HTTP tool's declared name. */
|
|
43
|
+
tool?: string;
|
|
43
44
|
/** The skill the call ran, and the plugin that brought its skill or MCP server. */
|
|
44
45
|
skill?: string;
|
|
45
46
|
plugin?: PluginLabel;
|
|
@@ -62,18 +63,22 @@ export type ToolRow = EffectDoc & ToolRowFacts & {
|
|
|
62
63
|
};
|
|
63
64
|
/** Where a tool call runs, and what it traces to (Q7, Q11). */
|
|
64
65
|
export interface ToolCallPlace {
|
|
65
|
-
|
|
66
|
+
/** Its target's kind; absent for a call that names none (an author's code tool). */
|
|
67
|
+
toolKind?: ToolCallKind;
|
|
66
68
|
/** Its MCP server or, for an agent's HTTP tool, its URL's host. */
|
|
67
69
|
server?: string;
|
|
70
|
+
/** Its identity: an MCP tool's own name on the server, an HTTP tool's declared name. */
|
|
71
|
+
tool?: string;
|
|
68
72
|
skill?: string;
|
|
69
73
|
plugin?: PluginLabel;
|
|
70
74
|
}
|
|
71
75
|
/**
|
|
72
|
-
* Where a tool call runs, and what it traces to
|
|
73
|
-
*
|
|
74
|
-
*
|
|
76
|
+
* Where a tool call runs, and what it traces to (protocol 15): its target's kind; an MCP call
|
|
77
|
+
* names its identity (server and tool) and the plugin that brought the server, an HTTP call its
|
|
78
|
+
* declared name and its URL's host. The skill the effect names (`skill`: a skill tool's, or a
|
|
79
|
+
* sandbox call in a skill's folder) is kept when the agent has it, with the plugin that brought it.
|
|
75
80
|
*/
|
|
76
|
-
export declare function toolKindOf(s: Pick<Session, "manifest"
|
|
81
|
+
export declare function toolKindOf(s: Pick<Session, "manifest">, agentManifest: AgentManifest | undefined, request: HostEffect): ToolCallPlace;
|
|
77
82
|
/** The facts a new tool row starts with: its first send, now. */
|
|
78
83
|
export declare function firstSend(kind: ToolCallPlace, now?: Date): ToolRowFacts;
|
|
79
84
|
/** A failed outcome the Runtime gives a call a crash interrupted: it may have run. */
|