@nylorun/runtime 0.17.0-beta → 0.19.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +155 -0
- package/README.md +89 -58
- package/dist/adapters/execution/restate.d.ts +1 -3
- package/dist/adapters/execution/restate.js +4 -31
- package/dist/adapters/replication/pgoutput.js +1 -1
- package/dist/adapters/sandbox/local.js +1 -1
- package/dist/adapters/sandbox/virtual.js +1 -1
- package/dist/api/ag-ui/routes.js +1 -1
- package/dist/api/ag-ui/translate.d.ts +1 -3
- package/dist/api/ag-ui/translate.js +2 -17
- package/dist/api/components.d.ts +4871 -2614
- package/dist/api/components.js +12 -11
- package/dist/api/gate/routes.d.ts +7 -8
- package/dist/api/gate/routes.js +58 -52
- package/dist/api/http/app.d.ts +6 -0
- package/dist/api/http/app.js +18 -14
- package/dist/api/http/define.d.ts +14 -2
- package/dist/api/http/define.js +34 -15
- package/dist/api/http/routes/access.d.ts +3 -3
- package/dist/api/http/routes/access.js +18 -17
- package/dist/api/http/routes/artifacts.js +2 -4
- package/dist/api/http/routes/files.d.ts +8 -0
- package/dist/api/http/routes/files.js +77 -0
- package/dist/api/http/routes/keys.d.ts +10 -0
- package/dist/api/http/routes/keys.js +64 -0
- package/dist/api/http/routes/me.js +5 -2
- package/dist/api/http/routes/reads.d.ts +66 -0
- package/dist/api/http/routes/reads.js +127 -0
- package/dist/api/http/routes/sandboxes.js +7 -4
- package/dist/api/http/routes/sessions.js +25 -8
- package/dist/api/http/routes/tenant.js +15 -18
- package/dist/api/http/routes/vaults.d.ts +10 -9
- package/dist/api/http/routes/vaults.js +27 -23
- package/dist/api/openapi.d.ts +10 -11
- package/dist/api/openapi.js +288 -63
- package/dist/artifacts/links.js +1 -1
- package/dist/core/flow-host.d.ts +44 -23
- package/dist/core/flow-host.js +88 -106
- package/dist/core/provider.d.ts +4 -1
- package/dist/core/provider.js +6 -1
- package/dist/core/sandbox-routes.d.ts +0 -9
- package/dist/core/sandbox-routes.js +2 -21
- package/dist/execution/memory.d.ts +4 -5
- package/dist/execution/memory.js +11 -25
- package/dist/execution/types.d.ts +3 -33
- package/dist/execution/types.js +2 -12
- package/dist/gates/http-tool.d.ts +86 -0
- package/dist/gates/http-tool.js +197 -0
- package/dist/gates/mcp-handler.d.ts +3 -0
- package/dist/gates/mcp-handler.js +1 -3
- package/dist/gates/meter.d.ts +2 -2
- package/dist/gates/meter.js +6 -0
- package/dist/gates/tenant-vaults.d.ts +5 -9
- package/dist/gates/tool-calls.d.ts +7 -15
- package/dist/gates/tool-calls.js +4 -4
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +23 -47
- package/dist/gates/tool-contract.d.ts +27 -39
- package/dist/gates/tool-contract.js +30 -21
- package/dist/gates/tool-gate.d.ts +25 -24
- package/dist/gates/tool-gate.js +11 -7
- package/dist/harness/calls.d.ts +10 -4
- package/dist/harness/calls.js +15 -6
- package/dist/harness/executors.d.ts +1 -1
- package/dist/harness/executors.js +17 -12
- package/dist/harness/main.d.ts +2 -2
- package/dist/harness/main.js +5 -13
- package/dist/harness/service.d.ts +4 -5
- package/dist/harness/service.js +9 -2
- package/dist/harness-api/in-process.js +2 -2
- package/dist/harness-api/record.d.ts +6 -3
- package/dist/harness-api/record.js +65 -72
- package/dist/harness-api/server.d.ts +1 -9
- package/dist/harness-api/server.js +19 -17
- package/dist/harness-api/start.js +1 -5
- package/dist/harness-api/workspace.js +2 -3
- package/dist/harness-api/ws-server.js +1 -1
- package/dist/host/app.d.ts +2 -9
- package/dist/host/app.js +15 -25
- package/dist/host/config-for.d.ts +1 -5
- package/dist/host/config-for.js +0 -3
- package/dist/host/config.d.ts +0 -5
- package/dist/host/create-host.d.ts +3 -33
- package/dist/host/create-host.js +18 -94
- package/dist/host/environment.d.ts +0 -3
- package/dist/host/environment.js +0 -9
- package/dist/host/gates.d.ts +4 -1
- package/dist/host/gates.js +3 -2
- package/dist/host/http.d.ts +1 -2
- package/dist/host/http.js +1 -7
- package/dist/host/index.d.ts +2 -2
- package/dist/host/index.js +2 -2
- package/dist/host/main.js +27 -34
- package/dist/host/operate.d.ts +29 -0
- package/dist/host/operate.js +223 -0
- package/dist/host/stack-config.d.ts +12 -12
- package/dist/host/stack-config.js +5 -32
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/infra/workers.d.ts +1 -1
- package/dist/keys/keys.js +2 -2
- package/dist/management-openapi.json +6491 -0
- package/dist/mcp/connect.d.ts +8 -4
- package/dist/mcp/connect.js +6 -26
- package/dist/mcp/pool.d.ts +5 -9
- package/dist/mcp/pool.js +8 -19
- package/dist/mcp/snapshot.d.ts +8 -2
- package/dist/mcp/snapshot.js +29 -2
- package/dist/media.d.ts +1 -1
- package/dist/media.js +1 -1
- package/dist/model/pi-model.js +3 -0
- package/dist/openapi.json +9372 -17030
- package/dist/reads/access.d.ts +4 -0
- package/dist/reads/access.js +12 -0
- package/dist/reads/cursor.d.ts +11 -0
- package/dist/reads/cursor.js +80 -0
- package/dist/reads/types.d.ts +25 -0
- package/dist/reads/types.js +1 -0
- package/dist/sandbox/manager.d.ts +16 -0
- package/dist/sandbox/manager.js +40 -0
- package/dist/sandbox/session-sandbox.js +13 -3
- package/dist/sandbox/skills.d.ts +13 -0
- package/dist/sandbox/skills.js +46 -0
- package/dist/sandbox/types.d.ts +2 -2
- package/dist/store/ownership.d.ts +9 -0
- package/dist/store/ownership.js +13 -0
- package/dist/store/postgres/connect.d.ts +2 -0
- package/dist/store/postgres/connect.js +29 -0
- package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
- package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
- package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
- package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.d.ts +3 -0
- package/dist/store/postgres/reads.js +272 -0
- package/dist/store/postgres/schema.d.ts +294 -489
- package/dist/store/postgres/schema.js +41 -76
- package/dist/store/postgres/store.js +51 -154
- package/dist/store/postgres/tenant.d.ts +34 -2
- package/dist/store/postgres/tenant.js +16 -32
- package/dist/store/types.d.ts +27 -96
- package/dist/store/types.js +0 -1
- package/dist/streams/control.d.ts +0 -2
- package/dist/streams/control.js +0 -5
- package/dist/streams/types.d.ts +1 -10
- package/dist/tenant/advance.d.ts +3 -3
- package/dist/tenant/advance.js +10 -7
- package/dist/tenant/auth.d.ts +14 -9
- package/dist/tenant/auth.js +24 -28
- package/dist/tenant/cause.d.ts +3 -3
- package/dist/tenant/cause.js +1 -1
- package/dist/tenant/commands.d.ts +2 -18
- package/dist/tenant/commands.js +35 -172
- package/dist/tenant/context.d.ts +14 -24
- package/dist/tenant/definition-files.d.ts +24 -0
- package/dist/tenant/definition-files.js +103 -0
- package/dist/tenant/effects.d.ts +18 -20
- package/dist/tenant/effects.js +56 -119
- package/dist/tenant/ephemeral.d.ts +7 -6
- package/dist/tenant/ephemeral.js +3 -11
- package/dist/tenant/host-token.js +1 -1
- package/dist/tenant/jwt.js +1 -1
- package/dist/tenant/module.d.ts +1 -4
- package/dist/tenant/module.js +3 -12
- package/dist/tenant/operator-keys.d.ts +34 -8
- package/dist/tenant/operator-keys.js +50 -18
- package/dist/tenant/outbound.d.ts +10 -1
- package/dist/tenant/outbound.js +44 -27
- package/dist/tenant/paths.d.ts +1 -1
- package/dist/tenant/paths.js +1 -3
- package/dist/tenant/principals.d.ts +11 -2
- package/dist/tenant/principals.js +27 -8
- package/dist/tenant/run-token.js +3 -3
- package/dist/tenant/runtime.d.ts +4 -6
- package/dist/tenant/runtime.js +19 -18
- package/dist/tenant/sandboxes.d.ts +4 -1
- package/dist/tenant/sandboxes.js +11 -0
- package/dist/tenant/scheduler.d.ts +1 -5
- package/dist/tenant/scheduler.js +2 -5
- package/dist/tenant/session-streams.d.ts +2 -1
- package/dist/tenant/session-streams.js +39 -5
- package/dist/tenant/session.d.ts +8 -41
- package/dist/tenant/session.js +0 -37
- package/dist/tenant/sessions.js +16 -8
- package/dist/tenant/signing-keys.d.ts +3 -3
- package/dist/tenant/signing-keys.js +5 -5
- package/dist/tenant/skill-tool.d.ts +20 -0
- package/dist/tenant/skill-tool.js +72 -0
- package/dist/tenant/slim.d.ts +1 -1
- package/dist/tenant/slim.js +1 -1
- package/dist/tenant/status.js +7 -12
- package/dist/tenant/store-pg.d.ts +15 -0
- package/dist/tenant/store-pg.js +7 -3
- package/dist/tenant/streams.d.ts +3 -10
- package/dist/tenant/streams.js +1 -24
- package/dist/tenant/sweep.js +0 -5
- package/dist/tenant/transcript.d.ts +2 -2
- package/dist/tenant/transcript.js +2 -2
- package/dist/tenant/types.d.ts +15 -22
- package/dist/tenant/worker.d.ts +1 -3
- package/dist/tenant/worker.js +3 -8
- package/dist/vault/sources.d.ts +7 -1
- package/dist/vault/sources.js +22 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/dist/admin-openapi.json +0 -904
- package/dist/api/http/routes/actions.d.ts +0 -8
- package/dist/api/http/routes/actions.js +0 -75
- package/dist/api/http/routes/endpoints.d.ts +0 -7
- package/dist/api/http/routes/endpoints.js +0 -100
- package/dist/host/admin-api.d.ts +0 -30
- package/dist/host/admin-api.js +0 -140
- package/dist/mcp/stdio.d.ts +0 -17
- package/dist/mcp/stdio.js +0 -82
- package/dist/tenant/actions.d.ts +0 -14
- package/dist/tenant/actions.js +0 -29
- package/dist/tenant/delivery-token.d.ts +0 -41
- package/dist/tenant/delivery-token.js +0 -104
- package/dist/tenant/delivery.d.ts +0 -62
- package/dist/tenant/delivery.js +0 -481
- package/dist/tenant/endpoints.d.ts +0 -67
- package/dist/tenant/endpoints.js +0 -90
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The loop's client of the Tool Gate in the gates service (F4.1, `tool-contract.ts`): remote
|
|
3
3
|
* MCP servers opened and called through the gate, which holds their connections and
|
|
4
|
-
* credentials, and
|
|
5
|
-
* client (`http-client.ts`): a call answers only when it
|
|
4
|
+
* credentials, and HTTP tools called by the gate (R2 M3).
|
|
5
|
+
* Over `node:http`, like the model gate's client (`http-client.ts`): a call answers only when it
|
|
6
|
+
* has finished.
|
|
6
7
|
*
|
|
7
8
|
* Failures keep the meaning they had in the loop's own process:
|
|
8
9
|
* - An MCP request that fails, at the server or on the hop, throws, so the pool reports a
|
|
9
|
-
* diagnostic and `resolveEffect` marks a call `uncertain`, as before.
|
|
10
|
-
*
|
|
11
|
-
* (the deliverer sends it again, even a tool); one that failed after is `lost`.
|
|
10
|
+
* diagnostic and `resolveEffect` marks a call `uncertain`, as before. An HTTP tool call
|
|
11
|
+
* throws only for the hop, or a call lost with the gateway: its own failures are outcomes.
|
|
12
12
|
*
|
|
13
13
|
* Credentials (F5): a session's MCP requests and keyed cancels carry its run token, read per
|
|
14
14
|
* request from the advance's grant, and leave the session out of the body: the gate takes it
|
|
15
|
-
* from the token.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* from the token. MCP requests made outside a run (closing a pooled connection after the
|
|
16
|
+
* advance ended) carry core's credential, `NYLORUN_GATES_TOKEN`, and name the session in the
|
|
17
|
+
* body.
|
|
18
18
|
*/
|
|
19
19
|
import { randomUUID } from "node:crypto";
|
|
20
20
|
import { request as httpRequest } from "node:http";
|
|
21
21
|
import { request as httpsRequest } from "node:https";
|
|
22
22
|
import { TENANT_HEADER } from "./contract.js";
|
|
23
23
|
import { GATE_CLIENT_TIMEOUT_MS } from "./http-client.js";
|
|
24
|
-
import {
|
|
24
|
+
import { HTTP_CALLS_PATH, MCP_CLOSE_PATH, MCP_CONNECT_PATH, MCP_LIST_PATH, TOOL_CALLS_PATH, } from "./tool-contract.js";
|
|
25
25
|
/** How long a close or a cancel may take; neither changes an outcome. */
|
|
26
26
|
const SHORT_TIMEOUT_MS = 2_000;
|
|
27
|
-
/** Extra silence allowed on a delivery beyond the endpoint's own timeout. */
|
|
28
|
-
const DELIVERY_SLACK_MS = 30_000;
|
|
29
27
|
export function httpToolGate(options) {
|
|
30
28
|
const where = new URL(options.url).origin;
|
|
31
29
|
const timeoutMs = options.timeoutMs ?? GATE_CLIENT_TIMEOUT_MS;
|
|
@@ -107,8 +105,11 @@ export function httpToolGate(options) {
|
|
|
107
105
|
const { sessionId: _, ...unnamed } = server;
|
|
108
106
|
return { body: body(unnamed), bearer: token };
|
|
109
107
|
}
|
|
110
|
-
/**
|
|
111
|
-
|
|
108
|
+
/**
|
|
109
|
+
* The result of an MCP or HTTP tool request, or a throw the pool and `resolveEffect` read as
|
|
110
|
+
* before: the call's fate is unknown, and the effect becomes `uncertain`.
|
|
111
|
+
*/
|
|
112
|
+
async function answered(path, scope, request) {
|
|
112
113
|
const result = await exchange(path, scope.body, {
|
|
113
114
|
...request,
|
|
114
115
|
timeoutMs,
|
|
@@ -135,13 +136,13 @@ export function httpToolGate(options) {
|
|
|
135
136
|
recovers: true,
|
|
136
137
|
async openMcp(server) {
|
|
137
138
|
// The credential is read per request: the connection outlives the advance that opened it.
|
|
138
|
-
await
|
|
139
|
+
await answered(MCP_CONNECT_PATH, scoped(server, (named) => ({ server: named })), {});
|
|
139
140
|
const client = {
|
|
140
|
-
listTools: (params, request) =>
|
|
141
|
+
listTools: (params, request) => answered(MCP_LIST_PATH, scoped(server, (named) => ({
|
|
141
142
|
server: named,
|
|
142
143
|
...(params?.cursor ? { cursor: params.cursor } : {}),
|
|
143
144
|
})), request?.signal ? { signal: request.signal } : {}),
|
|
144
|
-
callTool: (params, request) =>
|
|
145
|
+
callTool: (params, request) => answered(TOOL_CALLS_PATH, scoped(server, (named) => ({
|
|
145
146
|
server: named,
|
|
146
147
|
effectId: request?.key ?? randomUUID(),
|
|
147
148
|
name: params.name,
|
|
@@ -156,6 +157,12 @@ export function httpToolGate(options) {
|
|
|
156
157
|
close: () => fireAndForget(MCP_CLOSE_PATH, scoped(server, (named) => ({ server: named }))),
|
|
157
158
|
};
|
|
158
159
|
},
|
|
160
|
+
async callHttp(call, signal) {
|
|
161
|
+
const token = options.runTokens?.token(call.tool.sessionId);
|
|
162
|
+
const { sessionId: _, ...unnamed } = call.tool;
|
|
163
|
+
const body = { ...call, tool: token ? unnamed : { ...call.tool } };
|
|
164
|
+
return answered(HTTP_CALLS_PATH, { body, ...(token ? { bearer: token } : {}) }, { signal, idempotencyKey: call.effectId });
|
|
165
|
+
},
|
|
159
166
|
async cancel(request) {
|
|
160
167
|
const token = options.runTokens?.token(request.sessionId);
|
|
161
168
|
await fireAndForget(`${TOOL_CALLS_PATH}/${encodeURIComponent(request.effectId)}/cancel`, {
|
|
@@ -163,37 +170,6 @@ export function httpToolGate(options) {
|
|
|
163
170
|
...(token ? { bearer: token } : {}),
|
|
164
171
|
});
|
|
165
172
|
},
|
|
166
|
-
async post(delivery, signal) {
|
|
167
|
-
const result = await exchange(DELIVERIES_PATH, {
|
|
168
|
-
url: delivery.url,
|
|
169
|
-
body: delivery.body,
|
|
170
|
-
headers: { ...delivery.headers },
|
|
171
|
-
timeoutMs: delivery.timeoutMs,
|
|
172
|
-
}, { signal, timeoutMs: delivery.timeoutMs + DELIVERY_SLACK_MS });
|
|
173
|
-
if (result.kind === "aborted")
|
|
174
|
-
return {
|
|
175
|
-
kind: result.sent ? "lost" : "not_sent",
|
|
176
|
-
code: "ABORTED",
|
|
177
|
-
message: "The delivery was aborted",
|
|
178
|
-
};
|
|
179
|
-
if (result.kind === "unreachable")
|
|
180
|
-
return { kind: "not_sent", code: "gateway.unreachable", message: result.message };
|
|
181
|
-
if (result.kind === "lost")
|
|
182
|
-
return { kind: "lost", code: "gateway.lost", message: result.message };
|
|
183
|
-
const parsed = parse(result.text);
|
|
184
|
-
if (result.status !== 200 || !parsed?.result)
|
|
185
|
-
// The gate refused the request before sending anything.
|
|
186
|
-
return { kind: "not_sent", code: "gateway.refused", message: gateRefusal(result.status, parsed) };
|
|
187
|
-
const wire = parsed.result;
|
|
188
|
-
if (wire.kind !== "response")
|
|
189
|
-
return wire;
|
|
190
|
-
return {
|
|
191
|
-
kind: "response",
|
|
192
|
-
status: wire.status,
|
|
193
|
-
headers: wire.headers,
|
|
194
|
-
body: Buffer.from(wire.body, "base64"),
|
|
195
|
-
};
|
|
196
|
-
},
|
|
197
173
|
};
|
|
198
174
|
}
|
|
199
175
|
/** An MCP failure the gate reported, as the loop's own MCP code would have thrown it. */
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Tool Gate's wire format (blueprint §12, F4.1): the routes the loop calls on the gates
|
|
3
|
-
* service for remote MCP servers and
|
|
3
|
+
* service for remote MCP servers and HTTP tools. Internal, like the model call route
|
|
4
4
|
* (`contract.ts`): same optional Tenant header, not in the published OpenAPI documents.
|
|
5
5
|
*
|
|
6
6
|
* Credentials (F5). A session's MCP requests carry its run token, and the gate takes the
|
|
7
7
|
* session from it: `server.sessionId` is then absent (or the token's). Core's credential
|
|
8
8
|
* (`NYLORUN_GATES_TOKEN`) is accepted too, for requests made outside a run, and then
|
|
9
|
-
* `server.sessionId` names the session.
|
|
9
|
+
* `server.sessionId` names the session.
|
|
10
10
|
*
|
|
11
11
|
* Remote MCP. The gate holds the connection and the vault credential; the loop names the
|
|
12
12
|
* server, never a URL or a credential, and the gate finds it in the session's pinned manifest.
|
|
@@ -23,22 +23,23 @@
|
|
|
23
23
|
* answer, not a gate error. A keyed call whose earlier attempt was lost with the gateway answers
|
|
24
24
|
* `{ok: false, error: {uncertain: true}}` and is never run again.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* HTTP tools (R2 M3). `POST /nylorun/v1/http-calls` `{tool, effectId, turnId, input}`: one call
|
|
27
|
+
* of an HTTP tool. The loop names the tool (`{sessionId?, agentId?, capabilityId, toolName}`), or a
|
|
28
|
+
* flow's HTTP stage or HTTP verifier by its stage key (`{sessionId?, stage}`); the gate finds its
|
|
29
|
+
* URL, method and credential in the session's pinned manifest
|
|
30
|
+
* (`gates/http-tool.ts`). A run token's turn is the call's; `turnId` counts only under core's
|
|
31
|
+
* credential. Keyed like a tool call, and cancelled by the same route. It answers
|
|
32
|
+
* `200 {ok: true, result}` with the tool outcome (a failed request is a failed outcome the
|
|
33
|
+
* model sees), or `{ok: false, error: {uncertain: true}}` for a call lost with the gateway.
|
|
29
34
|
*/
|
|
30
35
|
import { z } from "zod";
|
|
31
36
|
export declare const MCP_CONNECT_PATH = "/nylorun/v1/mcp/connect";
|
|
32
37
|
export declare const MCP_LIST_PATH = "/nylorun/v1/mcp/list";
|
|
33
38
|
export declare const MCP_CLOSE_PATH = "/nylorun/v1/mcp/close";
|
|
34
39
|
export declare const TOOL_CALLS_PATH = "/nylorun/v1/tool-calls";
|
|
35
|
-
export declare const
|
|
36
|
-
/** Largest tool call
|
|
40
|
+
export declare const HTTP_CALLS_PATH = "/nylorun/v1/http-calls";
|
|
41
|
+
/** Largest tool call body the gate reads. */
|
|
37
42
|
export declare const MAX_TOOL_BODY_BYTES: number;
|
|
38
|
-
/** The longest delivery timeout the gate accepts: an endpoint's maximum `timeoutMs`. */
|
|
39
|
-
export declare const MAX_DELIVERY_TIMEOUT_MS: number;
|
|
40
|
-
/** The only headers the gate forwards on a delivery, lower-cased. */
|
|
41
|
-
export declare const DELIVERY_HEADERS: ReadonlySet<string>;
|
|
42
43
|
export declare const McpServerRefSchema: z.ZodObject<{
|
|
43
44
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
44
45
|
agentId: z.ZodOptional<z.ZodString>;
|
|
@@ -74,6 +75,21 @@ export declare const ToolCallBodySchema: z.ZodObject<{
|
|
|
74
75
|
arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
75
76
|
}, z.core.$strip>;
|
|
76
77
|
export type ToolCallBody = z.infer<typeof ToolCallBodySchema>;
|
|
78
|
+
export declare const HttpCallBodySchema: z.ZodObject<{
|
|
79
|
+
tool: z.ZodUnion<readonly [z.ZodObject<{
|
|
80
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
81
|
+
agentId: z.ZodOptional<z.ZodString>;
|
|
82
|
+
capabilityId: z.ZodString;
|
|
83
|
+
toolName: z.ZodString;
|
|
84
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
85
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
86
|
+
stage: z.ZodString;
|
|
87
|
+
}, z.core.$strip>]>;
|
|
88
|
+
effectId: z.ZodString;
|
|
89
|
+
turnId: z.ZodString;
|
|
90
|
+
input: z.ZodUnknown;
|
|
91
|
+
}, z.core.$strip>;
|
|
92
|
+
export type HttpCallBody = z.infer<typeof HttpCallBodySchema>;
|
|
77
93
|
/** Why an MCP request failed, as the loop's diagnostics read it (`mcp/connect.ts`). */
|
|
78
94
|
export interface McpGateError {
|
|
79
95
|
readonly message: string;
|
|
@@ -91,31 +107,3 @@ export type McpAnswer<T> = {
|
|
|
91
107
|
readonly ok: false;
|
|
92
108
|
readonly error: McpGateError;
|
|
93
109
|
};
|
|
94
|
-
export declare const DeliveryBodySchema: z.ZodObject<{
|
|
95
|
-
url: z.ZodString;
|
|
96
|
-
body: z.ZodString;
|
|
97
|
-
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
98
|
-
timeoutMs: z.ZodNumber;
|
|
99
|
-
}, z.core.$strip>;
|
|
100
|
-
export type DeliveryBody = z.infer<typeof DeliveryBodySchema>;
|
|
101
|
-
/** `OutboundResult` on the wire: the answer's body in base64. */
|
|
102
|
-
export type WireOutboundResult = {
|
|
103
|
-
readonly kind: "response";
|
|
104
|
-
readonly status: number;
|
|
105
|
-
readonly headers: Record<string, string | string[] | undefined>;
|
|
106
|
-
readonly body: string;
|
|
107
|
-
} | {
|
|
108
|
-
readonly kind: "too_large";
|
|
109
|
-
readonly status: number;
|
|
110
|
-
} | {
|
|
111
|
-
readonly kind: "not_sent";
|
|
112
|
-
readonly code: string;
|
|
113
|
-
readonly message: string;
|
|
114
|
-
} | {
|
|
115
|
-
readonly kind: "lost";
|
|
116
|
-
readonly code: string;
|
|
117
|
-
readonly message: string;
|
|
118
|
-
};
|
|
119
|
-
export interface DeliveryAnswer {
|
|
120
|
-
readonly result: WireOutboundResult;
|
|
121
|
-
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Tool Gate's wire format (blueprint §12, F4.1): the routes the loop calls on the gates
|
|
3
|
-
* service for remote MCP servers and
|
|
3
|
+
* service for remote MCP servers and HTTP tools. Internal, like the model call route
|
|
4
4
|
* (`contract.ts`): same optional Tenant header, not in the published OpenAPI documents.
|
|
5
5
|
*
|
|
6
6
|
* Credentials (F5). A session's MCP requests carry its run token, and the gate takes the
|
|
7
7
|
* session from it: `server.sessionId` is then absent (or the token's). Core's credential
|
|
8
8
|
* (`NYLORUN_GATES_TOKEN`) is accepted too, for requests made outside a run, and then
|
|
9
|
-
* `server.sessionId` names the session.
|
|
9
|
+
* `server.sessionId` names the session.
|
|
10
10
|
*
|
|
11
11
|
* Remote MCP. The gate holds the connection and the vault credential; the loop names the
|
|
12
12
|
* server, never a URL or a credential, and the gate finds it in the session's pinned manifest.
|
|
@@ -23,27 +23,23 @@
|
|
|
23
23
|
* answer, not a gate error. A keyed call whose earlier attempt was lost with the gateway answers
|
|
24
24
|
* `{ok: false, error: {uncertain: true}}` and is never run again.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* HTTP tools (R2 M3). `POST /nylorun/v1/http-calls` `{tool, effectId, turnId, input}`: one call
|
|
27
|
+
* of an HTTP tool. The loop names the tool (`{sessionId?, agentId?, capabilityId, toolName}`), or a
|
|
28
|
+
* flow's HTTP stage or HTTP verifier by its stage key (`{sessionId?, stage}`); the gate finds its
|
|
29
|
+
* URL, method and credential in the session's pinned manifest
|
|
30
|
+
* (`gates/http-tool.ts`). A run token's turn is the call's; `turnId` counts only under core's
|
|
31
|
+
* credential. Keyed like a tool call, and cancelled by the same route. It answers
|
|
32
|
+
* `200 {ok: true, result}` with the tool outcome (a failed request is a failed outcome the
|
|
33
|
+
* model sees), or `{ok: false, error: {uncertain: true}}` for a call lost with the gateway.
|
|
29
34
|
*/
|
|
30
35
|
import { z } from "zod";
|
|
31
|
-
import { PROTOCOL_HEADER, SIGNATURE_HEADER } from "@nylorun/core/compatibility";
|
|
32
36
|
export const MCP_CONNECT_PATH = "/nylorun/v1/mcp/connect";
|
|
33
37
|
export const MCP_LIST_PATH = "/nylorun/v1/mcp/list";
|
|
34
38
|
export const MCP_CLOSE_PATH = "/nylorun/v1/mcp/close";
|
|
35
39
|
export const TOOL_CALLS_PATH = "/nylorun/v1/tool-calls";
|
|
36
|
-
export const
|
|
37
|
-
/** Largest tool call
|
|
40
|
+
export const HTTP_CALLS_PATH = "/nylorun/v1/http-calls";
|
|
41
|
+
/** Largest tool call body the gate reads. */
|
|
38
42
|
export const MAX_TOOL_BODY_BYTES = 8 * 1024 * 1024;
|
|
39
|
-
/** The longest delivery timeout the gate accepts: an endpoint's maximum `timeoutMs`. */
|
|
40
|
-
export const MAX_DELIVERY_TIMEOUT_MS = 15 * 60_000;
|
|
41
|
-
/** The only headers the gate forwards on a delivery, lower-cased. */
|
|
42
|
-
export const DELIVERY_HEADERS = new Set([
|
|
43
|
-
SIGNATURE_HEADER.toLowerCase(),
|
|
44
|
-
PROTOCOL_HEADER.toLowerCase(),
|
|
45
|
-
"idempotency-key",
|
|
46
|
-
]);
|
|
47
43
|
export const McpServerRefSchema = z.object({
|
|
48
44
|
/** Required with core's credential; a run token names the session itself. */
|
|
49
45
|
sessionId: z.string().min(1).optional(),
|
|
@@ -62,9 +58,22 @@ export const ToolCallBodySchema = z.object({
|
|
|
62
58
|
name: z.string().min(1),
|
|
63
59
|
arguments: z.record(z.string(), z.unknown()),
|
|
64
60
|
});
|
|
65
|
-
export const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
export const HttpCallBodySchema = z.object({
|
|
62
|
+
tool: z.union([
|
|
63
|
+
z.object({
|
|
64
|
+
/** Required with core's credential; a run token names the session itself. */
|
|
65
|
+
sessionId: z.string().min(1).optional(),
|
|
66
|
+
agentId: z.string().min(1).optional(),
|
|
67
|
+
capabilityId: z.string().min(1),
|
|
68
|
+
toolName: z.string().min(1),
|
|
69
|
+
}),
|
|
70
|
+
z.object({
|
|
71
|
+
sessionId: z.string().min(1).optional(),
|
|
72
|
+
/** A flow's HTTP stage or HTTP verifier. */
|
|
73
|
+
stage: z.string().min(1),
|
|
74
|
+
}),
|
|
75
|
+
]),
|
|
76
|
+
effectId: z.string().min(1),
|
|
77
|
+
turnId: z.string().min(1),
|
|
78
|
+
input: z.unknown(),
|
|
70
79
|
});
|
|
@@ -1,46 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Tool Gate seam (blueprint §12, F4.1). Every tool call that leaves the loop crosses one
|
|
3
|
-
* `ToolGate`: a remote MCP server's connection and calls, and
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* `ToolGate`: a remote MCP server's connection and calls, and an HTTP tool's request (R2 M3).
|
|
4
|
+
* The gate owns what those need that the loop must not hold: the MCP and HTTP tool credentials
|
|
5
|
+
* and their OAuth refresh, and the outbound route.
|
|
6
6
|
*
|
|
7
7
|
* Two implementations: `inProcessToolGate` (embedding, the ephemeral Runtime, tests), which
|
|
8
|
-
* opens remote servers and
|
|
9
|
-
* service (`tool-client.ts`, the `gateway` container).
|
|
10
|
-
* never cross it: they run beside the loop until the session sandbox takes them (P4).
|
|
8
|
+
* opens remote servers and calls HTTP tools in this process, and the HTTP client of the gates
|
|
9
|
+
* service (`tool-client.ts`, the `gateway` container). The sandbox tools never cross it.
|
|
11
10
|
*/
|
|
12
11
|
import type { LiveConnection } from "../mcp/connect.js";
|
|
13
12
|
import type { McpServerRef } from "../mcp/pool.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
readonly url: string;
|
|
18
|
-
readonly body: string;
|
|
19
|
-
/** `Nylorun-Signature`, `Nylorun-Protocol` and `Idempotency-Key`; nothing else. */
|
|
20
|
-
readonly headers: Readonly<Record<string, string>>;
|
|
21
|
-
/** How long the endpoint may take to answer. */
|
|
22
|
-
readonly timeoutMs: number;
|
|
23
|
-
}
|
|
13
|
+
import type { OutboundPolicy } from "../tenant/outbound.js";
|
|
14
|
+
import type { Logger } from "../tenant/types.js";
|
|
15
|
+
import { type HttpOutcome, type HttpToolCall, type HttpToolTenant } from "./http-tool.js";
|
|
24
16
|
export interface ToolGate {
|
|
25
17
|
/**
|
|
26
18
|
* Opens a remote (`streamable-http` or `sse`) MCP server of a session. Absent: the loop's
|
|
27
19
|
* pool opens it itself, with the Tenant vault.
|
|
28
20
|
*/
|
|
29
21
|
openMcp?(server: McpServerRef): Promise<LiveConnection>;
|
|
30
|
-
/** POSTs a delivery. Never throws; `signal` aborts it (see `tenant/outbound.ts`). */
|
|
31
|
-
post(request: DeliveryRequest, signal: AbortSignal): Promise<OutboundResult>;
|
|
32
22
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* lost with
|
|
23
|
+
* Calls an HTTP tool of a session (R2 M3), keyed by the call's effect id. A failed request is
|
|
24
|
+
* a failed outcome; it throws only when the call's fate is unknown (the gate was lost, or the
|
|
25
|
+
* call was lost with it) or `signal` aborts. Absent: this Runtime cannot run HTTP tools.
|
|
26
|
+
*/
|
|
27
|
+
callHttp?(call: HttpToolCall, signal: AbortSignal): Promise<HttpOutcome>;
|
|
28
|
+
/**
|
|
29
|
+
* True when a keyed MCP or HTTP tool call outlives the caller's process (the gates service,
|
|
30
|
+
* G3): after a takeover or a shutdown, re-sending it joins the call or returns its outcome,
|
|
31
|
+
* and a call lost with the gateway answers `uncertain` instead of running again.
|
|
36
32
|
*/
|
|
37
33
|
readonly recovers?: boolean;
|
|
38
|
-
/** Stops a keyed
|
|
34
|
+
/** Stops a keyed tool call that outlives its caller (a user cancel). Never rejects. */
|
|
39
35
|
cancel?(request: {
|
|
40
36
|
tenantId: string;
|
|
41
37
|
sessionId: string;
|
|
42
38
|
effectId: string;
|
|
43
39
|
}): Promise<void>;
|
|
44
40
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The Tool Gate in the caller's process: remote MCP through the pool, and HTTP tools with
|
|
43
|
+
* `tenant`'s sessions and vault.
|
|
44
|
+
*/
|
|
45
|
+
export declare function inProcessToolGate(policy?: OutboundPolicy, tenant?: HttpToolTenant & {
|
|
46
|
+
readonly logger?: Logger;
|
|
47
|
+
}): ToolGate;
|
package/dist/gates/tool-gate.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
|
|
1
|
+
import { runHttpTool } from "./http-tool.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Tool Gate in the caller's process: remote MCP through the pool, and HTTP tools with
|
|
4
|
+
* `tenant`'s sessions and vault.
|
|
5
|
+
*/
|
|
6
|
+
export function inProcessToolGate(policy = {}, tenant) {
|
|
4
7
|
return {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
...(tenant
|
|
9
|
+
? {
|
|
10
|
+
callHttp: (call, signal) => runHttpTool(tenant, call, { policy, signal, ...(tenant.logger ? { logger: tenant.logger } : {}) }),
|
|
11
|
+
}
|
|
12
|
+
: {}),
|
|
9
13
|
};
|
|
10
14
|
}
|
package/dist/harness/calls.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The calls a harness executes, as pure helpers over what routes them: the Model Gate (or the
|
|
3
|
-
* Tenant's provider), the MCP pool, the SandboxManager. No store, no record: the
|
|
4
|
-
* routing comes with the run (`TurnStart.routing`).
|
|
3
|
+
* Tenant's provider), the Tool Gate, the MCP pool, the SandboxManager. No store, no record: the
|
|
4
|
+
* session's routing comes with the run (`TurnStart.routing`).
|
|
5
5
|
*/
|
|
6
6
|
import { type AgentManifest } from "@nylorun/core/define";
|
|
7
7
|
import type { HostEffect } from "@nylorun/harness/run";
|
|
8
8
|
import type { AbortReason } from "@nylorun/core/harness-api";
|
|
9
9
|
import type { ModelProvider } from "../core/provider.js";
|
|
10
10
|
import type { ModelGate } from "../gates/model-gate.js";
|
|
11
|
+
import type { ToolGate } from "../gates/tool-gate.js";
|
|
11
12
|
import { type McpPool } from "../mcp/pool.js";
|
|
12
13
|
import { type McpSnapshot } from "../mcp/snapshot.js";
|
|
13
14
|
import type { SandboxManager } from "../sandbox/manager.js";
|
|
@@ -22,7 +23,6 @@ export interface ModelRoute {
|
|
|
22
23
|
/** What a session's tool calls are routed by. */
|
|
23
24
|
export interface ToolRouting {
|
|
24
25
|
readonly rootManifest: AgentManifest;
|
|
25
|
-
readonly pluginRoots: Readonly<Record<string, string>>;
|
|
26
26
|
readonly mcpSnapshot?: McpSnapshot;
|
|
27
27
|
/** The session that owns the tree's sandbox, and the sandbox resource it is attached to. */
|
|
28
28
|
readonly sandboxOwnerId: string;
|
|
@@ -46,7 +46,13 @@ export declare function invokeModel(route: ModelRoute, request: HostEffect, sign
|
|
|
46
46
|
export declare function abortOn(signal: AbortSignal, kinds: readonly AbortReason[]): AbortSignal;
|
|
47
47
|
/** True when `request` calls `save_artifact` of the `nylorun.artifacts` capability `manifest` has. */
|
|
48
48
|
export declare function isSaveArtifactCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
|
|
49
|
-
/** True when `request` calls a tool of a
|
|
49
|
+
/** True when `request` calls a tool of a declared MCP server (every one is remote). */
|
|
50
50
|
export declare function isRemoteMcpCall(routing: Pick<ToolRouting, "rootManifest" | "mcpSnapshot">, request: HostEffect): boolean;
|
|
51
51
|
export declare function callMcpTool(mcp: McpPool, routing: ToolRouting, request: HostEffect, signal: AbortSignal): Promise<unknown>;
|
|
52
|
+
/**
|
|
53
|
+
* Calls an HTTP tool through the Tool Gate (R2 M3), keyed by the effect id: an agent's (the
|
|
54
|
+
* effect's agent used as a tool, or the root), or a flow's HTTP stage or HTTP verifier. Its
|
|
55
|
+
* outcome is the effect's value; a throw leaves the effect `uncertain`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function callHttpTool(gate: Pick<ToolGate, "callHttp">, request: HostEffect, signal: AbortSignal): Promise<unknown>;
|
|
52
58
|
export declare function callSandboxTool(sandbox: SandboxManager, routing: ToolRouting, request: HostEffect, signal: AbortSignal): Promise<unknown>;
|
package/dist/harness/calls.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The calls a harness executes, as pure helpers over what routes them: the Model Gate (or the
|
|
3
|
-
* Tenant's provider), the MCP pool, the SandboxManager. No store, no record: the
|
|
4
|
-
* routing comes with the run (`TurnStart.routing`).
|
|
3
|
+
* Tenant's provider), the Tool Gate, the MCP pool, the SandboxManager. No store, no record: the
|
|
4
|
+
* session's routing comes with the run (`TurnStart.routing`).
|
|
5
5
|
*/
|
|
6
6
|
import { ARTIFACTS_CAPABILITY_ID, SAVE_ARTIFACT_TOOL } from "@nylorun/core/define";
|
|
7
7
|
import { runAbortKind } from "@nylorun/harness/api";
|
|
8
|
+
import { httpToolRefOf } from "../gates/http-tool.js";
|
|
8
9
|
import { classifyThrown } from "../model/classify.js";
|
|
9
10
|
import { findServer } from "../mcp/pool.js";
|
|
10
11
|
import { manifestFor, mcpToolOf } from "../mcp/snapshot.js";
|
|
@@ -71,15 +72,14 @@ export function isSaveArtifactCall(manifest, request) {
|
|
|
71
72
|
request.toolName === SAVE_ARTIFACT_TOOL &&
|
|
72
73
|
manifest?.capabilities.some((capability) => capability.id === ARTIFACTS_CAPABILITY_ID) === true);
|
|
73
74
|
}
|
|
74
|
-
/** True when `request` calls a tool of a
|
|
75
|
+
/** True when `request` calls a tool of a declared MCP server (every one is remote). */
|
|
75
76
|
export function isRemoteMcpCall(routing, request) {
|
|
76
77
|
if (request.kind !== "tool")
|
|
77
78
|
return false;
|
|
78
79
|
const tool = mcpToolOf(routing.mcpSnapshot, request);
|
|
79
80
|
if (!tool)
|
|
80
81
|
return false;
|
|
81
|
-
|
|
82
|
-
return declared !== undefined && declared.server.type !== "stdio";
|
|
82
|
+
return findServer(routing.rootManifest, tool.agentId, tool.capabilityId, tool.serverName) !== undefined;
|
|
83
83
|
}
|
|
84
84
|
export async function callMcpTool(mcp, routing, request, signal) {
|
|
85
85
|
const tool = mcpToolOf(routing.mcpSnapshot, request);
|
|
@@ -93,11 +93,20 @@ export async function callMcpTool(mcp, routing, request, signal) {
|
|
|
93
93
|
serverToolName: tool.serverToolName,
|
|
94
94
|
args: request.input,
|
|
95
95
|
manifest: routing.rootManifest,
|
|
96
|
-
pluginRoots: routing.pluginRoots,
|
|
97
96
|
effectId: request.effectId,
|
|
98
97
|
signal,
|
|
99
98
|
});
|
|
100
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Calls an HTTP tool through the Tool Gate (R2 M3), keyed by the effect id: an agent's (the
|
|
102
|
+
* effect's agent used as a tool, or the root), or a flow's HTTP stage or HTTP verifier. Its
|
|
103
|
+
* outcome is the effect's value; a throw leaves the effect `uncertain`.
|
|
104
|
+
*/
|
|
105
|
+
export async function callHttpTool(gate, request, signal) {
|
|
106
|
+
if (!gate.callHttp)
|
|
107
|
+
throw new Error("This Runtime has no Tool Gate for HTTP tools");
|
|
108
|
+
return gate.callHttp({ tool: httpToolRefOf(request), effectId: request.effectId, turnId: request.turnId, input: request.input }, signal);
|
|
109
|
+
}
|
|
101
110
|
export async function callSandboxTool(sandbox, routing, request, signal) {
|
|
102
111
|
const capability = sandboxCapabilityOf(manifestFor(routing.rootManifest, request.agent), request.capabilityId, request.toolName);
|
|
103
112
|
if (!capability)
|
|
@@ -6,7 +6,7 @@ import { type ModelRoute, type ToolRouting } from "./calls.js";
|
|
|
6
6
|
export interface HarnessExecutorsOptions {
|
|
7
7
|
/** Where model calls go. Read per call: a harness process learns its Tenant at `hello`. */
|
|
8
8
|
readonly model: ModelRoute;
|
|
9
|
-
readonly toolGate: Pick<ToolGate, "recovers" | "cancel">;
|
|
9
|
+
readonly toolGate: Pick<ToolGate, "recovers" | "cancel" | "callHttp">;
|
|
10
10
|
readonly mcp: McpPool;
|
|
11
11
|
/** The SandboxManager; a harness process creates it once `hello` names the Tenant. */
|
|
12
12
|
readonly sandbox: () => SandboxManager;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A harness's executors (F6.1, F6.2): the model route, the Tool Gate
|
|
3
|
-
* SandboxManager, injected. They reach no store: a run's routing comes
|
|
4
|
-
* and the session's MCP discovery is recorded through core (`session.mcp`,
|
|
2
|
+
* A harness's executors (F6.1, F6.2): the model route, the Tool Gate (remote MCP and HTTP
|
|
3
|
+
* tools), an MCP pool and a SandboxManager, injected. They reach no store: a run's routing comes
|
|
4
|
+
* with its `turn.start`, and the session's MCP discovery is recorded through core (`session.mcp`,
|
|
5
|
+
* `prepare`).
|
|
5
6
|
*
|
|
6
7
|
* The in-process harness gets the Tenant's own pool and SandboxManager; a harness process
|
|
7
8
|
* (`--service harness`, `main.ts`) its own, whose sandbox events it claims from core.
|
|
@@ -10,27 +11,34 @@ import { hashManifest } from "@nylorun/core/define";
|
|
|
10
11
|
import { toolFixtureModel } from "../core/provider.js";
|
|
11
12
|
import { serversOf } from "../mcp/pool.js";
|
|
12
13
|
import { mcpToolOf } from "../mcp/snapshot.js";
|
|
13
|
-
import {
|
|
14
|
+
import { isHttpToolCall } from "../gates/http-tool.js";
|
|
15
|
+
import { abortOn, callHttpTool, callMcpTool, callSandboxTool, invokeModel, isRemoteMcpCall, isSaveArtifactCall, } from "./calls.js";
|
|
14
16
|
/** The Tenant's model of the fixture-model setting. Stateless. */
|
|
15
17
|
const fixture = toolFixtureModel();
|
|
16
18
|
export function harnessExecutors(options) {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
+
const recoversTools = options.toolGate.recovers === true;
|
|
20
|
+
const atGate = (effect, run) => {
|
|
21
|
+
const routing = routingOf(run);
|
|
22
|
+
return isRemoteMcpCall(routing, effect) || isHttpToolCall(routing.rootManifest, effect);
|
|
23
|
+
};
|
|
24
|
+
const recovered = (effect, run) => recoversTools && atGate(effect, run);
|
|
19
25
|
return {
|
|
20
26
|
model: (effect, signal, run) => invokeModel(options.model, effect, signal, run.start.options.fixtureModel ? fixture : undefined),
|
|
21
27
|
tool(effect, signal, run) {
|
|
22
28
|
const routing = routingOf(run);
|
|
29
|
+
// A call at the Tool Gate outlives a shutdown there; a local one finishes and is recorded.
|
|
30
|
+
const kinds = recovered(effect, run) ? ["cancel", "shutdown"] : ["cancel"];
|
|
31
|
+
if (isHttpToolCall(routing.rootManifest, effect))
|
|
32
|
+
return callHttpTool(options.toolGate, effect, abortOn(signal, kinds));
|
|
23
33
|
if (!mcpToolOf(routing.mcpSnapshot, effect))
|
|
24
34
|
return callSandboxTool(options.sandbox(), routing, effect, signal);
|
|
25
|
-
// A call at the Tool Gate outlives a shutdown there; a local one finishes and is recorded.
|
|
26
|
-
const kinds = remote(effect, run) ? ["cancel", "shutdown"] : ["cancel"];
|
|
27
35
|
return callMcpTool(options.mcp, routing, effect, abortOn(signal, kinds));
|
|
28
36
|
},
|
|
29
37
|
recovers: {
|
|
30
38
|
get model() {
|
|
31
39
|
return options.model.useVaultModel && options.model.modelGate.recovers === true;
|
|
32
40
|
},
|
|
33
|
-
|
|
41
|
+
tool: recovered,
|
|
34
42
|
},
|
|
35
43
|
async cancelAtGate(effect) {
|
|
36
44
|
await options.toolGate.cancel?.({
|
|
@@ -59,7 +67,6 @@ export async function prepareMcp(pool, run, record) {
|
|
|
59
67
|
sessionId,
|
|
60
68
|
manifest,
|
|
61
69
|
manifestHash: hashManifest(manifest),
|
|
62
|
-
pluginRoots: routing.pluginRoots,
|
|
63
70
|
signal: run.signal,
|
|
64
71
|
});
|
|
65
72
|
answer = await record({ snapshot: found.snapshot, diagnostics: found.diagnostics });
|
|
@@ -68,7 +75,6 @@ export async function prepareMcp(pool, run, record) {
|
|
|
68
75
|
const diagnostics = await pool.reconnect({
|
|
69
76
|
sessionId,
|
|
70
77
|
manifest,
|
|
71
|
-
pluginRoots: routing.pluginRoots,
|
|
72
78
|
tools: routing.mcpSnapshot.mcpTools,
|
|
73
79
|
signal: run.signal,
|
|
74
80
|
});
|
|
@@ -86,7 +92,6 @@ export function routingOf(run) {
|
|
|
86
92
|
const { routing } = run.start;
|
|
87
93
|
return {
|
|
88
94
|
rootManifest: routing.rootManifest,
|
|
89
|
-
pluginRoots: routing.pluginRoots,
|
|
90
95
|
...(routing.mcpSnapshot ? { mcpSnapshot: routing.mcpSnapshot } : {}),
|
|
91
96
|
sandboxOwnerId: routing.sandbox?.ownerId ?? run.grant.sessionId,
|
|
92
97
|
...(routing.sandbox?.sandboxId === undefined ? {} : { sandboxId: routing.sandbox.sandboxId }),
|
package/dist/harness/main.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StackConfig } from "../host/stack-config.js";
|
|
2
2
|
/**
|
|
3
|
-
* `baseline` is the allowlisted environment of
|
|
4
|
-
* by `host/main.ts`: nothing here reads the process environment.
|
|
3
|
+
* `baseline` is the allowlisted environment of a pod's sandbox tools (`baselineEnvironment`),
|
|
4
|
+
* read by `host/main.ts`: nothing here reads the process environment.
|
|
5
5
|
*/
|
|
6
6
|
export declare function runHarness(stack: StackConfig, baseline: Readonly<Record<string, string>>): Promise<void>;
|
package/dist/harness/main.js
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* database, no Restate, no keys.
|
|
7
7
|
*
|
|
8
8
|
* Its files live under `NYLORUN_HARNESS_ROOT` (`/harness`): `sandboxes/` (workspaces and their
|
|
9
|
-
* records)
|
|
10
|
-
* 127.0.0.1 only.
|
|
9
|
+
* records). `/health` answers on 127.0.0.1 only.
|
|
11
10
|
*
|
|
12
11
|
* In a pod sandbox (`NYLORUN_SANDBOX_KIND=pod`, F7.2) it is that sandbox's engine: it first waits
|
|
13
12
|
* until the pod's NetworkPolicy is in force (`awaitNetworkPolicy`), then joins with the
|
|
@@ -28,20 +27,14 @@ import { podHost } from "./pod.js";
|
|
|
28
27
|
import { harnessRunTokens } from "./run-tokens.js";
|
|
29
28
|
import { startHarnessService } from "./service.js";
|
|
30
29
|
/**
|
|
31
|
-
* `baseline` is the allowlisted environment of
|
|
32
|
-
* by `host/main.ts`: nothing here reads the process environment.
|
|
30
|
+
* `baseline` is the allowlisted environment of a pod's sandbox tools (`baselineEnvironment`),
|
|
31
|
+
* read by `host/main.ts`: nothing here reads the process environment.
|
|
33
32
|
*/
|
|
34
33
|
export async function runHarness(stack, baseline) {
|
|
35
34
|
const config = stack.harness;
|
|
36
35
|
const logger = createHostLogger();
|
|
37
|
-
const paths = {
|
|
38
|
-
|
|
39
|
-
pluginData: join(config.root, "plugin-data"),
|
|
40
|
-
home: join(config.root, "home"),
|
|
41
|
-
tmp: join(config.root, "tmp"),
|
|
42
|
-
};
|
|
43
|
-
for (const dir of Object.values(paths))
|
|
44
|
-
mkdirSync(dir, { recursive: true });
|
|
36
|
+
const paths = { sandboxes: join(config.root, "sandboxes") };
|
|
37
|
+
mkdirSync(paths.sandboxes, { recursive: true });
|
|
45
38
|
logger.info("host_stack_config", { services: [...stack.services], harness: config.url, gates: config.gatesUrl });
|
|
46
39
|
// A pod's engine trusts the network only once its NetworkPolicy blocks what it must.
|
|
47
40
|
let pod;
|
|
@@ -62,7 +55,6 @@ export async function runHarness(stack, baseline) {
|
|
|
62
55
|
token,
|
|
63
56
|
...(pod ? { sandboxBackends: [localBackend({ env: baseline, proxyEnv: () => pod.proxyEnv() })] } : {}),
|
|
64
57
|
paths,
|
|
65
|
-
childEnv: { ...baseline, HOME: paths.home, TMPDIR: paths.tmp },
|
|
66
58
|
modelGate: httpModelGate({ url: config.gatesUrl, runTokens }),
|
|
67
59
|
useVaultModel: true,
|
|
68
60
|
toolGate: httpToolGate({ url: config.gatesUrl, runTokens }),
|