@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,174 +0,0 @@
|
|
|
1
|
-
import { type EnvironmentRecipe, type EnvironmentView, type ForkEnvironmentRequest, type ForkEnvironmentResponse, type PutEnvironmentRequest, type PutEnvironmentSecretRequest } from "@nylorun/core/contracts";
|
|
2
|
-
import type { Environment, EnvironmentEventsQuery, Tx } from "../store/types.js";
|
|
3
|
-
import type { SandboxRouteDeps } from "../core/sandbox-routes.js";
|
|
4
|
-
import { type AuthScope, type Session, type TenantContext } from "./context.js";
|
|
5
|
-
import type { SealedSecretCopies } from "../vault/service.js";
|
|
6
|
-
/** The Environment grants that limit `scope`, or undefined when it reaches every Environment. */
|
|
7
|
-
export declare function environmentGrantsOf(scope: AuthScope): readonly string[] | undefined;
|
|
8
|
-
/** Who the vault's audit rows name for a request: the subject, else the application. */
|
|
9
|
-
export declare function actorOf(scope: AuthScope): string;
|
|
10
|
-
/** Refuses (the 404 of a missing one) Environment `id` when the caller's grants miss it. */
|
|
11
|
-
export declare function assertReaches(scope: AuthScope, id: string): void;
|
|
12
|
-
/** An Environment, unless it is gone or being deleted. */
|
|
13
|
-
export declare function liveEnvironment(t: Tx, id: string, options?: {
|
|
14
|
-
lock?: boolean;
|
|
15
|
-
}): Promise<Environment | undefined>;
|
|
16
|
-
/**
|
|
17
|
-
* Why input files cannot be used: each that is not a version of a Tenant-wide artifact (a
|
|
18
|
-
* session's artifacts go with the session). Pins nothing else: the version is the one named.
|
|
19
|
-
*/
|
|
20
|
-
export declare function fileErrors(t: Tx, files: EnvironmentRecipe["files"]): Promise<string[]>;
|
|
21
|
-
/**
|
|
22
|
-
* `PUT /v1/environments/{id}`: creates the Environment and its vault (within the Tenant's limit
|
|
23
|
-
* on their number) from an environment manifest's version or from the inline fields, or finds
|
|
24
|
-
* the one with this id, so "get or create" is one call. An existing one never changes what it
|
|
25
|
-
* runs (D63): its labels and owner guard may change, fields that match are accepted, and any
|
|
26
|
-
* other difference is `409 environment_immutable`. Every `PUT` counts as the Environment's use.
|
|
27
|
-
*/
|
|
28
|
-
export declare function putEnvironment(ctx: TenantContext, id: string, body: PutEnvironmentRequest, scope: AuthScope, options?: {
|
|
29
|
-
fork?: Fork;
|
|
30
|
-
}): Promise<EnvironmentView>;
|
|
31
|
-
/**
|
|
32
|
-
* The secret write `raw` asks of Environment `id` (D64). When what it runs declares secret
|
|
33
|
-
* slots, the name must be one (`409 secret_not_in_manifest`), and the body is `{ value }` (or
|
|
34
|
-
* `{ headers }` for a `headers` slot) with the binding from the slot; a full typed body is
|
|
35
|
-
* accepted only when its binding is the slot's. Without slots, today's typed body.
|
|
36
|
-
*/
|
|
37
|
-
export declare function secretRequestFor(ctx: TenantContext, id: string, name: string, raw: unknown): Promise<PutEnvironmentSecretRequest>;
|
|
38
|
-
/** What a create does for a fork (`POST .../fork`); `copied` is filled in by the create. */
|
|
39
|
-
interface Fork {
|
|
40
|
-
source: string;
|
|
41
|
-
setup: boolean;
|
|
42
|
-
/**
|
|
43
|
-
* The source's secrets sealed by keys for the new vault `vaultId` (F4.2), before the create's
|
|
44
|
-
* transaction, which inserts them; absent with `secrets: none`.
|
|
45
|
-
*/
|
|
46
|
-
sealed?: {
|
|
47
|
-
vaultId: string;
|
|
48
|
-
copies: SealedSecretCopies;
|
|
49
|
-
};
|
|
50
|
-
copied?: {
|
|
51
|
-
copied: string[];
|
|
52
|
-
dropped: string[];
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* `POST /v1/environments/{id}/fork` (Q15): how an Environment gets a new manifest version. A new
|
|
57
|
-
* Environment `body.id` is made from the manifest version (default the source's manifest at its
|
|
58
|
-
* latest), its disk started from a version of the source's (`latest` takes a snapshot first,
|
|
59
|
-
* refused during a turn), and its secrets copied inside the Runtime. A fork onto other setup
|
|
60
|
-
* runs that setup on the copied disk before its first turn (Q17). The source keeps what it runs,
|
|
61
|
-
* its disk and its sessions. With `dryRun`, the plan only.
|
|
62
|
-
*/
|
|
63
|
-
export declare function forkEnvironment(ctx: TenantContext, sourceId: string, body: ForkEnvironmentRequest, scope: AuthScope): Promise<ForkEnvironmentResponse>;
|
|
64
|
-
/** `GET /v1/environments/{id}`. */
|
|
65
|
-
export declare function getEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
66
|
-
/** `GET /v1/environments?label=k=v`: every Environment with all the labels, that the caller reaches. */
|
|
67
|
-
export declare function listEnvironments(ctx: TenantContext, labels: Record<string, string>, scope: AuthScope): Promise<{
|
|
68
|
-
environments: EnvironmentView[];
|
|
69
|
-
}>;
|
|
70
|
-
/**
|
|
71
|
-
* Asks pod Environment `id` to run when it is stopped or failed (a disk copy needs its engine),
|
|
72
|
-
* with its recipe applied, as a turn start would.
|
|
73
|
-
*/
|
|
74
|
-
export declare function wakePod(ctx: TenantContext, id: string): Promise<void>;
|
|
75
|
-
/** Whether a disk lease (R2d step 3) holds `environment` now. */
|
|
76
|
-
export declare function diskHeld(environment: Environment, now?: number): boolean;
|
|
77
|
-
/** Refused while a snapshot or restore copies the disk (a pending seed does not count). */
|
|
78
|
-
export declare function refuseDiskCopy(environment: Environment): void;
|
|
79
|
-
/**
|
|
80
|
-
* `DELETE /v1/environments/{id}`: deletes the Environment, its vault and its workspace. Refused
|
|
81
|
-
* while a session that names it has an active turn. Sessions keep its id: their next turn is
|
|
82
|
-
* refused (`environment_unavailable`) unless an Environment with this id exists again.
|
|
83
|
-
*/
|
|
84
|
-
export declare function deleteEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<{
|
|
85
|
-
id: string;
|
|
86
|
-
deleted: boolean;
|
|
87
|
-
}>;
|
|
88
|
-
/**
|
|
89
|
-
* Deletes every Environment unused for its `lifecycle.deleteAfter` (Q13): no turn, recipe
|
|
90
|
-
* change, secret write, stop or reset since. One with a turn running waits for the next sweep.
|
|
91
|
-
* Run by the Tenant sweep.
|
|
92
|
-
*/
|
|
93
|
-
export declare function sweepUnusedEnvironments(ctx: TenantContext, now?: number): Promise<void>;
|
|
94
|
-
/**
|
|
95
|
-
* `POST /v1/environments/{id}/stop`: suspends a pod Environment. Its volume is kept, and the next
|
|
96
|
-
* turn of a session that names it starts it again. Refused during a turn.
|
|
97
|
-
*/
|
|
98
|
-
export declare function stopEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
99
|
-
/**
|
|
100
|
-
* `POST /v1/environments/{id}/reset`: a new pod on a new, empty volume (the next volume
|
|
101
|
-
* generation), with a new join token and the recipe applied; the old Sandbox and volume are
|
|
102
|
-
* deleted. Leaves `lost` and `failed`. Refused during a turn, and while an earlier reset's
|
|
103
|
-
* Sandbox is still being deleted.
|
|
104
|
-
*/
|
|
105
|
-
export declare function resetEnvironment(ctx: TenantContext, id: string, scope: AuthScope): Promise<EnvironmentView>;
|
|
106
|
-
/**
|
|
107
|
-
* Gives pod Environment `environment` (locked) a new pod on a new, empty volume, the next volume
|
|
108
|
-
* generation, with its recipe applied: the old Sandbox and volume are retired. With `seed`, the
|
|
109
|
-
* new volume starts from that disk version before any turn (R2d step 3): a restore, or the
|
|
110
|
-
* recovery of a lost volume.
|
|
111
|
-
*/
|
|
112
|
-
export declare function newVolume(ctx: TenantContext, t: Tx, environment: Environment, options?: {
|
|
113
|
-
seed?: {
|
|
114
|
-
artifactId: string;
|
|
115
|
-
version: number;
|
|
116
|
-
};
|
|
117
|
-
reason?: "restore" | "lost";
|
|
118
|
-
}): Promise<number>;
|
|
119
|
-
/** How long a pending seed holds the disk before another process may take it over. */
|
|
120
|
-
export declare const SEED_LEASE_MS: number;
|
|
121
|
-
/** `GET /v1/environments/{id}/events`: the Environment's lifecycle stream. */
|
|
122
|
-
export declare function environmentEventsOf(ctx: TenantContext, id: string, scope: AuthScope, query?: EnvironmentEventsQuery): Promise<{
|
|
123
|
-
events: {
|
|
124
|
-
schema: "nylorun.environment-event/1";
|
|
125
|
-
eventId: string;
|
|
126
|
-
tenantId: string;
|
|
127
|
-
environmentId: string;
|
|
128
|
-
seq: number;
|
|
129
|
-
time: string;
|
|
130
|
-
type: "environment.attached" | "environment.created" | "environment.deleted" | "environment.detached" | "environment.egress" | "environment.failed" | "environment.forked" | "environment.lost" | "environment.relaunched" | "environment.reset" | "environment.running" | "environment.suspended";
|
|
131
|
-
payload: Record<string, unknown>;
|
|
132
|
-
}[];
|
|
133
|
-
}>;
|
|
134
|
-
/**
|
|
135
|
-
* Opens a new session on Environment `id` (`PutSessionRequest.environment`): it must exist, be
|
|
136
|
-
* reachable with `grants` and pass its owner guard. Runs in the session's transaction, after
|
|
137
|
-
* its session row lock; holds the Environment's row lock.
|
|
138
|
-
*/
|
|
139
|
-
export declare function openEnvironment(t: Tx, id: string, options: {
|
|
140
|
-
grants?: readonly string[];
|
|
141
|
-
ownerUserId: string;
|
|
142
|
-
opaque: boolean;
|
|
143
|
-
}): Promise<Environment>;
|
|
144
|
-
/** Records the attachment on the session's log and on the Environment's stream. */
|
|
145
|
-
export declare function recordAttachment(t: Tx, sessionId: string, environmentId: string): Promise<void>;
|
|
146
|
-
/**
|
|
147
|
-
* Checks a turn start on a session that names an Environment, in the command's transaction
|
|
148
|
-
* after the session row lock: the Environment still exists, a token caller's grants reach it,
|
|
149
|
-
* its owner guard admits the session's owner, and no disk copy holds it. Other sessions' turns
|
|
150
|
-
* do not stop it (D66). Holds the Environment row's lock until the transaction ends, so a turn
|
|
151
|
-
* start and disk work on one Environment are decided one after the other.
|
|
152
|
-
*
|
|
153
|
-
* A pod Environment must also be usable: not lost (`environment_lost`), on a Runtime with
|
|
154
|
-
* sandbox pods (`environment_unavailable`). A stopped or failed pod is asked to run again, with
|
|
155
|
-
* its recipe applied, after the commit.
|
|
156
|
-
*/
|
|
157
|
-
export declare function checkEnvironmentTurn(t: Tx, session: Session, scope: AuthScope, ctx?: TenantContext): Promise<void>;
|
|
158
|
-
/** A sessions reset detaches every session from its Environment: each one's stream says so. */
|
|
159
|
-
export declare function detachAllSessions(t: Tx): Promise<void>;
|
|
160
|
-
/**
|
|
161
|
-
* Marks the end of a turn's segment on Environment `id`: it was used now (`deleteAfter` counts
|
|
162
|
-
* from here), and for a running pod idle counts from now and the idle timer is armed (D34).
|
|
163
|
-
* Best effort.
|
|
164
|
-
*/
|
|
165
|
-
export declare function touchEnvironment(ctx: TenantContext, id: string): Promise<void>;
|
|
166
|
-
/**
|
|
167
|
-
* Re-arms the idle timer of every running pod after the Tenant's settings change, so a shorter
|
|
168
|
-
* `limits.idle` applies to pods already idle (D36: the settings are read whenever a timer is
|
|
169
|
-
* set). Best effort.
|
|
170
|
-
*/
|
|
171
|
-
export declare function rearmPodTimers(ctx: TenantContext): Promise<void>;
|
|
172
|
-
/** Session lookups for the sandbox route handlers (`core/sandbox-routes.ts`). */
|
|
173
|
-
export declare function sandboxRouteDeps(ctx: TenantContext): SandboxRouteDeps;
|
|
174
|
-
export {};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The skill tools (track R2 M4): `load_skill` and `read_skill_resource`, which the Runtime pins
|
|
3
|
-
* in the `runtime` block of an agent with skills. The Runtime runs them itself, like `save_artifact`, from the
|
|
4
|
-
* definition files uploaded with the agent: no developer process is involved.
|
|
5
|
-
*
|
|
6
|
-
* - `load_skill`: the skill's instructions (its `SKILL.md` after the frontmatter), the paths of
|
|
7
|
-
* its other files, and, when the session has a sandbox, where they are in it
|
|
8
|
-
* (`/skills/<name>@<hash>/`, read-only, D66).
|
|
9
|
-
* - `read_skill_resource`: one text file of the skill. A binary file is refused: the model reads
|
|
10
|
-
* it in the sandbox, when there is one.
|
|
11
|
-
*
|
|
12
|
-
* Expected problems are failed outcomes the model sees; only infrastructure errors throw.
|
|
13
|
-
*/
|
|
14
|
-
import type { SandboxToolOutcome } from "@nylorun/core/contracts";
|
|
15
|
-
import { type AgentManifest } from "@nylorun/core/define";
|
|
16
|
-
import type { HostEffect } from "@nylorun/harness/run";
|
|
17
|
-
import type { TenantContext } from "./context.js";
|
|
18
|
-
/** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
|
|
19
|
-
export declare function isSkillToolCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
|
|
20
|
-
export declare function callSkillTool(ctx: TenantContext, manifest: AgentManifest, request: HostEffect, signal: AbortSignal): Promise<SandboxToolOutcome>;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { LOAD_SKILL_TOOL, SKILL_ENTRY, skillFolderOf, isSkillTool, skillInstructions, } from "@nylorun/core/define";
|
|
2
|
-
import { sandboxToolSpec } from "../sandbox/runtime-tools.js";
|
|
3
|
-
import { readDefinitionFile } from "./definition-files.js";
|
|
4
|
-
const failed = (code, message) => ({ kind: "failed", code, message });
|
|
5
|
-
/** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
|
|
6
|
-
export function isSkillToolCall(manifest, request) {
|
|
7
|
-
return request.kind === "tool" && isSkillTool(manifest, request.toolName);
|
|
8
|
-
}
|
|
9
|
-
/** Every skill of the agent, by name. */
|
|
10
|
-
function skillsOf(manifest) {
|
|
11
|
-
return new Map(Object.values(manifest.skills ?? {}).map((skill) => [skill.name, skill]));
|
|
12
|
-
}
|
|
13
|
-
/** UTF-8 text, or undefined for bytes that are not (a NUL byte, or invalid UTF-8). */
|
|
14
|
-
function textOf(bytes) {
|
|
15
|
-
if (bytes.includes(0))
|
|
16
|
-
return undefined;
|
|
17
|
-
try {
|
|
18
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export async function callSkillTool(ctx, manifest, request, signal) {
|
|
25
|
-
const input = (request.input ?? {});
|
|
26
|
-
const skills = skillsOf(manifest);
|
|
27
|
-
const name = typeof input.name === "string" ? input.name : "";
|
|
28
|
-
const skill = skills.get(name);
|
|
29
|
-
if (!skill)
|
|
30
|
-
return request.toolName === LOAD_SKILL_TOOL
|
|
31
|
-
? { kind: "completed", output: { unknown: name, available: [...skills.keys()].sort() } }
|
|
32
|
-
: failed("skill.unknown", `There is no skill '${name}'.`);
|
|
33
|
-
const sandboxed = sandboxToolSpec(manifest, "bash") !== undefined;
|
|
34
|
-
const directory = `${skillFolderOf(skill)}/`;
|
|
35
|
-
const read = async (path) => {
|
|
36
|
-
const bytes = await readDefinitionFile(ctx.blobs, skill.files[path], signal);
|
|
37
|
-
if (!bytes)
|
|
38
|
-
throw new Error(`The bytes of ${skill.files[path]} (${skill.name}/${path}) are missing from the Object store`);
|
|
39
|
-
return bytes;
|
|
40
|
-
};
|
|
41
|
-
if (request.toolName === LOAD_SKILL_TOOL) {
|
|
42
|
-
const text = textOf(await read(SKILL_ENTRY));
|
|
43
|
-
if (text === undefined)
|
|
44
|
-
return failed("skill.binary_resource", `${SKILL_ENTRY} of '${skill.name}' is not text.`);
|
|
45
|
-
const resources = Object.keys(skill.files)
|
|
46
|
-
.filter((path) => path !== SKILL_ENTRY)
|
|
47
|
-
.sort();
|
|
48
|
-
return {
|
|
49
|
-
kind: "completed",
|
|
50
|
-
output: {
|
|
51
|
-
name: skill.name,
|
|
52
|
-
content: skillInstructions(text),
|
|
53
|
-
...(resources.length === 0 ? {} : { resources }),
|
|
54
|
-
...(sandboxed ? { sandboxPath: directory } : {}),
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
const path = typeof input.path === "string" ? input.path : "";
|
|
59
|
-
if (skill.files[path] === undefined)
|
|
60
|
-
return failed("skill.unknown_resource", `Skill '${skill.name}' has no resource '${path}'.`);
|
|
61
|
-
const content = textOf(await read(path));
|
|
62
|
-
if (content === undefined)
|
|
63
|
-
return failed("skill.binary_resource", sandboxed
|
|
64
|
-
? `${path} is not a text file. It is in the sandbox at ${directory}${path}; use it there.`
|
|
65
|
-
: `${path} is not a text file; only text files can be read without a sandbox.`);
|
|
66
|
-
return { kind: "completed", output: { name: skill.name, path, content } };
|
|
67
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { HostEffect } from "@nylorun/harness/run";
|
|
2
|
-
import type { TenantContext } from "./context.js";
|
|
3
|
-
/** The most of one tool result that is recorded inline (Q22): 32 KiB, as JSON. */
|
|
4
|
-
export declare const TOOL_RESULT_INLINE_BYTES: number;
|
|
5
|
-
/** How much of a stored result's start, and of its end, the preview keeps. */
|
|
6
|
-
export declare const PREVIEW_HEAD_BYTES: number;
|
|
7
|
-
export declare const PREVIEW_TAIL_BYTES = 1024;
|
|
8
|
-
/**
|
|
9
|
-
* The most one step's results may hold together: a step's results are one transcript entry, so
|
|
10
|
-
* one event, which must stay well under S2's 1 MiB record.
|
|
11
|
-
*/
|
|
12
|
-
export declare const STEP_RESULTS_BUDGET_BYTES: number;
|
|
13
|
-
/** A result's cap once its step's budget is spent: a stub naming its artifact. */
|
|
14
|
-
export declare const TOOL_RESULT_STUB_BYTES = 512;
|
|
15
|
-
/** A result this small is never shaped, nor counted against its step's budget. */
|
|
16
|
-
export declare const TOOL_RESULT_SMALL_BYTES = 1024;
|
|
17
|
-
/** The call whose outcome is shaped, and the session its artifacts belong to. */
|
|
18
|
-
export interface ShapedCall {
|
|
19
|
-
readonly request: HostEffect;
|
|
20
|
-
readonly session: {
|
|
21
|
-
readonly id: string;
|
|
22
|
-
readonly ownerUserId: string;
|
|
23
|
-
};
|
|
24
|
-
/** A remote MCP tool's: its output may be the server's content parts. */
|
|
25
|
-
readonly mcp: boolean;
|
|
26
|
-
/** This result's cap (`resultLimit`). Default `TOOL_RESULT_INLINE_BYTES`. */
|
|
27
|
-
readonly limit?: number;
|
|
28
|
-
}
|
|
29
|
-
/** A result's cap when the other results of its step already took `used` bytes. */
|
|
30
|
-
export declare function resultLimit(used: number): number;
|
|
31
|
-
/** The JSON size of `value` in bytes: what it adds to an event or a prompt. */
|
|
32
|
-
export declare function jsonBytes(value: unknown): number;
|
|
33
|
-
/**
|
|
34
|
-
* What a tool outcome's result weighs in its step's transcript entry: a completed one's output,
|
|
35
|
-
* a failed one's message; 0 for anything else, such as a model call's outcome.
|
|
36
|
-
*/
|
|
37
|
-
export declare function resultBytes(value: unknown): number;
|
|
38
|
-
/**
|
|
39
|
-
* False for an outcome `shapeToolOutcome` returns as it is, whatever made it: a model call's, a
|
|
40
|
-
* small tool result with no parts. Spares a look at the effect for most outcomes.
|
|
41
|
-
*/
|
|
42
|
-
export declare function mayNeedShaping(value: unknown): boolean;
|
|
43
|
-
/**
|
|
44
|
-
* The outcome `value` of `call`, shaped to fit its cap (see the module comment). An outcome that
|
|
45
|
-
* fits and has no binary part comes back as it is.
|
|
46
|
-
*/
|
|
47
|
-
export declare function shapeToolOutcome(ctx: TenantContext, call: ShapedCall, value: unknown, signal: AbortSignal): Promise<unknown>;
|
|
48
|
-
/**
|
|
49
|
-
* The start and end of `text` in whole characters, `budget` bytes split four to one: by default
|
|
50
|
-
* the first `PREVIEW_HEAD_BYTES` and the last `PREVIEW_TAIL_BYTES`.
|
|
51
|
-
*/
|
|
52
|
-
export declare function previewOf(text: string, budget?: number): string;
|
|
53
|
-
/**
|
|
54
|
-
* The nearest character boundary of the UTF-8 `bytes` at or before (`down`) or at or after
|
|
55
|
-
* (`up`) byte `at`: never inside a character.
|
|
56
|
-
*/
|
|
57
|
-
export declare function utf8Boundary(bytes: Uint8Array, at: number, direction: "down" | "up"): number;
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool results that fit (R2b C11, Q22–Q24): core shapes what an agent's remote MCP tool or HTTP
|
|
3
|
-
* tool returned before it records the outcome (`harness-api/record.ts`), so no journal row,
|
|
4
|
-
* event or prompt holds more of one result than the inline cap. The gate already refused an
|
|
5
|
-
* answer past 8 MiB (`mcp.too-large`, `http.too-large`).
|
|
6
|
-
*
|
|
7
|
-
* - An `image`, `audio` or blob `resource` part becomes a file artifact of the session, and the
|
|
8
|
-
* part says `{artifactId, version, contentType, size}`. An image also goes to the model as a
|
|
9
|
-
* file (`ToolOutcome.files`), which the model call shows to a model that reads images (Q23).
|
|
10
|
-
* - Text or JSON past `TOOL_RESULT_INLINE_BYTES` (32 KiB, Q22) becomes a file artifact, and the
|
|
11
|
-
* model gets `{truncated: true, artifactId, size, preview}`: the first 4 KiB and the last 1 KiB.
|
|
12
|
-
* In a result of several parts each part is shaped alone, the largest text first, until the
|
|
13
|
-
* whole fits; one that still does not is stored whole.
|
|
14
|
-
* - A `resource_link` stays a link, never fetched, and a text resource that fits stays inline.
|
|
15
|
-
* - A failed outcome's message is cut to its start and end.
|
|
16
|
-
* - When an artifact cannot be stored (the Tenant's artifact limits, an Object store that
|
|
17
|
-
* fails), the preview stays and `dropped` says why the rest is gone: a result never passes
|
|
18
|
-
* the cap. Only an abort throws.
|
|
19
|
-
* - **One step's results share a budget** (`STEP_RESULTS_BUDGET_BYTES`, 256 KiB), since the
|
|
20
|
-
* transcript keeps a step's results in one entry, one event: the record seam counts what the
|
|
21
|
-
* step's other results took, under the session lock, and gives this one the rest as its cap
|
|
22
|
-
* (`resultLimit`). Once the budget is spent, a result past `TOOL_RESULT_SMALL_BYTES` becomes a
|
|
23
|
-
* stub naming its artifact, its preview cut to fit `TOOL_RESULT_STUB_BYTES`.
|
|
24
|
-
*
|
|
25
|
-
* The model reads a stored result with `read_artifact` (`artifact-tool.ts`). Artifacts are the
|
|
26
|
-
* session's, saved by our engine (`source: "engine"`), with the turn and the tool call on their
|
|
27
|
-
* `artifact.created` event.
|
|
28
|
-
*/
|
|
29
|
-
import { READ_ARTIFACT_MAX_BYTES } from "@nylorun/core/define";
|
|
30
|
-
import { MODEL_FILE_MAX_BYTES, extensionFor, isModelImage, isText, normalizeContentType, } from "../artifacts/media-types.js";
|
|
31
|
-
import { uploadArtifact } from "../artifacts/service.js";
|
|
32
|
-
import { DEFAULT_CONTENT_TYPE } from "../blob/index.js";
|
|
33
|
-
import { HttpError } from "./http.js";
|
|
34
|
-
import { toolIds } from "./transcript.js";
|
|
35
|
-
/** The most of one tool result that is recorded inline (Q22): 32 KiB, as JSON. */
|
|
36
|
-
export const TOOL_RESULT_INLINE_BYTES = READ_ARTIFACT_MAX_BYTES;
|
|
37
|
-
/** How much of a stored result's start, and of its end, the preview keeps. */
|
|
38
|
-
export const PREVIEW_HEAD_BYTES = 4 * 1024;
|
|
39
|
-
export const PREVIEW_TAIL_BYTES = 1024;
|
|
40
|
-
/**
|
|
41
|
-
* The most one step's results may hold together: a step's results are one transcript entry, so
|
|
42
|
-
* one event, which must stay well under S2's 1 MiB record.
|
|
43
|
-
*/
|
|
44
|
-
export const STEP_RESULTS_BUDGET_BYTES = 256 * 1024;
|
|
45
|
-
/** A result's cap once its step's budget is spent: a stub naming its artifact. */
|
|
46
|
-
export const TOOL_RESULT_STUB_BYTES = 512;
|
|
47
|
-
/** A result this small is never shaped, nor counted against its step's budget. */
|
|
48
|
-
export const TOOL_RESULT_SMALL_BYTES = 1024;
|
|
49
|
-
/** A result's cap when the other results of its step already took `used` bytes. */
|
|
50
|
-
export function resultLimit(used) {
|
|
51
|
-
return Math.max(TOOL_RESULT_STUB_BYTES, Math.min(TOOL_RESULT_INLINE_BYTES, STEP_RESULTS_BUDGET_BYTES - used));
|
|
52
|
-
}
|
|
53
|
-
/** The JSON size of `value` in bytes: what it adds to an event or a prompt. */
|
|
54
|
-
export function jsonBytes(value) {
|
|
55
|
-
return Buffer.byteLength(JSON.stringify(value) ?? "null");
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* What a tool outcome's result weighs in its step's transcript entry: a completed one's output,
|
|
59
|
-
* a failed one's message; 0 for anything else, such as a model call's outcome.
|
|
60
|
-
*/
|
|
61
|
-
export function resultBytes(value) {
|
|
62
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
63
|
-
return 0;
|
|
64
|
-
const outcome = value;
|
|
65
|
-
if (outcome.kind === "failed")
|
|
66
|
-
return typeof outcome.message === "string" ? Buffer.byteLength(outcome.message) : 0;
|
|
67
|
-
if (outcome.kind !== "completed" || outcome.output === undefined)
|
|
68
|
-
return 0;
|
|
69
|
-
return jsonBytes(outcome.output);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* False for an outcome `shapeToolOutcome` returns as it is, whatever made it: a model call's, a
|
|
73
|
-
* small tool result with no parts. Spares a look at the effect for most outcomes.
|
|
74
|
-
*/
|
|
75
|
-
export function mayNeedShaping(value) {
|
|
76
|
-
const output = value?.output;
|
|
77
|
-
if (value?.kind === "completed" && Array.isArray(output))
|
|
78
|
-
return true;
|
|
79
|
-
return resultBytes(value) > TOOL_RESULT_SMALL_BYTES;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* The outcome `value` of `call`, shaped to fit its cap (see the module comment). An outcome that
|
|
83
|
-
* fits and has no binary part comes back as it is.
|
|
84
|
-
*/
|
|
85
|
-
export async function shapeToolOutcome(ctx, call, value, signal) {
|
|
86
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
87
|
-
return value;
|
|
88
|
-
const outcome = value;
|
|
89
|
-
const limit = call.limit ?? TOOL_RESULT_INLINE_BYTES;
|
|
90
|
-
if (outcome.kind === "failed" && typeof outcome.message === "string")
|
|
91
|
-
return Buffer.byteLength(outcome.message) > limit
|
|
92
|
-
? { ...outcome, message: cutMessage(outcome.message, limit) }
|
|
93
|
-
: value;
|
|
94
|
-
if (outcome.kind !== "completed" || outcome.output === undefined)
|
|
95
|
-
return value;
|
|
96
|
-
const shaping = { ...call, limit, ctx, signal, files: [] };
|
|
97
|
-
let output = outcome.output;
|
|
98
|
-
if (call.mcp && isContentParts(output))
|
|
99
|
-
output = await shapeParts(shaping, output);
|
|
100
|
-
let truncated = false;
|
|
101
|
-
if (jsonBytes(output) > limit) {
|
|
102
|
-
output = await storedWhole(shaping, output);
|
|
103
|
-
truncated = true;
|
|
104
|
-
}
|
|
105
|
-
if (output === outcome.output)
|
|
106
|
-
return value;
|
|
107
|
-
return {
|
|
108
|
-
...outcome,
|
|
109
|
-
output,
|
|
110
|
-
...(shaping.files.length > 0 ? { files: shaping.files } : {}),
|
|
111
|
-
...(truncated ? { truncated: true } : {}),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
/** True for an MCP `content` array: objects with a `type` each. */
|
|
115
|
-
function isContentParts(value) {
|
|
116
|
-
return (Array.isArray(value) &&
|
|
117
|
-
value.length > 0 &&
|
|
118
|
-
value.every((part) => !!part &&
|
|
119
|
-
typeof part === "object" &&
|
|
120
|
-
!Array.isArray(part) &&
|
|
121
|
-
typeof part.type === "string"));
|
|
122
|
-
}
|
|
123
|
-
/** An MCP result's parts: binary ones stored, then the largest text ones until the whole fits. */
|
|
124
|
-
async function shapeParts(shaping, parts) {
|
|
125
|
-
const shaped = [];
|
|
126
|
-
for (const [index, part] of parts.entries())
|
|
127
|
-
shaped.push(await shapeBinary(shaping, part, index));
|
|
128
|
-
const texts = shaped
|
|
129
|
-
.map((part, index) => ({ index, bytes: textOf(part) === undefined ? 0 : jsonBytes(part) }))
|
|
130
|
-
.filter((item) => item.bytes > 0)
|
|
131
|
-
.sort((a, b) => b.bytes - a.bytes);
|
|
132
|
-
for (const { index } of texts) {
|
|
133
|
-
if (jsonBytes(shaped) <= shaping.limit)
|
|
134
|
-
break;
|
|
135
|
-
const part = shaped[index];
|
|
136
|
-
const text = textOf(part);
|
|
137
|
-
const resource = part.type === "resource" ? part.resource : undefined;
|
|
138
|
-
const contentType = resource ? textType(resource.mimeType) : "text/plain; charset=utf-8";
|
|
139
|
-
const kept = await store(shaping, text, contentType, nameOf(shaping, contentType, index));
|
|
140
|
-
shaped[index] = withPreview({
|
|
141
|
-
type: part.type,
|
|
142
|
-
...(resource && typeof resource.uri === "string" ? { uri: resource.uri } : {}),
|
|
143
|
-
truncated: true,
|
|
144
|
-
...kept,
|
|
145
|
-
}, text, shaping.limit);
|
|
146
|
-
}
|
|
147
|
-
return shaped;
|
|
148
|
-
}
|
|
149
|
-
/** An `image`, `audio` or blob `resource` part, stored; any other part as it is. */
|
|
150
|
-
async function shapeBinary(shaping, part, index) {
|
|
151
|
-
const resource = part.type === "resource" && part.resource && typeof part.resource === "object"
|
|
152
|
-
? part.resource
|
|
153
|
-
: undefined;
|
|
154
|
-
const data = part.type === "image" || part.type === "audio"
|
|
155
|
-
? part.data
|
|
156
|
-
: resource !== undefined
|
|
157
|
-
? resource.blob
|
|
158
|
-
: undefined;
|
|
159
|
-
if (typeof data !== "string")
|
|
160
|
-
return part;
|
|
161
|
-
const declared = resource ? resource.mimeType : part.mimeType;
|
|
162
|
-
const contentType = (typeof declared === "string" ? normalizeContentType(declared) : undefined) ??
|
|
163
|
-
DEFAULT_CONTENT_TYPE;
|
|
164
|
-
const name = nameOf(shaping, contentType, index);
|
|
165
|
-
const kept = await store(shaping, Buffer.from(data, "base64"), contentType, name);
|
|
166
|
-
// An image the model reads goes to it as a file, beside the part (Q23).
|
|
167
|
-
if (part.type === "image" &&
|
|
168
|
-
"artifactId" in kept &&
|
|
169
|
-
isModelImage(contentType) &&
|
|
170
|
-
kept.size <= MODEL_FILE_MAX_BYTES)
|
|
171
|
-
shaping.files.push({
|
|
172
|
-
mediaType: contentType,
|
|
173
|
-
reference: { artifactId: kept.artifactId, version: kept.version, name, size: kept.size },
|
|
174
|
-
});
|
|
175
|
-
return {
|
|
176
|
-
type: part.type,
|
|
177
|
-
...(resource && typeof resource.uri === "string" ? { uri: resource.uri } : {}),
|
|
178
|
-
...("artifactId" in kept ? kept : { contentType, ...kept }),
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
/** The text a part carries inline: a text part's, or a text resource's. */
|
|
182
|
-
function textOf(part) {
|
|
183
|
-
if (part.type === "text" && typeof part.text === "string")
|
|
184
|
-
return part.text;
|
|
185
|
-
if (part.type === "resource" && part.resource && typeof part.resource === "object") {
|
|
186
|
-
const text = part.resource.text;
|
|
187
|
-
if (typeof text === "string")
|
|
188
|
-
return text;
|
|
189
|
-
}
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
192
|
-
function textType(declared) {
|
|
193
|
-
const type = typeof declared === "string" ? normalizeContentType(declared) : undefined;
|
|
194
|
-
return type !== undefined && isText(type) ? type : "text/plain; charset=utf-8";
|
|
195
|
-
}
|
|
196
|
-
/** `value` stored whole, as text or JSON, and the preview the model gets. */
|
|
197
|
-
async function storedWhole(shaping, value) {
|
|
198
|
-
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
199
|
-
const contentType = typeof value === "string" ? "text/plain; charset=utf-8" : "application/json";
|
|
200
|
-
const kept = await store(shaping, text, contentType, nameOf(shaping, contentType));
|
|
201
|
-
return withPreview({ truncated: true, ...kept }, text, shaping.limit);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* `stub` with the preview of `text`: the first 4 KiB and the last 1 KiB, or less, so that the
|
|
205
|
-
* whole fits `limit` (a step's budget spent, R2b C11); none when even a little does not.
|
|
206
|
-
*/
|
|
207
|
-
function withPreview(stub, text, limit) {
|
|
208
|
-
let budget = Math.min(PREVIEW_HEAD_BYTES + PREVIEW_TAIL_BYTES, limit);
|
|
209
|
-
for (;;) {
|
|
210
|
-
const shaped = { ...stub, preview: previewOf(text, budget) };
|
|
211
|
-
const over = jsonBytes(shaped) - limit;
|
|
212
|
-
if (over <= 0 || budget === 0)
|
|
213
|
-
return shaped;
|
|
214
|
-
budget = budget - over < 64 ? 0 : budget - over;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/** Stores `body` as an artifact of the call's session, or says why it was not. */
|
|
218
|
-
async function store(shaping, body, contentType, name) {
|
|
219
|
-
const bytes = typeof body === "string" ? Buffer.from(body, "utf8") : body;
|
|
220
|
-
const { ctx, request, session, signal } = shaping;
|
|
221
|
-
const ids = toolIds(request.context);
|
|
222
|
-
try {
|
|
223
|
-
const saved = await uploadArtifact(ctx, {
|
|
224
|
-
name,
|
|
225
|
-
contentType,
|
|
226
|
-
sessionId: session.id,
|
|
227
|
-
source: "engine",
|
|
228
|
-
turnId: request.turnId,
|
|
229
|
-
...("callId" in ids ? { callId: ids.callId } : {}),
|
|
230
|
-
}, bytes,
|
|
231
|
-
// Into the call's own session only.
|
|
232
|
-
{ owner: session.ownerUserId }, signal);
|
|
233
|
-
return {
|
|
234
|
-
artifactId: saved.artifact.artifactId,
|
|
235
|
-
version: saved.version.version,
|
|
236
|
-
contentType: saved.version.contentType,
|
|
237
|
-
size: saved.version.size,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
catch (error) {
|
|
241
|
-
if (signal.aborted)
|
|
242
|
-
throw error;
|
|
243
|
-
// A limit is the Tenant's to raise; any other failure is the store's. Never the bytes.
|
|
244
|
-
ctx.config.logger.warn("tool_result_not_stored", {
|
|
245
|
-
session: session.id,
|
|
246
|
-
effect: request.effectId,
|
|
247
|
-
error: error instanceof Error ? error.message : String(error),
|
|
248
|
-
});
|
|
249
|
-
return {
|
|
250
|
-
dropped: error instanceof HttpError
|
|
251
|
-
? `The result could not be stored as an artifact: ${error.message}`
|
|
252
|
-
: "The result could not be stored as an artifact",
|
|
253
|
-
size: bytes.byteLength,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/** A name for a stored result: the tool's, with the part's number and the type's extension. */
|
|
258
|
-
function nameOf(shaping, contentType, index) {
|
|
259
|
-
const tool = (shaping.request.toolName ?? "tool").replace(/[^A-Za-z0-9_.-]/gu, "_");
|
|
260
|
-
const extension = extensionFor(contentType) ?? "bin";
|
|
261
|
-
return `${tool.slice(0, 200)}-result${index === undefined ? "" : `-${index + 1}`}.${extension}`;
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* The start and end of `text` in whole characters, `budget` bytes split four to one: by default
|
|
265
|
-
* the first `PREVIEW_HEAD_BYTES` and the last `PREVIEW_TAIL_BYTES`.
|
|
266
|
-
*/
|
|
267
|
-
export function previewOf(text, budget = PREVIEW_HEAD_BYTES + PREVIEW_TAIL_BYTES) {
|
|
268
|
-
const bytes = Buffer.from(text, "utf8");
|
|
269
|
-
if (bytes.byteLength <= budget)
|
|
270
|
-
return text;
|
|
271
|
-
if (budget <= 0)
|
|
272
|
-
return "";
|
|
273
|
-
const tailBytes = Math.floor(budget / 5);
|
|
274
|
-
const head = utf8Boundary(bytes, budget - tailBytes, "down");
|
|
275
|
-
const tail = utf8Boundary(bytes, bytes.byteLength - tailBytes, "up");
|
|
276
|
-
return `${bytes.subarray(0, head).toString("utf8")}\n…\n${bytes.subarray(tail).toString("utf8")}`;
|
|
277
|
-
}
|
|
278
|
-
/** A message past `limit`: its start and end, and how long it was. */
|
|
279
|
-
function cutMessage(message, limit) {
|
|
280
|
-
const note = `\n(The message was ${Buffer.byteLength(message)} bytes; its middle is not shown.)`;
|
|
281
|
-
const budget = Math.min(PREVIEW_HEAD_BYTES + PREVIEW_TAIL_BYTES, limit - note.length - 16);
|
|
282
|
-
return `${previewOf(message, Math.max(0, budget))}${note}`;
|
|
283
|
-
}
|
|
284
|
-
/**
|
|
285
|
-
* The nearest character boundary of the UTF-8 `bytes` at or before (`down`) or at or after
|
|
286
|
-
* (`up`) byte `at`: never inside a character.
|
|
287
|
-
*/
|
|
288
|
-
export function utf8Boundary(bytes, at, direction) {
|
|
289
|
-
let position = Math.max(0, Math.min(at, bytes.byteLength));
|
|
290
|
-
const inside = (index) => index < bytes.byteLength && (bytes[index] & 0xc0) === 0x80;
|
|
291
|
-
if (direction === "down")
|
|
292
|
-
while (position > 0 && inside(position))
|
|
293
|
-
position -= 1;
|
|
294
|
-
else
|
|
295
|
-
while (inside(position))
|
|
296
|
-
position += 1;
|
|
297
|
-
return position;
|
|
298
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { HostEffect } from "@nylorun/harness/run";
|
|
2
|
-
import { type McpSnapshot, type McpToolRecord } from "../mcp/snapshot.js";
|
|
3
|
-
import { type TenantContext } from "./context.js";
|
|
4
|
-
/**
|
|
5
|
-
* True when `request` calls `tool_search`, the session tool an agent gets when the session's
|
|
6
|
-
* pinned snapshot holds deferred tools of its own. The name is reserved: no tool of the agent's
|
|
7
|
-
* own takes it.
|
|
8
|
-
*/
|
|
9
|
-
export declare function isToolSearchCall(snapshot: McpSnapshot | undefined, request: HostEffect): boolean;
|
|
10
|
-
/** Runs `tool_search` for the run's agent. */
|
|
11
|
-
export declare function callToolSearch(ctx: TenantContext, request: HostEffect): Promise<{
|
|
12
|
-
output?: undefined;
|
|
13
|
-
kind: string;
|
|
14
|
-
code: string;
|
|
15
|
-
message: string;
|
|
16
|
-
} | {
|
|
17
|
-
code?: undefined;
|
|
18
|
-
message?: undefined;
|
|
19
|
-
kind: string;
|
|
20
|
-
output: {
|
|
21
|
-
tools: {
|
|
22
|
-
name: string;
|
|
23
|
-
description?: string | undefined;
|
|
24
|
-
inputSchema: import("@nylorun/core/define").JsonObject;
|
|
25
|
-
}[];
|
|
26
|
-
message?: string | undefined;
|
|
27
|
-
};
|
|
28
|
-
}>;
|
|
29
|
-
/**
|
|
30
|
-
* Lower-case words of `text`: `camelCase`, `snake_case` and `kebab-case` split into words, and a
|
|
31
|
-
* plural `s` dropped (`issues` finds `issue`).
|
|
32
|
-
*/
|
|
33
|
-
export declare function tokens(text: string): string[];
|
|
34
|
-
/**
|
|
35
|
-
* The tools that match `query`, best first, by BM25 over each tool's name (counted twice, with
|
|
36
|
-
* the server's own name for it) and description. A tool no word of the query is in is left out;
|
|
37
|
-
* ties keep the snapshot's order.
|
|
38
|
-
*/
|
|
39
|
-
export declare function rank(tools: readonly McpToolRecord[], query: string): McpToolRecord[];
|