@nylorun/runtime 0.19.1-beta → 0.21.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 +90 -0
- package/README.md +22 -13
- package/dist/adapters/streams/s2.js +5 -11
- package/dist/api/components.d.ts +326 -205
- package/dist/api/components.js +3 -3
- package/dist/api/http/app.js +2 -0
- package/dist/api/http/define.d.ts +3 -2
- package/dist/api/http/define.js +10 -11
- package/dist/api/http/routes/mcp.d.ts +9 -0
- package/dist/api/http/routes/mcp.js +32 -0
- package/dist/api/http/routes/vaults.d.ts +1 -9
- package/dist/api/http/routes/vaults.js +3 -103
- package/dist/api/openapi.js +37 -6
- package/dist/artifacts/media-types.d.ts +2 -0
- package/dist/artifacts/media-types.js +5 -0
- package/dist/execution/types.d.ts +1 -1
- package/dist/gates/http-tool.d.ts +7 -0
- package/dist/gates/http-tool.js +34 -3
- package/dist/gates/mcp-handler.d.ts +4 -1
- package/dist/gates/mcp-handler.js +64 -8
- package/dist/gates/tenant-vaults.d.ts +9 -15
- package/dist/gates/tenant-vaults.js +9 -17
- package/dist/gates/tool-client.js +36 -17
- package/dist/gates/tool-contract.d.ts +19 -3
- package/dist/gates/tool-contract.js +9 -3
- package/dist/gates/tool-gate.d.ts +2 -2
- package/dist/harness/calls.d.ts +2 -0
- package/dist/harness/calls.js +13 -3
- package/dist/harness-api/record.d.ts +7 -6
- package/dist/harness-api/record.js +99 -17
- package/dist/harness-api/server.js +35 -27
- package/dist/harness-api/start.js +2 -1
- package/dist/host/app.d.ts +3 -0
- package/dist/host/app.js +33 -4
- package/dist/host/config-for.d.ts +0 -2
- package/dist/host/config-for.js +0 -1
- package/dist/host/create-host.d.ts +6 -0
- package/dist/host/create-host.js +1 -0
- package/dist/host/gates.js +0 -1
- package/dist/host/main.js +24 -7
- package/dist/host/stack-config.d.ts +5 -8
- package/dist/host/stack-config.js +9 -20
- package/dist/index.d.ts +0 -1
- package/dist/infra/index.d.ts +2 -1
- package/dist/infra/index.js +0 -1
- package/dist/infra/readiness.d.ts +6 -6
- package/dist/infra/readiness.js +2 -5
- package/dist/keys/client.js +1 -9
- package/dist/keys/keys.d.ts +11 -13
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +671 -378
- package/dist/mcp/connect.d.ts +159 -13
- package/dist/mcp/connect.js +538 -55
- package/dist/mcp/pool.d.ts +11 -2
- package/dist/mcp/pool.js +74 -27
- package/dist/mcp/preview.d.ts +35 -0
- package/dist/mcp/preview.js +215 -0
- package/dist/mcp/snapshot.d.ts +79 -5
- package/dist/mcp/snapshot.js +145 -27
- package/dist/model/catalog.d.ts +14 -0
- package/dist/model/catalog.js +14 -1
- package/dist/model/pi-model.js +36 -2
- package/dist/openapi.json +644 -266
- package/dist/redact.d.ts +19 -1
- package/dist/redact.js +42 -13
- package/dist/sandbox/session-sandbox.d.ts +7 -0
- package/dist/sandbox/session-sandbox.js +89 -28
- package/dist/store/postgres/connect.d.ts +10 -0
- package/dist/store/postgres/connect.js +30 -3
- package/dist/store/postgres/control.d.ts +14 -0
- package/dist/store/postgres/control.js +187 -0
- package/dist/store/postgres/drizzle/0015_control_signals.sql +11 -0
- package/dist/store/postgres/drizzle/0016_mcp_oauth_removed.sql +5 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +14 -0
- package/dist/store/postgres/schema.d.ts +122 -261
- package/dist/store/postgres/schema.js +22 -36
- package/dist/store/postgres/store.js +16 -18
- package/dist/store/postgres/tenant.d.ts +14 -0
- package/dist/store/postgres/tenant.js +22 -2
- package/dist/store/types.d.ts +42 -8
- package/dist/streams/types.d.ts +6 -29
- package/dist/streams/types.js +5 -4
- package/dist/tenant/artifact-tool.d.ts +9 -1
- package/dist/tenant/artifact-tool.js +113 -9
- package/dist/tenant/auth.d.ts +16 -6
- package/dist/tenant/auth.js +41 -17
- package/dist/tenant/commands.js +10 -6
- package/dist/tenant/context.d.ts +9 -6
- package/dist/tenant/control.d.ts +26 -0
- package/dist/tenant/control.js +35 -0
- package/dist/tenant/effects.d.ts +2 -2
- package/dist/tenant/effects.js +20 -5
- package/dist/tenant/ephemeral.d.ts +0 -6
- package/dist/tenant/ephemeral.js +1 -1
- package/dist/tenant/http.d.ts +4 -2
- package/dist/tenant/http.js +4 -2
- package/dist/tenant/identity-file.d.ts +16 -12
- package/dist/tenant/identity-file.js +41 -29
- package/dist/tenant/issuers.d.ts +4 -3
- package/dist/tenant/issuers.js +22 -16
- package/dist/tenant/outbound.d.ts +14 -5
- package/dist/tenant/outbound.js +21 -9
- package/dist/tenant/reset.d.ts +2 -2
- package/dist/tenant/reset.js +8 -2
- package/dist/tenant/resource-server.d.ts +56 -0
- package/dist/tenant/resource-server.js +62 -0
- package/dist/tenant/runtime.d.ts +1 -1
- package/dist/tenant/runtime.js +16 -15
- package/dist/tenant/scheduler.d.ts +1 -1
- package/dist/tenant/scheduler.js +1 -1
- package/dist/tenant/sessions.js +20 -3
- package/dist/tenant/store-pg.js +9 -0
- package/dist/tenant/streams.d.ts +16 -22
- package/dist/tenant/streams.js +7 -87
- package/dist/tenant/sweep.js +9 -1
- package/dist/tenant/tool-results.d.ts +57 -0
- package/dist/tenant/tool-results.js +298 -0
- package/dist/tenant/tool-search.d.ts +43 -0
- package/dist/tenant/tool-search.js +100 -0
- package/dist/tenant/transcript.d.ts +108 -0
- package/dist/tenant/transcript.js +13 -0
- package/dist/tenant/types.d.ts +0 -14
- package/dist/vault/crypto.d.ts +0 -7
- package/dist/vault/crypto.js +0 -16
- package/dist/vault/headers.d.ts +17 -0
- package/dist/vault/headers.js +61 -0
- package/dist/vault/service.d.ts +11 -68
- package/dist/vault/service.js +83 -438
- package/dist/vault/sources.d.ts +20 -48
- package/dist/vault/sources.js +25 -189
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/streams/control.d.ts +0 -13
- package/dist/streams/control.js +0 -25
- package/dist/vault/oauth.d.ts +0 -55
- package/dist/vault/oauth.js +0 -186
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Record seam of the Harness API: core's journal for the effects of a run. `recordIntent`
|
|
3
3
|
* journals an effect before anything runs it, and either answers it from the journal, hands it
|
|
4
|
-
* to core's own executors (flow work, delegation, `save_artifact`
|
|
5
|
-
* the harness to `execute` it (model calls; MCP, HTTP
|
|
6
|
-
* and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* to core's own executors (flow work, delegation, `save_artifact`, `read_artifact`,
|
|
5
|
+
* `tool_search` and the skill tools), tells the harness to `execute` it (model calls; MCP, HTTP
|
|
6
|
+
* and sandbox tools, a deferred MCP tool's `tool_call` among them, whose effect names the tool;
|
|
7
|
+
* a flow's HTTP stages and HTTP verifiers), or fails a tool the Runtime cannot run (one that
|
|
8
|
+
* would run the developer's code, R2 M6). `recordOutcome` records what the harness's call returned, an
|
|
9
|
+
* agent's MCP or HTTP tool result first shaped to fit (R2b C11). Both run under the advance's
|
|
10
|
+
* lease: every write is epoch-checked (`ownedSession`), and a lost epoch writes nothing.
|
|
10
11
|
*
|
|
11
12
|
* Rows store the request's hash (`requestHash`) and, for a model call, the request without its
|
|
12
13
|
* prompt: drift is a hash compare. Rows written before carry their full request, hashed on read.
|
|
@@ -14,9 +15,12 @@
|
|
|
14
15
|
import { HarnessApiError, effectRequestHash, } from "@nylorun/core/harness-api";
|
|
15
16
|
import { isFlowEffect, isFlowToolEffect, recordVerdict, settleAgentEffect, } from "../core/flow-host.js";
|
|
16
17
|
import { sandboxCapabilityOf } from "../sandbox/capability.js";
|
|
17
|
-
import { isSaveArtifactCall } from "../harness/calls.js";
|
|
18
|
-
import { callSaveArtifact } from "../tenant/artifact-tool.js";
|
|
18
|
+
import { abortOn, isReadArtifactCall, isSaveArtifactCall } from "../harness/calls.js";
|
|
19
|
+
import { callReadArtifact, callSaveArtifact } from "../tenant/artifact-tool.js";
|
|
20
|
+
import { mayNeedShaping, resultBytes, resultLimit, shapeToolOutcome, } from "../tenant/tool-results.js";
|
|
19
21
|
import { callSkillTool, isSkillToolCall } from "../tenant/skill-tool.js";
|
|
22
|
+
import { callToolSearch, isToolSearchCall } from "../tenant/tool-search.js";
|
|
23
|
+
import { turnManifestOf } from "../tenant/session.js";
|
|
20
24
|
import { isOwnershipLost } from "../store/ownership.js";
|
|
21
25
|
import { manifestFor, mcpToolOf } from "../mcp/snapshot.js";
|
|
22
26
|
import { isHttpToolCall } from "../gates/http-tool.js";
|
|
@@ -109,17 +113,24 @@ export async function recordIntent(scope, effect, requestHash) {
|
|
|
109
113
|
throw new Error(`Agent '${request.agent?.id ?? ""}' is not used as a tool`);
|
|
110
114
|
const executed = request.kind === "model" ||
|
|
111
115
|
(request.kind === "tool" &&
|
|
112
|
-
|
|
116
|
+
// An MCP tool the turn's manifest disables is not one (R2b C9).
|
|
117
|
+
(mcpToolOf(s.mcpSnapshot, request, turnManifestOf(s)) !== undefined ||
|
|
113
118
|
// HTTP tools (R2 M3) cross the Tool Gate.
|
|
114
119
|
isHttpToolCall(s.manifest, request) ||
|
|
115
120
|
sandboxCapabilityOf(agentManifest, request.capabilityId, request.toolName) !== undefined ||
|
|
116
|
-
// `save_artifact` (F8.1) runs beside the sandbox tools,
|
|
121
|
+
// `save_artifact` (F8.1) runs beside the sandbox tools, as do `read_artifact` (R2b
|
|
122
|
+
// C11) and the skill tools (R2 M4).
|
|
117
123
|
isSaveArtifactCall(agentManifest, request) ||
|
|
118
|
-
|
|
124
|
+
isReadArtifactCall(agentManifest, request) ||
|
|
125
|
+
isSkillToolCall(agentManifest, request) ||
|
|
126
|
+
// `tool_search` (R2b C10) reads the session's pinned MCP snapshot: core serves it.
|
|
127
|
+
isToolSearchCall(agentManifest, request)));
|
|
119
128
|
if (!executed) {
|
|
120
129
|
// A tool that would run the developer's code: refused at save (a turn's manifest only
|
|
121
|
-
// removes tools), so this is a backstop
|
|
122
|
-
|
|
130
|
+
// removes tools), so this is a backstop, as is an MCP tool the turn disabled, which the
|
|
131
|
+
// model was never offered. The model sees the failure; nothing runs.
|
|
132
|
+
const disabled = request.kind === "tool" && mcpToolOf(s.mcpSnapshot, request) !== undefined;
|
|
133
|
+
const outcome = { value: disabled ? disabledTool(request) : unrunnableTool(request) };
|
|
123
134
|
await t.put("effects", request.effectId, { request, requestHash, status: "completed", outcome });
|
|
124
135
|
const transcript = toolCompleted(request, outcome.value);
|
|
125
136
|
if (transcript)
|
|
@@ -135,13 +146,22 @@ export async function recordIntent(scope, effect, requestHash) {
|
|
|
135
146
|
// workspace capability, wherever the sandbox is.
|
|
136
147
|
if (request.kind === "tool" && isSaveArtifactCall(agentManifest, request))
|
|
137
148
|
return "save";
|
|
149
|
+
// `read_artifact` reads the session's artifacts: core serves it, with or without a sandbox.
|
|
150
|
+
if (isReadArtifactCall(agentManifest, request))
|
|
151
|
+
return "read";
|
|
138
152
|
// The skill tools read the agent's definition files: core serves them.
|
|
139
153
|
if (isSkillToolCall(agentManifest, request))
|
|
140
154
|
return { skill: agentManifest };
|
|
155
|
+
if (isToolSearchCall(agentManifest, request))
|
|
156
|
+
return "search";
|
|
141
157
|
return { status: "execute" };
|
|
142
158
|
});
|
|
143
159
|
if (answer === "save")
|
|
144
160
|
return runInCore(scope, request, () => callSaveArtifact(scope.ctx, request, scope.signal));
|
|
161
|
+
if (answer === "read")
|
|
162
|
+
return runInCore(scope, request, () => callReadArtifact(scope.ctx, request, scope.signal));
|
|
163
|
+
if (answer === "search")
|
|
164
|
+
return runInCore(scope, request, () => callToolSearch(scope.ctx, request));
|
|
145
165
|
if (typeof answer === "object" && "skill" in answer)
|
|
146
166
|
return runInCore(scope, request, () => callSkillTool(scope.ctx, answer.skill, request, scope.signal));
|
|
147
167
|
if (answer !== "flow")
|
|
@@ -151,9 +171,10 @@ export async function recordIntent(scope, effect, requestHash) {
|
|
|
151
171
|
return resolveNewFlowEffect(ctx, request, signal, lease);
|
|
152
172
|
}
|
|
153
173
|
/**
|
|
154
|
-
* Runs a tool core serves (`save_artifact`, F8.1;
|
|
155
|
-
*
|
|
156
|
-
*
|
|
174
|
+
* Runs a tool core serves (`save_artifact`, F8.1; `read_artifact`, R2b C11; `tool_search`, R2b
|
|
175
|
+
* C10; the skill tools, R2 M4) for the run and records its outcome, as a harness would record a
|
|
176
|
+
* call it ran: the run gets
|
|
177
|
+
* the outcome as the intent's answer.
|
|
157
178
|
*/
|
|
158
179
|
async function runInCore(scope, request, call) {
|
|
159
180
|
let value;
|
|
@@ -169,6 +190,14 @@ async function runInCore(scope, request, call) {
|
|
|
169
190
|
}
|
|
170
191
|
return recordOutcome(scope, request.effectId, { value });
|
|
171
192
|
}
|
|
193
|
+
/** The failed outcome of an MCP tool the turn's manifest disables (R2b C9). */
|
|
194
|
+
function disabledTool(request) {
|
|
195
|
+
return {
|
|
196
|
+
kind: "failed",
|
|
197
|
+
code: "tool.disabled",
|
|
198
|
+
message: `Tool '${request.toolName ?? ""}' is disabled by its MCP server's tools settings.`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
172
201
|
/** The failed outcome of a tool the Runtime cannot run: it would run the developer's code. */
|
|
173
202
|
function unrunnableTool(request) {
|
|
174
203
|
return {
|
|
@@ -199,7 +228,7 @@ export async function recordOutcome(scope, effectId, result) {
|
|
|
199
228
|
});
|
|
200
229
|
return { status: "uncertain" };
|
|
201
230
|
}
|
|
202
|
-
const
|
|
231
|
+
const value = await shaped(scope, effectId, result.value);
|
|
203
232
|
return ctx.store.tx(async (t) => {
|
|
204
233
|
const s = await t.assertEpoch(lease.sessionId, lease.epoch);
|
|
205
234
|
const effect = await t.get("effects", effectId);
|
|
@@ -234,6 +263,59 @@ export async function recordOutcome(scope, effectId, result) {
|
|
|
234
263
|
return { status: "completed", outcome: effect.outcome };
|
|
235
264
|
});
|
|
236
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* The outcome of an agent's remote MCP or HTTP tool call, shaped to fit before anything records
|
|
268
|
+
* it (R2b C11, `tenant/tool-results.ts`): what does not fit becomes the session's artifacts. Any
|
|
269
|
+
* other outcome, and one a cancel will discard, as it is. Only a cancel stops the upload: after a
|
|
270
|
+
* shutdown or a deadline the outcome is still recorded, so the next advance replays it.
|
|
271
|
+
*
|
|
272
|
+
* Its cap is what its step's budget has left (`resultLimit`): a step's results are one transcript
|
|
273
|
+
* entry. Parallel results are counted under the session lock, each reserving its share on its
|
|
274
|
+
* row (`resultBytes`) before it is shaped, so two never spend the same room.
|
|
275
|
+
*/
|
|
276
|
+
async function shaped(scope, effectId, value) {
|
|
277
|
+
const { ctx, lease, signal } = scope;
|
|
278
|
+
if (abortKind(signal) === "cancel" || !mayNeedShaping(value))
|
|
279
|
+
return value;
|
|
280
|
+
const call = await ctx.store.tx(async (t) => {
|
|
281
|
+
const s = await t.lockSession(lease.sessionId);
|
|
282
|
+
const effect = await t.get("effects", effectId);
|
|
283
|
+
if (!s || !effect || effect.status === "completed")
|
|
284
|
+
return undefined;
|
|
285
|
+
const request = effect.request;
|
|
286
|
+
// An agent's tool; a flow's HTTP stage or verifier names no capability, and its output is data.
|
|
287
|
+
if (request.kind !== "tool" || request.capabilityId === undefined)
|
|
288
|
+
return undefined;
|
|
289
|
+
const mcp = mcpToolOf(s.mcpSnapshot, request) !== undefined;
|
|
290
|
+
if (!mcp && !isHttpToolCall(s.manifest, request))
|
|
291
|
+
return undefined;
|
|
292
|
+
const step = stepOf(request);
|
|
293
|
+
let used = 0;
|
|
294
|
+
if (step !== undefined)
|
|
295
|
+
for (const other of await t.effectsForTurn(s.id, request.turnId, [
|
|
296
|
+
"invoking",
|
|
297
|
+
"completed",
|
|
298
|
+
])) {
|
|
299
|
+
if (other.request.effectId === effectId || stepOf(other.request) !== step)
|
|
300
|
+
continue;
|
|
301
|
+
used +=
|
|
302
|
+
other.resultBytes ??
|
|
303
|
+
(other.status === "completed" ? resultBytes(other.outcome?.value) : 0);
|
|
304
|
+
}
|
|
305
|
+
const limit = resultLimit(used);
|
|
306
|
+
effect.resultBytes = Math.min(resultBytes(value), limit);
|
|
307
|
+
await t.put("effects", effectId, effect);
|
|
308
|
+
return { request, session: { id: s.id, ownerUserId: s.ownerUserId }, mcp, limit };
|
|
309
|
+
});
|
|
310
|
+
return call ? shapeToolOutcome(ctx, call, value, abortOn(signal, ["cancel"])) : value;
|
|
311
|
+
}
|
|
312
|
+
/** The model step a tool call answers, and whose agent: its results share one transcript entry. */
|
|
313
|
+
function stepOf(request) {
|
|
314
|
+
if (request.kind !== "tool")
|
|
315
|
+
return undefined;
|
|
316
|
+
const stepId = request.context?.stepId;
|
|
317
|
+
return typeof stepId === "string" ? JSON.stringify([request.agent?.id ?? null, stepId]) : undefined;
|
|
318
|
+
}
|
|
237
319
|
/** What a journal row keeps of a request: a model call without its prompt. */
|
|
238
320
|
function storedRequest(request) {
|
|
239
321
|
if (request.kind !== "model" || request.input === undefined)
|
|
@@ -29,7 +29,9 @@ import { HARNESS_API_VERSION, HARNESS_CLAIMS, HarnessApiError, } from "@nylorun/
|
|
|
29
29
|
import { definitionFilesOf } from "@nylorun/core/contracts";
|
|
30
30
|
import { isOwnershipLost } from "../store/ownership.js";
|
|
31
31
|
import { ownedSession } from "../tenant/context.js";
|
|
32
|
-
import { mcpDiscovered, sessionToolsOf } from "../mcp/snapshot.js";
|
|
32
|
+
import { mcpDiscovered, pinDeferral, sessionToolsOf, } from "../mcp/snapshot.js";
|
|
33
|
+
import { contextWindowOf } from "../model/catalog.js";
|
|
34
|
+
import { turnManifestOf } from "../tenant/session.js";
|
|
33
35
|
import { sandboxWorkspaceKey, workspacePrefix } from "../sandbox/records.js";
|
|
34
36
|
import { abortKind } from "../tenant/worker.js";
|
|
35
37
|
import { readDefinitionFile } from "../tenant/definition-files.js";
|
|
@@ -194,36 +196,42 @@ export function createHarnessApiServer(ctx, options = {}) {
|
|
|
194
196
|
* session wins, with `mcp.discovered` in its log; diagnostics replace those of the same server.
|
|
195
197
|
* Answers the session's snapshot and the tools the engine advertises.
|
|
196
198
|
*/
|
|
197
|
-
const recordMcp = (run, params) =>
|
|
198
|
-
const { lease } = run.offer;
|
|
199
|
-
const current = await ownedSession(t, lease, lease.sessionId);
|
|
200
|
-
const diagnostics = params.diagnostics;
|
|
199
|
+
const recordMcp = async (run, params) => {
|
|
201
200
|
const snapshot = params.snapshot;
|
|
202
201
|
if (snapshot !== undefined && !isSnapshot(snapshot))
|
|
203
202
|
throw new HarnessApiError("invalid", "The MCP snapshot is malformed");
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
else
|
|
217
|
-
prior.push(item);
|
|
203
|
+
// Which MCP tools the model reaches through tool_search, decided once for the session from
|
|
204
|
+
// the Tenant's model's context window (R2b C10, Q21).
|
|
205
|
+
const contextWindow = snapshot ? contextWindowOf(await ctx.vault.getHostModel()) : 0;
|
|
206
|
+
return ctx.store.tx(async (t) => {
|
|
207
|
+
const { lease } = run.offer;
|
|
208
|
+
const current = await ownedSession(t, lease, lease.sessionId);
|
|
209
|
+
const diagnostics = params.diagnostics;
|
|
210
|
+
if (snapshot && !current.mcpSnapshot) {
|
|
211
|
+
current.mcpSnapshot = pinDeferral(snapshot, current.manifest, contextWindow);
|
|
212
|
+
current.mcpDiagnostics = diagnostics;
|
|
213
|
+
await t.put("sessions", current.id, current);
|
|
214
|
+
await t.event(current.id, run.grant.turnId, "mcp.discovered", mcpDiscovered(current.mcpSnapshot, diagnostics));
|
|
218
215
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
216
|
+
else if (diagnostics.length > 0) {
|
|
217
|
+
const prior = [...(current.mcpDiagnostics ?? [])];
|
|
218
|
+
for (const item of diagnostics) {
|
|
219
|
+
const index = prior.findIndex((existing) => existing.capabilityId === item.capabilityId && existing.serverName === item.serverName);
|
|
220
|
+
if (index >= 0)
|
|
221
|
+
prior[index] = item;
|
|
222
|
+
else
|
|
223
|
+
prior.push(item);
|
|
224
|
+
}
|
|
225
|
+
current.mcpDiagnostics = prior;
|
|
226
|
+
await t.put("sessions", current.id, current);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
...(current.mcpSnapshot ? { snapshot: current.mcpSnapshot } : {}),
|
|
230
|
+
// The turn's manifest: a variant may have disabled tools or required their approval.
|
|
231
|
+
sessionTools: [...(sessionToolsOf(current.mcpSnapshot, turnManifestOf(current)) ?? [])],
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
};
|
|
227
235
|
/** A definition file the run's definition names (its skills', for its sandbox), base64. */
|
|
228
236
|
const definitionFile = async (run, sha256, signal) => {
|
|
229
237
|
if (!definitionFilesOf(run.offer.start.routing.rootManifest).has(sha256))
|
|
@@ -57,7 +57,8 @@ export function buildTurnStart(ctx, segment) {
|
|
|
57
57
|
checkpoint: !flow && cp.state
|
|
58
58
|
? { ...cp, state: withTranscript(cp.state, []) }
|
|
59
59
|
: cp,
|
|
60
|
-
|
|
60
|
+
// The turn's manifest: a variant may have disabled MCP tools or required their approval.
|
|
61
|
+
...(flow ? {} : { sessionTools: sessionToolsOf(current.mcpSnapshot, turnManifestOf(current)) ?? [] }),
|
|
61
62
|
outcomes: segment.outcomes,
|
|
62
63
|
transcript: { cursor: segment.cursor },
|
|
63
64
|
options: {
|
package/dist/host/app.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import type { Logger, NodeBindings, TenantModule } from "../tenant/types.js";
|
|
3
|
+
import { type ResourceServerConfig } from "../tenant/resource-server.js";
|
|
3
4
|
export type HostEnv = {
|
|
4
5
|
Bindings: NodeBindings;
|
|
5
6
|
Variables: {
|
|
@@ -19,6 +20,8 @@ export interface HostAppOptions {
|
|
|
19
20
|
ok: boolean;
|
|
20
21
|
checks: Record<string, boolean>;
|
|
21
22
|
}>;
|
|
23
|
+
/** The public URL and trusted issuers the OAuth metadata and challenges name. */
|
|
24
|
+
resourceServer?: ResourceServerConfig;
|
|
22
25
|
/** The listener is listening. */
|
|
23
26
|
listening(): boolean;
|
|
24
27
|
closing(): boolean;
|
package/dist/host/app.js
CHANGED
|
@@ -3,10 +3,13 @@ import { RESPONSE_ALREADY_SENT } from "@hono/node-server/utils/response";
|
|
|
3
3
|
import { checkCompatibility, HOST_PROTOCOL, PROTOCOL_HEADER, TENANT_HEADER, } from "@nylorun/core/compatibility";
|
|
4
4
|
import { RUNTIME_VERSION } from "../version.js";
|
|
5
5
|
import { findTenantRoute } from "../api/http/app.js";
|
|
6
|
+
import { keyAccess } from "../api/http/define.js";
|
|
7
|
+
import { bearerChallenge, PROTECTED_RESOURCE_PATH, protectedResourceMetadata, protectedResourceMetadataUrl, } from "../tenant/resource-server.js";
|
|
6
8
|
import { managementDocument, runtimeDocument } from "../api/openapi.js";
|
|
7
9
|
import { headerValue, isJsonContentType, jsonResponse, opaqueNotFoundResponse, protocolRejectedResponse, pathnameIsLogged, redactRoutePath, rejectedResponse, requestHasBody, } from "./http.js";
|
|
8
10
|
export function createHostApp(options) {
|
|
9
11
|
const { module, logger } = options;
|
|
12
|
+
const resourceServer = options.resourceServer ?? {};
|
|
10
13
|
const app = new Hono();
|
|
11
14
|
app.use(async (c, next) => {
|
|
12
15
|
const started = Date.now();
|
|
@@ -28,9 +31,10 @@ export function createHostApp(options) {
|
|
|
28
31
|
app.use(async (c, next) => {
|
|
29
32
|
const { incoming } = c.env;
|
|
30
33
|
if (headerValue(incoming, "origin") !== undefined) {
|
|
31
|
-
// Only Tenant routes
|
|
32
|
-
// browser.
|
|
33
|
-
if (pathnameOf(incoming).split("/").filter(Boolean)[0] !== "v1"
|
|
34
|
+
// Only Tenant routes, where the Tenant then accepts only a trusted issuer's token from a
|
|
35
|
+
// browser, and the public OAuth metadata a browser client reads before it signs in.
|
|
36
|
+
if (pathnameOf(incoming).split("/").filter(Boolean)[0] !== "v1" &&
|
|
37
|
+
!isProtectedResourcePath(pathnameOf(incoming)))
|
|
34
38
|
return rejectedResponse(403, "origin_rejected", "Browser Origin headers are not accepted");
|
|
35
39
|
}
|
|
36
40
|
// CORS is the operator's proxy's: an OPTIONS request gets no CORS header.
|
|
@@ -83,13 +87,35 @@ export function createHostApp(options) {
|
|
|
83
87
|
return jsonResponse(200, runtimeDocument(), { "cache-control": "no-cache" });
|
|
84
88
|
if (pathname === "/openapi/management.json" && incoming.method === "GET")
|
|
85
89
|
return jsonResponse(200, managementDocument(), { "cache-control": "no-cache" });
|
|
90
|
+
// RFC 9728: where the Runtime API's tokens come from. None without trusted issuers.
|
|
91
|
+
if (isProtectedResourcePath(pathname) && incoming.method === "GET") {
|
|
92
|
+
const metadata = protectedResourceMetadata(resourceServer, incoming);
|
|
93
|
+
return metadata
|
|
94
|
+
? jsonResponse(200, metadata, { "cache-control": "no-cache" })
|
|
95
|
+
: rejectedResponse(404, "not_found", "This Runtime trusts no identity provider");
|
|
96
|
+
}
|
|
86
97
|
// Tenant routes: protocol → the Tenant → selection → the Tenant's routes.
|
|
87
98
|
const tenantHeader = headerValue(incoming, TENANT_HEADER);
|
|
88
99
|
const named = tenantHeader === undefined || tenantHeader.trim() === "" ? undefined : tenantHeader.trim();
|
|
89
100
|
const protocol = headerValue(incoming, PROTOCOL_HEADER);
|
|
101
|
+
// A generic OAuth client sends neither header: answer it the challenge, not the 426.
|
|
102
|
+
const route = tenantRouteOf(incoming);
|
|
103
|
+
if (protocol === undefined &&
|
|
104
|
+
headerValue(incoming, "authorization") === undefined &&
|
|
105
|
+
route !== undefined &&
|
|
106
|
+
route.anonymous !== true) {
|
|
107
|
+
const metadata = keyAccess(route).application
|
|
108
|
+
? protectedResourceMetadataUrl(resourceServer, incoming)
|
|
109
|
+
: undefined;
|
|
110
|
+
return jsonResponse(401, {
|
|
111
|
+
status: "rejected",
|
|
112
|
+
code: "credential_required",
|
|
113
|
+
message: "A bearer credential is required",
|
|
114
|
+
}, { "www-authenticate": bearerChallenge({ resourceMetadata: metadata }) });
|
|
115
|
+
}
|
|
90
116
|
// A capability link is opened without the header; when one is sent, it is checked.
|
|
91
117
|
if (!protocolAccepted(protocol) &&
|
|
92
|
-
!(protocol === undefined &&
|
|
118
|
+
!(protocol === undefined && route?.unversioned === true))
|
|
93
119
|
return protocolRejectedResponse();
|
|
94
120
|
const resolution = await module.resolve();
|
|
95
121
|
if (resolution.kind !== "open") {
|
|
@@ -138,6 +164,9 @@ export function createHostApp(options) {
|
|
|
138
164
|
}
|
|
139
165
|
/** The methods the Runtime serves, for an `OPTIONS` answer's `Allow`. */
|
|
140
166
|
const ALLOWED_METHODS = "GET, POST, PUT, DELETE, OPTIONS";
|
|
167
|
+
function isProtectedResourcePath(pathname) {
|
|
168
|
+
return pathname === PROTECTED_RESOURCE_PATH || pathname.startsWith(`${PROTECTED_RESOURCE_PATH}/`);
|
|
169
|
+
}
|
|
141
170
|
/** The Tenant route a request names, if any; a malformed path names none. */
|
|
142
171
|
function tenantRouteOf(incoming) {
|
|
143
172
|
const segments = [];
|
|
@@ -14,6 +14,4 @@ export declare function configForFactory(options: {
|
|
|
14
14
|
delivery?: TenantConfig["delivery"];
|
|
15
15
|
/** The trusted issuers of the identity file (`NYLORUN_IDENTITY_FILE`). */
|
|
16
16
|
issuers?: TenantConfig["issuers"];
|
|
17
|
-
/** `NYLORUN_PUBLIC_URL`: the base of the MCP OAuth callback (F9 C2). */
|
|
18
|
-
publicUrl?: string;
|
|
19
17
|
}): (id: string) => TenantConfig;
|
package/dist/host/config-for.js
CHANGED
|
@@ -16,7 +16,6 @@ export function configForFactory(options) {
|
|
|
16
16
|
model: options.model ?? { kind: "vault" },
|
|
17
17
|
...(options.delivery ? { delivery: options.delivery } : {}),
|
|
18
18
|
...(options.issuers ? { issuers: options.issuers } : {}),
|
|
19
|
-
...(options.publicUrl ? { publicUrl: options.publicUrl } : {}),
|
|
20
19
|
logger: {
|
|
21
20
|
info: (message, fields) => options.logger.info(message, { tenantId: id, ...fields }),
|
|
22
21
|
warn: (message, fields) => options.logger.warn(message, { tenantId: id, ...fields }),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ResourceServerConfig } from "../tenant/resource-server.js";
|
|
1
2
|
import type { Logger, TenantModule } from "../tenant/types.js";
|
|
2
3
|
import type { HostConfigFile } from "./config.js";
|
|
3
4
|
import type { ContainerListen } from "./stack-config.js";
|
|
@@ -25,6 +26,11 @@ export interface CreateHostOptions {
|
|
|
25
26
|
ok: boolean;
|
|
26
27
|
checks: Record<string, boolean>;
|
|
27
28
|
}>;
|
|
29
|
+
/**
|
|
30
|
+
* The public URL and trusted issuers behind `/.well-known/oauth-protected-resource` and the
|
|
31
|
+
* challenge a request without credential or protocol gets (protocol 9). Absent: no metadata.
|
|
32
|
+
*/
|
|
33
|
+
resourceServer?: ResourceServerConfig;
|
|
28
34
|
/**
|
|
29
35
|
* Shutdown steps around closing the Tenant. `close()` runs them whatever asked for it
|
|
30
36
|
* (SIGTERM in `host/main.ts`): the listener stops, then
|
package/dist/host/create-host.js
CHANGED
|
@@ -20,6 +20,7 @@ export function createHost(options) {
|
|
|
20
20
|
coreVersion,
|
|
21
21
|
pid,
|
|
22
22
|
...(options.readiness ? { readiness: options.readiness } : {}),
|
|
23
|
+
...(options.resourceServer ? { resourceServer: options.resourceServer } : {}),
|
|
23
24
|
listening: () => Boolean(server?.listening),
|
|
24
25
|
closing: () => closing,
|
|
25
26
|
});
|
package/dist/host/gates.js
CHANGED
package/dist/host/main.js
CHANGED
|
@@ -71,9 +71,10 @@ function loadJson(path) {
|
|
|
71
71
|
/**
|
|
72
72
|
* The trusted issuers of the identity file (`NYLORUN_IDENTITY_FILE`, Host feature
|
|
73
73
|
* `trusted-issuers`). A missing or malformed file stops the boot, naming the issuer and field;
|
|
74
|
-
*
|
|
74
|
+
* a key the file does not define is logged and ignored. An issuer's JWKS is fetched only when a
|
|
75
|
+
* token needs it, so one that is down does not stop the boot.
|
|
75
76
|
*/
|
|
76
|
-
function loadIssuers(path) {
|
|
77
|
+
function loadIssuers(path, logger) {
|
|
77
78
|
let text;
|
|
78
79
|
try {
|
|
79
80
|
text = readFileSync(path, "utf8");
|
|
@@ -81,7 +82,9 @@ function loadIssuers(path) {
|
|
|
81
82
|
catch (error) {
|
|
82
83
|
throw new Error(`NYLORUN_IDENTITY_FILE names ${path}, which cannot be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
83
84
|
}
|
|
84
|
-
return createTrustedIssuers(parseIdentityFile(text, path
|
|
85
|
+
return createTrustedIssuers(parseIdentityFile(text, path, {
|
|
86
|
+
warn: (message) => logger.warn("identity_file_key_ignored", { message }),
|
|
87
|
+
}));
|
|
85
88
|
}
|
|
86
89
|
/** The bootstrap management key: 64 hex characters, surrounding whitespace ignored. */
|
|
87
90
|
function loadManagementKey(path) {
|
|
@@ -136,6 +139,17 @@ async function ensureBucket(store, bucket, logger) {
|
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Settings of a removed feature that are still set: logged, never fatal. The credential
|
|
144
|
+
* resolver (`NYLORUN_RESOLVER_*`) is gone in protocol 10. Never logs the values.
|
|
145
|
+
*/
|
|
146
|
+
function warnRemovedSettings(stack, logger) {
|
|
147
|
+
if (stack.removedResolverVariables)
|
|
148
|
+
logger.warn("resolver_removed", {
|
|
149
|
+
variables: stack.removedResolverVariables,
|
|
150
|
+
message: "The credential resolver is gone (protocol 10) and these variables are ignored: keep a person's keys in their user vault, or reach their accounts through a gateway",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
139
153
|
/**
|
|
140
154
|
* The gateway's services: the Model Gate's listener (gates, keys) and egress-gate's (egress), over
|
|
141
155
|
* the Postgres pool and the Host's tenant directory. Writes nothing to the Host root (the local
|
|
@@ -150,9 +164,8 @@ async function runGates(stack) {
|
|
|
150
164
|
...(stack.packing ? { packing: stack.packing } : {}),
|
|
151
165
|
endpoints: describeEndpoints(stack.endpoints),
|
|
152
166
|
objectStore: stack.objectStore ? "s3" : "none",
|
|
153
|
-
// Never the resolver's URL or token: only whether one is set (F9 C1).
|
|
154
|
-
resolver: stack.gates?.resolver ? "configured" : "none",
|
|
155
167
|
});
|
|
168
|
+
warnRemovedSettings(stack, logger);
|
|
156
169
|
const database = createDatabase(stack);
|
|
157
170
|
const servers = [];
|
|
158
171
|
try {
|
|
@@ -224,13 +237,14 @@ export async function main() {
|
|
|
224
237
|
const config = loadJson(paths.config);
|
|
225
238
|
const credentials = loadJson(paths.credentials);
|
|
226
239
|
const identityFile = stack.tenant?.identityFile;
|
|
227
|
-
const issuers = identityFile ? loadIssuers(identityFile) : undefined;
|
|
228
240
|
const logger = createHostLogger();
|
|
241
|
+
const issuers = identityFile ? loadIssuers(identityFile, logger) : undefined;
|
|
229
242
|
if (issuers)
|
|
230
243
|
logger.info("trusted_issuers", {
|
|
231
244
|
file: identityFile,
|
|
232
245
|
issuers: issuers.issuers.map((issuer) => issuer.config.name),
|
|
233
246
|
});
|
|
247
|
+
warnRemovedSettings(stack, logger);
|
|
234
248
|
if (stack.deprecatedRole)
|
|
235
249
|
logger.warn("deprecated_flag", {
|
|
236
250
|
flag: "--role",
|
|
@@ -258,7 +272,6 @@ export async function main() {
|
|
|
258
272
|
logger,
|
|
259
273
|
...(stack.delivery ? { delivery: stack.delivery } : {}),
|
|
260
274
|
...(issuers ? { issuers } : {}),
|
|
261
|
-
...(stack.publicUrl ? { publicUrl: stack.publicUrl } : {}),
|
|
262
275
|
});
|
|
263
276
|
// The process's Durable Session Execution: Restate when its endpoints are set, else the
|
|
264
277
|
// in-process memory execution. An invocation that arrives while the Tenant opens waits for it.
|
|
@@ -362,6 +375,10 @@ export async function main() {
|
|
|
362
375
|
coreVersion: coreVersion(),
|
|
363
376
|
...(stack.listen ? { listen: stack.listen } : {}),
|
|
364
377
|
...(infra.readiness ? { readiness: infra.readiness } : {}),
|
|
378
|
+
resourceServer: {
|
|
379
|
+
...(issuers ? { issuers } : {}),
|
|
380
|
+
...(stack.publicUrl ? { publicUrl: stack.publicUrl } : {}),
|
|
381
|
+
},
|
|
365
382
|
// SIGTERM closes the Host this way: stop the Worker and the relay, close the Tenant, then end the infrastructure clients.
|
|
366
383
|
shutdown: {
|
|
367
384
|
beforeTenants: async () => {
|
|
@@ -54,14 +54,6 @@ export interface GatesConfig {
|
|
|
54
54
|
listen: ContainerListen;
|
|
55
55
|
/** `NYLORUN_GATES_TOKEN`: the bearer the loop presents; at least 32 bytes as hex. */
|
|
56
56
|
token: string;
|
|
57
|
-
/**
|
|
58
|
-
* The operator's credential resolver (`NYLORUN_RESOLVER_URL`, `NYLORUN_RESOLVER_TOKEN`), asked
|
|
59
|
-
* for a person's MCP credential when the session's vaults hold none (F9 C1). Absent: vaults only.
|
|
60
|
-
*/
|
|
61
|
-
resolver?: {
|
|
62
|
-
url: string;
|
|
63
|
-
token: string;
|
|
64
|
-
};
|
|
65
57
|
}
|
|
66
58
|
/** egress-gate's listener (`NYLORUN_EGRESS_LISTEN_HOST`, `NYLORUN_EGRESS_LISTEN_PORT`). */
|
|
67
59
|
export interface EgressConfig {
|
|
@@ -168,6 +160,11 @@ export interface StackConfig {
|
|
|
168
160
|
packing?: "combined" | "split";
|
|
169
161
|
/** Set when the process was started with the deprecated `--role` (logged at startup). */
|
|
170
162
|
deprecatedRole?: RuntimeRole;
|
|
163
|
+
/**
|
|
164
|
+
* The removed credential resolver's variables (`NYLORUN_RESOLVER_*`, protocol 10) the
|
|
165
|
+
* environment still sets: ignored, and logged at startup as `resolver_removed`.
|
|
166
|
+
*/
|
|
167
|
+
removedResolverVariables?: string[];
|
|
171
168
|
/** Present in container mode; absent means bind what host.json names. */
|
|
172
169
|
listen?: ContainerListen;
|
|
173
170
|
endpoints: StackEndpoints;
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* `NYLORUN_GATES_TOKEN`. In a container, loop requires the gate: the loop
|
|
16
16
|
* process must never hold a model credential. `egress` (egress-gate, F7.2) joins gates and keys
|
|
17
17
|
* in the gateway and parses its listener (`NYLORUN_EGRESS_LISTEN_*`, default `0.0.0.0:4200`).
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* The credential resolver is gone (protocol 10): its `NYLORUN_RESOLVER_*` variables are ignored,
|
|
19
|
+
* and the Host logs `resolver_removed` when one is set.
|
|
20
20
|
*
|
|
21
21
|
* `harness` (F6.2) runs alone: it holds the harness credential and nothing else. It connects to
|
|
22
22
|
* core's Harness API listener (`NYLORUN_HARNESS_URL`, `NYLORUN_HARNESS_TOKEN`), calls models and
|
|
@@ -66,7 +66,7 @@ export const DEFAULT_SERVICES = new Set([
|
|
|
66
66
|
]);
|
|
67
67
|
/** Services of the blueprint this release doesn't have yet. */
|
|
68
68
|
const LATER_SERVICES = [
|
|
69
|
-
"
|
|
69
|
+
"sandboxes",
|
|
70
70
|
];
|
|
71
71
|
const ROLE_SERVICES = {
|
|
72
72
|
api: ["core"],
|
|
@@ -304,9 +304,13 @@ export function parseStackConfig(env, argv) {
|
|
|
304
304
|
const delivery = parseDelivery(env);
|
|
305
305
|
const tenant = servesApi ? parseTenant(env) : undefined;
|
|
306
306
|
const objectStore = parseObjectStore(env);
|
|
307
|
+
const removedResolverVariables = Object.keys(env)
|
|
308
|
+
.filter((name) => name.startsWith(REMOVED_RESOLVER_PREFIX) && read(env, name) !== undefined)
|
|
309
|
+
.sort();
|
|
307
310
|
return {
|
|
308
311
|
services,
|
|
309
312
|
...(deprecatedRole ? { deprecatedRole } : {}),
|
|
313
|
+
...(removedResolverVariables.length ? { removedResolverVariables } : {}),
|
|
310
314
|
...(gates ? { gates } : {}),
|
|
311
315
|
...(egress ? { egress } : {}),
|
|
312
316
|
...(modelGate ? { modelGate } : {}),
|
|
@@ -509,28 +513,13 @@ function parseGates(env) {
|
|
|
509
513
|
throw new StackConfigError("NYLORUN_GATES_TOKEN is required for --service gates: the token the loop presents (`nylorun start` sets it)");
|
|
510
514
|
if (!GATES_TOKEN.test(token))
|
|
511
515
|
throw new StackConfigError("NYLORUN_GATES_TOKEN must be at least 32 bytes as hex");
|
|
512
|
-
const resolver = parseResolver(env);
|
|
513
516
|
return {
|
|
514
517
|
listen: { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] },
|
|
515
518
|
token,
|
|
516
|
-
...(resolver ? { resolver } : {}),
|
|
517
519
|
};
|
|
518
520
|
}
|
|
519
|
-
/**
|
|
520
|
-
|
|
521
|
-
const url = parseUrl(env, "NYLORUN_RESOLVER_URL", ["http:", "https:"]);
|
|
522
|
-
const token = read(env, "NYLORUN_RESOLVER_TOKEN");
|
|
523
|
-
if (url === undefined) {
|
|
524
|
-
if (token !== undefined)
|
|
525
|
-
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is set without NYLORUN_RESOLVER_URL: set the URL of your credential resolver");
|
|
526
|
-
return undefined;
|
|
527
|
-
}
|
|
528
|
-
if (token === undefined)
|
|
529
|
-
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN is required with NYLORUN_RESOLVER_URL: the bearer the gateway presents to your credential resolver");
|
|
530
|
-
if (/\s/.test(token))
|
|
531
|
-
throw new StackConfigError("NYLORUN_RESOLVER_TOKEN cannot contain whitespace");
|
|
532
|
-
return { url, token };
|
|
533
|
-
}
|
|
521
|
+
/** The prefix of the credential resolver's variables (removed in protocol 10). */
|
|
522
|
+
const REMOVED_RESOLVER_PREFIX = "NYLORUN_RESOLVER_";
|
|
534
523
|
/** `StackConfig.egress` from `NYLORUN_EGRESS_LISTEN_*`. CONNECT has no Host header to check. */
|
|
535
524
|
function parseEgress(env) {
|
|
536
525
|
const host = read(env, "NYLORUN_EGRESS_LISTEN_HOST") ?? DEFAULT_CONTAINER_LISTEN_HOST;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export { parseIdentityFile, IdentityFileError, type TrustedIssuerConfig, } from
|
|
|
4
4
|
export { createTrustedIssuers, type TrustedIssuers, type TrustedIssuersOptions, } from "./tenant/issuers.js";
|
|
5
5
|
export type { TenantConfig, TenantHandle, TenantPaths, Logger, OpenTenantRuntime, } from "./tenant/types.js";
|
|
6
6
|
export { scriptedModel, gatewayModel, type ModelProvider } from "./core/provider.js";
|
|
7
|
-
export type { ResolverConfig } from "./vault/sources.js";
|
|
8
7
|
export type { RuntimeAgent } from "./contracts.js";
|
|
9
8
|
export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
|
|
10
9
|
export type { RuntimeModelAdapter } from "./contracts.js";
|
package/dist/infra/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Host's infrastructure clients, built from the stack configuration: the
|
|
3
3
|
* Postgres pool, Durable Session Execution and Durable Streams, each only when
|
|
4
|
-
* its endpoints are configured, plus the readiness that covers
|
|
4
|
+
* its endpoints are configured, plus the readiness that covers Postgres and
|
|
5
|
+
* Restate (not S2: `readiness.ts`).
|
|
5
6
|
*
|
|
6
7
|
* Building a client connects to nothing: the pool connects on first query,
|
|
7
8
|
* Restate and S2 on first call. Nothing here starts a Worker (see
|
package/dist/infra/index.js
CHANGED
|
@@ -20,7 +20,6 @@ export function createInfra(config, options = {}) {
|
|
|
20
20
|
const probes = infraProbes({
|
|
21
21
|
...(database ? { database } : {}),
|
|
22
22
|
...(execution ? { execution } : {}),
|
|
23
|
-
...(streams ? { streams } : {}),
|
|
24
23
|
});
|
|
25
24
|
const readiness = Object.keys(probes).length > 0
|
|
26
25
|
? logTransitions(createReadiness(probes), options.logger)
|