@nylorun/runtime 0.24.0-beta → 0.26.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 +143 -0
- package/README.md +18 -4
- package/dist/api/a2a/card.d.ts +11 -1
- package/dist/api/a2a/card.js +26 -2
- package/dist/api/a2a/endpoint.js +4 -2
- package/dist/api/a2a/protocol.d.ts +25 -2
- package/dist/api/a2a/protocol.js +20 -3
- package/dist/api/a2a/routes.d.ts +4 -1
- package/dist/api/a2a/routes.js +65 -7
- package/dist/api/ag-ui/endpoint.js +5 -2
- package/dist/api/ag-ui/history.d.ts +6 -1
- package/dist/api/ag-ui/history.js +35 -2
- package/dist/api/ag-ui/routes.js +53 -11
- package/dist/api/components.d.ts +1165 -678
- package/dist/api/components.js +16 -1
- package/dist/api/gate/keys.d.ts +2 -1
- package/dist/api/gate/keys.js +7 -0
- package/dist/api/gate/routes.js +13 -0
- package/dist/api/http/app.d.ts +2 -2
- package/dist/api/http/app.js +15 -4
- package/dist/api/http/body.d.ts +3 -3
- package/dist/api/http/body.js +7 -7
- package/dist/api/http/define.d.ts +1 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/environment-manifests.d.ts +9 -0
- package/dist/api/http/routes/environment-manifests.js +118 -0
- package/dist/api/http/routes/environments.js +61 -12
- package/dist/api/http/routes/reads.d.ts +52 -3
- package/dist/api/http/routes/sessions.js +14 -4
- package/dist/api/http/routes/tenant.js +35 -7
- package/dist/api/inbound-files.d.ts +65 -0
- package/dist/api/inbound-files.js +115 -0
- package/dist/api/openapi.js +18 -3
- package/dist/artifacts/disk.js +20 -14
- package/dist/artifacts/media-types.d.ts +15 -0
- package/dist/artifacts/media-types.js +56 -4
- package/dist/artifacts/parts.d.ts +12 -3
- package/dist/artifacts/parts.js +15 -4
- package/dist/artifacts/workspace.d.ts +4 -4
- package/dist/artifacts/workspace.js +6 -18
- package/dist/core/flow-host.d.ts +1 -1
- package/dist/core/flow-host.js +2 -2
- package/dist/core/sandbox-routes.js +2 -2
- package/dist/core/turn-manifest.d.ts +3 -2
- package/dist/core/turn-manifest.js +29 -5
- package/dist/gates/egress-credentials.js +1 -1
- package/dist/gates/egress.d.ts +13 -19
- package/dist/gates/egress.js +32 -29
- package/dist/gates/http-tool.d.ts +3 -4
- package/dist/gates/http-tool.js +23 -19
- package/dist/gates/journal.js +0 -1
- package/dist/gates/mcp-handler.js +2 -3
- package/dist/gates/policy.js +1 -3
- package/dist/gates/tool-contract.d.ts +1 -1
- package/dist/harness/calls.d.ts +2 -2
- package/dist/harness/calls.js +9 -12
- package/dist/harness/main.js +7 -1
- package/dist/harness/pod.d.ts +6 -1
- package/dist/harness/pod.js +5 -0
- package/dist/harness/service.js +5 -5
- package/dist/harness/setup.d.ts +2 -0
- package/dist/harness/setup.js +25 -1
- package/dist/harness-api/record.d.ts +1 -1
- package/dist/harness-api/record.js +13 -13
- package/dist/harness-api/server.d.ts +27 -4
- package/dist/harness-api/server.js +41 -8
- package/dist/harness-api/tool-journal.d.ts +17 -8
- package/dist/harness-api/tool-journal.js +41 -11
- package/dist/harness-api/workspace.d.ts +7 -5
- package/dist/harness-api/workspace.js +25 -19
- package/dist/host/gates.js +2 -2
- package/dist/host/stack-config.js +1 -1
- package/dist/keys/contract.d.ts +1 -1
- package/dist/keys/contract.js +1 -1
- package/dist/keys/keys.d.ts +9 -2
- package/dist/keys/keys.js +4 -1
- package/dist/management-openapi.json +366 -61
- package/dist/mcp/connect.d.ts +1 -2
- package/dist/mcp/connect.js +1 -4
- package/dist/mcp/pool.d.ts +1 -4
- package/dist/mcp/pool.js +13 -27
- package/dist/mcp/preview.d.ts +1 -1
- package/dist/mcp/preview.js +1 -2
- package/dist/mcp/snapshot.d.ts +11 -13
- package/dist/mcp/snapshot.js +27 -38
- package/dist/model/capabilities.d.ts +26 -0
- package/dist/model/capabilities.js +44 -0
- package/dist/model/catalog.d.ts +34 -3
- package/dist/model/catalog.js +38 -2
- package/dist/model/models.d.ts +2 -0
- package/dist/model/models.js +1 -1
- package/dist/model/native-blocks.d.ts +35 -0
- package/dist/model/native-blocks.js +170 -0
- package/dist/model/pi-model.js +106 -94
- package/dist/openapi.json +9554 -5076
- package/dist/record/environment.js +1 -1
- package/dist/sandbox/join.js +4 -0
- package/dist/sandbox/manager.d.ts +32 -14
- package/dist/sandbox/manager.js +132 -93
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +2 -2
- package/dist/sandbox/pods/client.d.ts +3 -1
- package/dist/sandbox/pods/lifecycle.d.ts +8 -0
- package/dist/sandbox/pods/lifecycle.js +15 -0
- package/dist/sandbox/pods/spec.js +2 -1
- package/dist/sandbox/resolve.d.ts +5 -3
- package/dist/sandbox/resolve.js +9 -2
- package/dist/sandbox/runtime-tools.d.ts +9 -0
- package/dist/sandbox/runtime-tools.js +16 -0
- package/dist/sandbox/session-sandbox.d.ts +4 -6
- package/dist/sandbox/session-sandbox.js +47 -94
- package/dist/sandbox/setup.d.ts +4 -1
- package/dist/sandbox/setup.js +46 -9
- package/dist/sandbox/share.d.ts +12 -7
- package/dist/sandbox/share.js +27 -25
- package/dist/sandbox/skills.d.ts +8 -6
- package/dist/sandbox/skills.js +24 -23
- package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
- package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
- package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
- package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/migrate.js +1 -1
- package/dist/store/postgres/reads.js +8 -2
- package/dist/store/postgres/schema.d.ts +217 -0
- package/dist/store/postgres/schema.js +36 -2
- package/dist/store/postgres/store.js +79 -4
- package/dist/store/types.d.ts +68 -14
- package/dist/tenant/advance.js +3 -0
- package/dist/tenant/artifact-tool.d.ts +1 -1
- package/dist/tenant/artifact-tool.js +43 -22
- package/dist/tenant/commands.js +24 -4
- package/dist/tenant/context.d.ts +10 -4
- package/dist/tenant/effects.js +7 -9
- package/dist/tenant/environment-manifests.d.ts +57 -0
- package/dist/tenant/environment-manifests.js +200 -0
- package/dist/tenant/environments.d.ts +54 -47
- package/dist/tenant/environments.js +309 -85
- package/dist/tenant/ephemeral.d.ts +1 -1
- package/dist/tenant/host-token.js +1 -1
- package/dist/tenant/identity-file.d.ts +1 -1
- package/dist/tenant/identity-file.js +1 -1
- package/dist/tenant/model-setting.d.ts +14 -0
- package/dist/tenant/model-setting.js +51 -0
- package/dist/tenant/outbound.d.ts +6 -5
- package/dist/tenant/outbound.js +8 -6
- package/dist/tenant/sessions.d.ts +5 -1
- package/dist/tenant/sessions.js +45 -12
- package/dist/tenant/skill-tool.d.ts +3 -3
- package/dist/tenant/skill-tool.js +6 -11
- package/dist/tenant/sweep.js +1 -1
- package/dist/tenant/tool-results.js +1 -1
- package/dist/tenant/tool-search.d.ts +7 -11
- package/dist/tenant/tool-search.js +8 -5
- package/dist/tenant/transcript.d.ts +51 -32
- package/dist/tenant/transcript.js +2 -1
- package/dist/tenant/types.d.ts +2 -2
- package/dist/traces/ids.d.ts +0 -1
- package/dist/traces/ids.js +0 -4
- package/dist/traces/map.d.ts +2 -2
- package/dist/traces/map.js +1 -29
- package/dist/vault/coverage.js +11 -13
- package/dist/vault/host-model.d.ts +4 -1
- package/dist/vault/host-model.js +10 -2
- package/dist/vault/service.d.ts +49 -4
- package/dist/vault/service.js +153 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/sandbox/capability.d.ts +0 -3
- package/dist/sandbox/capability.js +0 -10
package/dist/mcp/connect.d.ts
CHANGED
|
@@ -202,7 +202,6 @@ export declare function serverInstructions(text: unknown, secrets: readonly stri
|
|
|
202
202
|
* collides gets the hash suffix first.
|
|
203
203
|
*/
|
|
204
204
|
export declare function listMcpTools(client: McpClient, input: {
|
|
205
|
-
capabilityId: string;
|
|
206
205
|
serverName: string;
|
|
207
206
|
taken: Set<string>;
|
|
208
207
|
signal?: AbortSignal;
|
|
@@ -224,4 +223,4 @@ export declare function listMcpTools(client: McpClient, input: {
|
|
|
224
223
|
* unknown.
|
|
225
224
|
*/
|
|
226
225
|
export declare function callMcpTool(client: McpClient, serverToolName: string, args: unknown, options?: McpCallOptions): Promise<McpToolOutcome>;
|
|
227
|
-
export declare function diagnosticFromError(
|
|
226
|
+
export declare function diagnosticFromError(serverName: string, error: unknown): McpDiagnostic;
|
package/dist/mcp/connect.js
CHANGED
|
@@ -285,7 +285,6 @@ export async function listMcpTools(client, input) {
|
|
|
285
285
|
const { tool, inputSchema } = candidate;
|
|
286
286
|
const outputSchema = tool.outputSchema ? usableSchema(tool.outputSchema) : undefined;
|
|
287
287
|
tools.push({
|
|
288
|
-
capabilityId: input.capabilityId,
|
|
289
288
|
serverName: input.serverName,
|
|
290
289
|
serverToolName: tool.name,
|
|
291
290
|
name,
|
|
@@ -353,14 +352,13 @@ function onlyText(content) {
|
|
|
353
352
|
return (Array.isArray(content) &&
|
|
354
353
|
content.every((part) => !!part && typeof part === "object" && part.type === "text"));
|
|
355
354
|
}
|
|
356
|
-
export function diagnosticFromError(
|
|
355
|
+
export function diagnosticFromError(serverName, error) {
|
|
357
356
|
const credentialIds = error && typeof error === "object" && "credentialIds" in error
|
|
358
357
|
? error.credentialIds
|
|
359
358
|
: undefined;
|
|
360
359
|
const refused = error instanceof Error && error.message.startsWith("MCP authorization refused");
|
|
361
360
|
if (refused) {
|
|
362
361
|
return {
|
|
363
|
-
capabilityId,
|
|
364
362
|
serverName,
|
|
365
363
|
outcome: "refused",
|
|
366
364
|
message: error.message,
|
|
@@ -374,7 +372,6 @@ export function diagnosticFromError(capabilityId, serverName, error) {
|
|
|
374
372
|
code === 401 ||
|
|
375
373
|
(error instanceof Error && /\b401\b/.test(error.message));
|
|
376
374
|
return {
|
|
377
|
-
capabilityId,
|
|
378
375
|
serverName,
|
|
379
376
|
outcome: "failed",
|
|
380
377
|
message: unauthorized
|
package/dist/mcp/pool.d.ts
CHANGED
|
@@ -51,7 +51,6 @@ export declare class McpPool {
|
|
|
51
51
|
call(input: {
|
|
52
52
|
sessionId: string;
|
|
53
53
|
agentId?: string;
|
|
54
|
-
capabilityId: string;
|
|
55
54
|
serverName: string;
|
|
56
55
|
serverToolName: string;
|
|
57
56
|
args: unknown;
|
|
@@ -85,7 +84,6 @@ export interface McpServerRef {
|
|
|
85
84
|
readonly sessionId: string;
|
|
86
85
|
/** The agent used as a tool that declares the server; absent for the session's root agent. */
|
|
87
86
|
readonly agentId?: string;
|
|
88
|
-
readonly capabilityId: string;
|
|
89
87
|
readonly serverName: string;
|
|
90
88
|
}
|
|
91
89
|
export interface DeclaredServer {
|
|
@@ -93,9 +91,8 @@ export interface DeclaredServer {
|
|
|
93
91
|
readonly agentId?: string;
|
|
94
92
|
/** The manifest of the agent that declares the server. */
|
|
95
93
|
readonly manifest: AgentManifest;
|
|
96
|
-
readonly capabilityId: string;
|
|
97
94
|
readonly server: McpServerManifest;
|
|
98
95
|
}
|
|
99
96
|
/** Servers of the root agent, then of each agent it uses as a tool. */
|
|
100
97
|
export declare function serversOf(manifest: AgentManifest): DeclaredServer[];
|
|
101
|
-
export declare function findServer(manifest: AgentManifest, agentId: string | undefined,
|
|
98
|
+
export declare function findServer(manifest: AgentManifest, agentId: string | undefined, serverName: string): DeclaredServer | undefined;
|
package/dist/mcp/pool.js
CHANGED
|
@@ -34,7 +34,6 @@ export class McpPool {
|
|
|
34
34
|
if (!taken.has(declared.agentId))
|
|
35
35
|
taken.set(declared.agentId, declaredToolNames(declared.manifest));
|
|
36
36
|
const listed = await listMcpTools(opened.connection.client, {
|
|
37
|
-
capabilityId: declared.capabilityId,
|
|
38
37
|
serverName: declared.server.name,
|
|
39
38
|
taken: taken.get(declared.agentId),
|
|
40
39
|
server: declared.server,
|
|
@@ -43,13 +42,11 @@ export class McpPool {
|
|
|
43
42
|
tools.push(...listed.tools.map((tool) => owned(declared, tool)));
|
|
44
43
|
if (opened.connection.instructions)
|
|
45
44
|
notes.push(owned(declared, {
|
|
46
|
-
capabilityId: declared.capabilityId,
|
|
47
45
|
serverName: declared.server.name,
|
|
48
46
|
instructions: opened.connection.instructions,
|
|
49
47
|
}));
|
|
50
48
|
diagnostics.push({
|
|
51
49
|
...ownerOf(declared),
|
|
52
|
-
capabilityId: declared.capabilityId,
|
|
53
50
|
serverName: declared.server.name,
|
|
54
51
|
outcome: "connected",
|
|
55
52
|
message: [
|
|
@@ -67,7 +64,7 @@ export class McpPool {
|
|
|
67
64
|
}
|
|
68
65
|
catch (error) {
|
|
69
66
|
await opened.connection.close().catch(() => { });
|
|
70
|
-
diagnostics.push(owned(declared, diagnosticFromError(declared.
|
|
67
|
+
diagnostics.push(owned(declared, diagnosticFromError(declared.server.name, error)));
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
70
|
return {
|
|
@@ -84,7 +81,7 @@ export class McpPool {
|
|
|
84
81
|
const diagnostics = [];
|
|
85
82
|
const seen = new Set();
|
|
86
83
|
for (const tool of input.tools) {
|
|
87
|
-
const key = this.liveKey(input.sessionId, tool.agentId, tool.
|
|
84
|
+
const key = this.liveKey(input.sessionId, tool.agentId, tool.serverName);
|
|
88
85
|
if (seen.has(key))
|
|
89
86
|
continue;
|
|
90
87
|
seen.add(key);
|
|
@@ -95,11 +92,10 @@ export class McpPool {
|
|
|
95
92
|
continue;
|
|
96
93
|
}
|
|
97
94
|
input.signal?.throwIfAborted();
|
|
98
|
-
const declared = findServer(input.manifest, tool.agentId, tool.
|
|
95
|
+
const declared = findServer(input.manifest, tool.agentId, tool.serverName);
|
|
99
96
|
if (!declared) {
|
|
100
97
|
diagnostics.push({
|
|
101
98
|
...(tool.agentId === undefined ? {} : { agentId: tool.agentId }),
|
|
102
|
-
capabilityId: tool.capabilityId,
|
|
103
99
|
serverName: tool.serverName,
|
|
104
100
|
outcome: "failed",
|
|
105
101
|
message: "Declared MCP server is missing from the pinned manifest",
|
|
@@ -116,7 +112,7 @@ export class McpPool {
|
|
|
116
112
|
return diagnostics;
|
|
117
113
|
}
|
|
118
114
|
async call(input) {
|
|
119
|
-
const key = this.liveKey(input.sessionId, input.agentId, input.
|
|
115
|
+
const key = this.liveKey(input.sessionId, input.agentId, input.serverName);
|
|
120
116
|
for (let attempt = 0;; attempt += 1) {
|
|
121
117
|
const live = await this.liveFor(input, key);
|
|
122
118
|
// No connection, so no call was sent: the model sees why, a 401 included (R2b C1, C7).
|
|
@@ -152,7 +148,7 @@ export class McpPool {
|
|
|
152
148
|
const live = this.live.get(key);
|
|
153
149
|
if (live)
|
|
154
150
|
return live;
|
|
155
|
-
const declared = findServer(input.manifest, input.agentId, input.
|
|
151
|
+
const declared = findServer(input.manifest, input.agentId, input.serverName);
|
|
156
152
|
if (!declared)
|
|
157
153
|
throw new Error(`MCP server '${input.serverName}' is not declared`);
|
|
158
154
|
let opening = this.opening.get(key);
|
|
@@ -196,7 +192,7 @@ export class McpPool {
|
|
|
196
192
|
}
|
|
197
193
|
/** Keeps the connection, or closes it when the server is already connected for the session. */
|
|
198
194
|
remember(sessionId, declared, connection) {
|
|
199
|
-
const key = this.liveKey(sessionId, declared.agentId, declared.
|
|
195
|
+
const key = this.liveKey(sessionId, declared.agentId, declared.server.name);
|
|
200
196
|
const existing = this.live.get(key);
|
|
201
197
|
if (existing) {
|
|
202
198
|
if (existing.connection !== connection)
|
|
@@ -204,7 +200,6 @@ export class McpPool {
|
|
|
204
200
|
return existing;
|
|
205
201
|
}
|
|
206
202
|
const live = {
|
|
207
|
-
capabilityId: declared.capabilityId,
|
|
208
203
|
serverName: declared.server.name,
|
|
209
204
|
connection,
|
|
210
205
|
lastUsedAt: this.now(),
|
|
@@ -213,8 +208,8 @@ export class McpPool {
|
|
|
213
208
|
this.live.set(key, live);
|
|
214
209
|
return live;
|
|
215
210
|
}
|
|
216
|
-
liveKey(sessionId, agentId,
|
|
217
|
-
return JSON.stringify([sessionId, agentId ?? null,
|
|
211
|
+
liveKey(sessionId, agentId, serverName) {
|
|
212
|
+
return JSON.stringify([sessionId, agentId ?? null, serverName]);
|
|
218
213
|
}
|
|
219
214
|
async connectDeclared(input, declared) {
|
|
220
215
|
try {
|
|
@@ -222,7 +217,6 @@ export class McpPool {
|
|
|
222
217
|
const connection = await this.options.openRemote({
|
|
223
218
|
sessionId: input.sessionId,
|
|
224
219
|
...ownerOf(declared),
|
|
225
|
-
capabilityId: declared.capabilityId,
|
|
226
220
|
serverName: declared.server.name,
|
|
227
221
|
});
|
|
228
222
|
return { ok: true, connection };
|
|
@@ -242,7 +236,7 @@ export class McpPool {
|
|
|
242
236
|
return {
|
|
243
237
|
ok: false,
|
|
244
238
|
error,
|
|
245
|
-
diagnostic: owned(declared, diagnosticFromError(declared.
|
|
239
|
+
diagnostic: owned(declared, diagnosticFromError(declared.server.name, error)),
|
|
246
240
|
};
|
|
247
241
|
}
|
|
248
242
|
}
|
|
@@ -251,24 +245,16 @@ export class McpPool {
|
|
|
251
245
|
export function serversOf(manifest) {
|
|
252
246
|
const servers = [];
|
|
253
247
|
const add = (agent, agentId) => {
|
|
254
|
-
for (const
|
|
255
|
-
|
|
256
|
-
servers.push({
|
|
257
|
-
...(agentId === undefined ? {} : { agentId }),
|
|
258
|
-
manifest: agent,
|
|
259
|
-
capabilityId: capability.id,
|
|
260
|
-
server,
|
|
261
|
-
});
|
|
248
|
+
for (const server of Object.values(agent.mcpServers ?? {}))
|
|
249
|
+
servers.push({ ...(agentId === undefined ? {} : { agentId }), manifest: agent, server });
|
|
262
250
|
};
|
|
263
251
|
add(manifest);
|
|
264
252
|
for (const child of delegatesOf(manifest))
|
|
265
253
|
add(child.manifest, child.manifest.id);
|
|
266
254
|
return servers;
|
|
267
255
|
}
|
|
268
|
-
export function findServer(manifest, agentId,
|
|
269
|
-
return serversOf(manifest).find((item) => item.agentId === agentId &&
|
|
270
|
-
item.capabilityId === capabilityId &&
|
|
271
|
-
item.server.name === serverName);
|
|
256
|
+
export function findServer(manifest, agentId, serverName) {
|
|
257
|
+
return serversOf(manifest).find((item) => item.agentId === agentId && item.server.name === serverName);
|
|
272
258
|
}
|
|
273
259
|
function ownerOf(declared) {
|
|
274
260
|
return declared.agentId === undefined ? {} : { agentId: declared.agentId };
|
package/dist/mcp/preview.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A remote MCP server's tools before an agent names it (R2b C12, `POST /v1/tenant/mcp/preview`,
|
|
3
|
-
* `nylorun mcp inspect`, an Environment's Secrets tab in Studio). It runs where plaintext credentials live:
|
|
3
|
+
* `nylorun tenant mcp inspect`, an Environment's Secrets tab in Studio). It runs where plaintext credentials live:
|
|
4
4
|
* the keys service (`keys/keys.ts`, `previewMcp`), in the gateway or in process.
|
|
5
5
|
*
|
|
6
6
|
* One connection: `initialize` and `tools/list` with the Environment's credential for the
|
package/dist/mcp/preview.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A remote MCP server's tools before an agent names it (R2b C12, `POST /v1/tenant/mcp/preview`,
|
|
3
|
-
* `nylorun mcp inspect`, an Environment's Secrets tab in Studio). It runs where plaintext credentials live:
|
|
3
|
+
* `nylorun tenant mcp inspect`, an Environment's Secrets tab in Studio). It runs where plaintext credentials live:
|
|
4
4
|
* the keys service (`keys/keys.ts`, `previewMcp`), in the gateway or in process.
|
|
5
5
|
*
|
|
6
6
|
* One connection: `initialize` and `tools/list` with the Environment's credential for the
|
|
@@ -72,7 +72,6 @@ export async function previewMcpServer(body, options) {
|
|
|
72
72
|
callTool: () => Promise.reject(new Error("A preview never calls a tool")),
|
|
73
73
|
};
|
|
74
74
|
const listed = await listMcpTools(listing, {
|
|
75
|
-
capabilityId: "preview",
|
|
76
75
|
serverName: name,
|
|
77
76
|
taken: new Set(),
|
|
78
77
|
signal,
|
package/dist/mcp/snapshot.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type { DurableSessionTool, HostEffect } from "@nylorun/harness/run";
|
|
|
5
5
|
export interface McpToolRecord {
|
|
6
6
|
/** The agent used as a tool that declares the server; absent for the session's root agent. */
|
|
7
7
|
readonly agentId?: string;
|
|
8
|
-
readonly capabilityId: string;
|
|
9
8
|
readonly serverName: string;
|
|
10
9
|
/** The tool's name on its server, which the call sends. */
|
|
11
10
|
readonly serverToolName: string;
|
|
@@ -23,7 +22,6 @@ export interface McpToolRecord {
|
|
|
23
22
|
/** A server's own instructions (MCP `initialize`), for the note on its deferred tools (R2b C10). */
|
|
24
23
|
export interface McpServerNote {
|
|
25
24
|
readonly agentId?: string;
|
|
26
|
-
readonly capabilityId: string;
|
|
27
25
|
readonly serverName: string;
|
|
28
26
|
/** Cut to `SERVER_INSTRUCTIONS_MAX_CHARS`. */
|
|
29
27
|
readonly instructions: string;
|
|
@@ -38,7 +36,6 @@ export interface McpSnapshot {
|
|
|
38
36
|
export interface McpDiagnostic {
|
|
39
37
|
/** The agent used as a tool that declares the server; absent for the session's root agent. */
|
|
40
38
|
readonly agentId?: string;
|
|
41
|
-
readonly capabilityId: string;
|
|
42
39
|
readonly serverName: string;
|
|
43
40
|
readonly outcome: "connected" | "refused" | "failed";
|
|
44
41
|
readonly message: string;
|
|
@@ -55,8 +52,11 @@ export interface McpRenamedTool {
|
|
|
55
52
|
readonly serverToolName: string;
|
|
56
53
|
readonly name: string;
|
|
57
54
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The `mcp.discovered` payload: each server's outcome, with the tools it added to the snapshot,
|
|
57
|
+
* and the Agent Plugin that brought the server (from `manifest`, the session's pinned one).
|
|
58
|
+
*/
|
|
59
|
+
export declare function mcpDiscovered(snapshot: McpSnapshot, diagnostics: readonly McpDiagnostic[], manifest?: AgentManifest): EventPayload<"mcp.discovered">;
|
|
60
60
|
/** The longest tool name every model provider accepts (R2b C6, Q14). */
|
|
61
61
|
export declare const MODEL_TOOL_NAME_MAX = 64;
|
|
62
62
|
/**
|
|
@@ -69,6 +69,7 @@ export declare const MODEL_TOOL_NAME_MAX = 64;
|
|
|
69
69
|
export declare function normalizeToolName(serverName: string, serverToolName: string, options?: {
|
|
70
70
|
readonly suffixed?: boolean;
|
|
71
71
|
}): string;
|
|
72
|
+
/** The names of the agent's tools: its own and those the Runtime pinned. */
|
|
72
73
|
export declare function declaredToolNames(manifest: AgentManifest): Set<string>;
|
|
73
74
|
/** The tool's settings in `manifest` (R2b C9); the defaults when its server is not there. */
|
|
74
75
|
export declare function mcpToolSettingsIn(manifest: AgentManifest, tool: McpToolRecord): ResolvedMcpToolSettings;
|
|
@@ -78,10 +79,9 @@ export declare function mcpToolSettingsIn(manifest: AgentManifest, tool: McpTool
|
|
|
78
79
|
*
|
|
79
80
|
* - a tool its settings disable is left out (R2b C9); the Tool Gate holds a call its approval
|
|
80
81
|
* or the Tenant's tool policy asks a person about (R5 step 2);
|
|
81
|
-
* - a deferred tool (R2b C10) is marked so, out of the model's list, and its agent gets
|
|
82
|
-
* `tool_search`, with the note on the servers it holds deferred tools of, and
|
|
83
|
-
*
|
|
84
|
-
* its list.
|
|
82
|
+
* - a deferred tool (R2b C10) is marked so, out of the model's list, and its agent gets the
|
|
83
|
+
* session tools `tool_search`, with the note on the servers it holds deferred tools of, and
|
|
84
|
+
* `tool_call`. Their names are reserved: no tool of the agent's own takes them.
|
|
85
85
|
*
|
|
86
86
|
* Nothing here changes between the steps of a turn, so neither does the model's tool list.
|
|
87
87
|
*/
|
|
@@ -94,16 +94,14 @@ export declare const CHARS_PER_TOKEN = 4;
|
|
|
94
94
|
* The snapshot with its deferred tools marked (R2b C10, Q21), decided once for the session when
|
|
95
95
|
* core records it. A tool's own setting, then `"*"`'s, then its server's, decides; a tool none
|
|
96
96
|
* sets is deferred when the JSON of its agent's MCP tools that would be listed passes a tenth of
|
|
97
|
-
* the model's context window (`contextWindow` tokens, at 4 characters a token).
|
|
98
|
-
* the `nylorun.tools` capability (its definition names a tool `tool_search` or `tool_call`, or the
|
|
99
|
-
* session was opened before it existed) defers nothing.
|
|
97
|
+
* the model's context window (`contextWindow` tokens, at 4 characters a token).
|
|
100
98
|
*/
|
|
101
99
|
export declare function pinDeferral(snapshot: McpSnapshot, manifest: AgentManifest, contextWindow: number): McpSnapshot;
|
|
102
100
|
/**
|
|
103
101
|
* The snapshot's record of an MCP tool call, or undefined when the call is not an MCP tool. With
|
|
104
102
|
* the turn's `manifest`, a tool its settings disable is not one either (R2b C9).
|
|
105
103
|
*/
|
|
106
|
-
export declare function mcpToolOf(snapshot: McpSnapshot | undefined, request: Pick<HostEffect, "agent" | "
|
|
104
|
+
export declare function mcpToolOf(snapshot: McpSnapshot | undefined, request: Pick<HostEffect, "agent" | "toolName">, manifest?: AgentManifest): McpToolRecord | undefined;
|
|
107
105
|
/** True when the tool's settings in `manifest` leave it enabled (R2b C9). */
|
|
108
106
|
export declare function isEnabledIn(manifest: AgentManifest, tool: McpToolRecord): boolean;
|
|
109
107
|
/** The manifest of the agent an effect belongs to: the root, or an agent it uses as a tool. */
|
package/dist/mcp/snapshot.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { delegatesOf, pluginOf, deferredToolsInstructions, deferredToolsTools, delegateManifest, mcpToolSettings, } from "@nylorun/core/define";
|
|
3
|
+
/**
|
|
4
|
+
* The `mcp.discovered` payload: each server's outcome, with the tools it added to the snapshot,
|
|
5
|
+
* and the Agent Plugin that brought the server (from `manifest`, the session's pinned one).
|
|
6
|
+
*/
|
|
7
|
+
export function mcpDiscovered(snapshot, diagnostics, manifest) {
|
|
8
|
+
const agents = new Map(manifest === undefined
|
|
9
|
+
? []
|
|
10
|
+
: [[undefined, manifest], ...delegatesOf(manifest).map(({ manifest: child }) => [child.id, child])]);
|
|
11
|
+
const key = (item) => JSON.stringify([item.agentId ?? null, item.serverName]);
|
|
6
12
|
const tools = new Map();
|
|
7
13
|
const deferred = new Map();
|
|
8
14
|
for (const tool of snapshot.mcpTools) {
|
|
@@ -13,8 +19,8 @@ export function mcpDiscovered(snapshot, diagnostics) {
|
|
|
13
19
|
return {
|
|
14
20
|
servers: diagnostics.map((item) => ({
|
|
15
21
|
...(item.agentId === undefined ? {} : { agentId: item.agentId }),
|
|
16
|
-
capabilityId: item.capabilityId,
|
|
17
22
|
serverName: item.serverName,
|
|
23
|
+
...withPlugin(pluginOf(agents.get(item.agentId), { server: item.serverName })),
|
|
18
24
|
outcome: item.outcome,
|
|
19
25
|
message: item.message,
|
|
20
26
|
tools: tools.get(key(item)) ?? 0,
|
|
@@ -26,6 +32,9 @@ export function mcpDiscovered(snapshot, diagnostics) {
|
|
|
26
32
|
})),
|
|
27
33
|
};
|
|
28
34
|
}
|
|
35
|
+
function withPlugin(plugin) {
|
|
36
|
+
return plugin === undefined ? {} : { plugin };
|
|
37
|
+
}
|
|
29
38
|
/** The longest tool name every model provider accepts (R2b C6, Q14). */
|
|
30
39
|
export const MODEL_TOOL_NAME_MAX = 64;
|
|
31
40
|
/**
|
|
@@ -45,38 +54,29 @@ export function normalizeToolName(serverName, serverToolName, options = {}) {
|
|
|
45
54
|
.slice(0, 8);
|
|
46
55
|
return `${name.slice(0, MODEL_TOOL_NAME_MAX - 9)}_${hash}`;
|
|
47
56
|
}
|
|
57
|
+
/** The names of the agent's tools: its own and those the Runtime pinned. */
|
|
48
58
|
export function declaredToolNames(manifest) {
|
|
49
|
-
|
|
50
|
-
for (const capability of manifest.capabilities)
|
|
51
|
-
for (const tool of capability.tools ?? [])
|
|
52
|
-
names.add(tool.name);
|
|
53
|
-
return names;
|
|
59
|
+
return new Set([...(manifest.tools ?? []), ...(manifest.runtime?.tools ?? [])].map((tool) => tool.name));
|
|
54
60
|
}
|
|
55
61
|
/** The declaration of the server a tool of the snapshot comes from, in `manifest`. */
|
|
56
62
|
function serverOf(manifest, tool) {
|
|
57
63
|
const agent = tool.agentId === undefined ? manifest : delegateManifest(manifest, tool.agentId);
|
|
58
|
-
return agent?.
|
|
64
|
+
return agent?.mcpServers?.[tool.serverName];
|
|
59
65
|
}
|
|
60
66
|
/** The tool's settings in `manifest` (R2b C9); the defaults when its server is not there. */
|
|
61
67
|
export function mcpToolSettingsIn(manifest, tool) {
|
|
62
68
|
const server = serverOf(manifest, tool);
|
|
63
69
|
return server ? mcpToolSettings(server, tool.serverToolName) : { enabled: true, approval: "never" };
|
|
64
70
|
}
|
|
65
|
-
/** True when the agent the tool belongs to has `tool_search` and `tool_call` (`nylorun.tools`). */
|
|
66
|
-
function reachesDeferred(manifest, agentId) {
|
|
67
|
-
const agent = agentId === undefined ? manifest : delegateManifest(manifest, agentId);
|
|
68
|
-
return agent?.capabilities.some((capability) => capability.id === TOOLS_CAPABILITY_ID) === true;
|
|
69
|
-
}
|
|
70
71
|
/**
|
|
71
72
|
* The tools of a snapshot, as the engine gets them for a turn whose manifest is `manifest` (the
|
|
72
73
|
* session's pin, or a turn variant that tightened its MCP servers' tools):
|
|
73
74
|
*
|
|
74
75
|
* - a tool its settings disable is left out (R2b C9); the Tool Gate holds a call its approval
|
|
75
76
|
* or the Tenant's tool policy asks a person about (R5 step 2);
|
|
76
|
-
* - a deferred tool (R2b C10) is marked so, out of the model's list, and its agent gets
|
|
77
|
-
* `tool_search`, with the note on the servers it holds deferred tools of, and
|
|
78
|
-
*
|
|
79
|
-
* its list.
|
|
77
|
+
* - a deferred tool (R2b C10) is marked so, out of the model's list, and its agent gets the
|
|
78
|
+
* session tools `tool_search`, with the note on the servers it holds deferred tools of, and
|
|
79
|
+
* `tool_call`. Their names are reserved: no tool of the agent's own takes them.
|
|
80
80
|
*
|
|
81
81
|
* Nothing here changes between the steps of a turn, so neither does the model's tool list.
|
|
82
82
|
*/
|
|
@@ -90,10 +90,9 @@ export function sessionToolsOf(snapshot, manifest) {
|
|
|
90
90
|
const settings = mcpToolSettingsIn(manifest, tool);
|
|
91
91
|
if (!settings.enabled)
|
|
92
92
|
continue;
|
|
93
|
-
const defer = tool.deferred === true
|
|
93
|
+
const defer = tool.deferred === true;
|
|
94
94
|
const entry = {
|
|
95
95
|
...(tool.agentId === undefined ? {} : { agentId: tool.agentId }),
|
|
96
|
-
capabilityId: tool.capabilityId,
|
|
97
96
|
name: tool.name,
|
|
98
97
|
...(tool.description === undefined ? {} : { description: tool.description }),
|
|
99
98
|
inputSchema: tool.inputSchema,
|
|
@@ -109,7 +108,7 @@ export function sessionToolsOf(snapshot, manifest) {
|
|
|
109
108
|
servers.set(tool.serverName, (servers.get(tool.serverName) ?? 0) + 1);
|
|
110
109
|
notes.set(tool.agentId, servers);
|
|
111
110
|
}
|
|
112
|
-
const
|
|
111
|
+
const session = [];
|
|
113
112
|
for (const [agentId, tools] of deferred) {
|
|
114
113
|
const servers = [...notes.get(agentId)].map(([serverName, count]) => {
|
|
115
114
|
const instructions = snapshot.servers?.find((item) => item.agentId === agentId && item.serverName === serverName)?.instructions;
|
|
@@ -120,14 +119,10 @@ export function sessionToolsOf(snapshot, manifest) {
|
|
|
120
119
|
{ ...search, instructions: [deferredToolsInstructions(servers)] },
|
|
121
120
|
call,
|
|
122
121
|
])
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
capabilityId: TOOLS_CAPABILITY_ID,
|
|
126
|
-
...tool,
|
|
127
|
-
});
|
|
128
|
-
platform.push(...tools);
|
|
122
|
+
session.push({ ...(agentId === undefined ? {} : { agentId }), ...tool });
|
|
123
|
+
session.push(...tools);
|
|
129
124
|
}
|
|
130
|
-
return [...inline, ...
|
|
125
|
+
return [...inline, ...session];
|
|
131
126
|
}
|
|
132
127
|
/** The share of the model's context window past which an agent's MCP tools are deferred (Q21). */
|
|
133
128
|
export const DEFER_CONTEXT_SHARE = 0.1;
|
|
@@ -137,9 +132,7 @@ export const CHARS_PER_TOKEN = 4;
|
|
|
137
132
|
* The snapshot with its deferred tools marked (R2b C10, Q21), decided once for the session when
|
|
138
133
|
* core records it. A tool's own setting, then `"*"`'s, then its server's, decides; a tool none
|
|
139
134
|
* sets is deferred when the JSON of its agent's MCP tools that would be listed passes a tenth of
|
|
140
|
-
* the model's context window (`contextWindow` tokens, at 4 characters a token).
|
|
141
|
-
* the `nylorun.tools` capability (its definition names a tool `tool_search` or `tool_call`, or the
|
|
142
|
-
* session was opened before it existed) defers nothing.
|
|
135
|
+
* the model's context window (`contextWindow` tokens, at 4 characters a token).
|
|
143
136
|
*/
|
|
144
137
|
export function pinDeferral(snapshot, manifest, contextWindow) {
|
|
145
138
|
const limit = contextWindow * CHARS_PER_TOKEN * DEFER_CONTEXT_SHARE;
|
|
@@ -153,8 +146,6 @@ export function pinDeferral(snapshot, manifest, contextWindow) {
|
|
|
153
146
|
});
|
|
154
147
|
const mcpTools = snapshot.mcpTools.map((tool, i) => {
|
|
155
148
|
const { deferred: _, ...rest } = tool;
|
|
156
|
-
if (!reachesDeferred(manifest, tool.agentId))
|
|
157
|
-
return rest;
|
|
158
149
|
const defer = set[i] ?? (listed.get(tool.agentId) ?? 0) > limit;
|
|
159
150
|
return defer ? { ...rest, deferred: true } : rest;
|
|
160
151
|
});
|
|
@@ -165,9 +156,7 @@ export function pinDeferral(snapshot, manifest, contextWindow) {
|
|
|
165
156
|
* the turn's `manifest`, a tool its settings disable is not one either (R2b C9).
|
|
166
157
|
*/
|
|
167
158
|
export function mcpToolOf(snapshot, request, manifest) {
|
|
168
|
-
const tool = snapshot?.mcpTools.find((tool) => tool.agentId === request.agent?.id &&
|
|
169
|
-
tool.capabilityId === request.capabilityId &&
|
|
170
|
-
tool.name === request.toolName);
|
|
159
|
+
const tool = snapshot?.mcpTools.find((tool) => tool.agentId === request.agent?.id && tool.name === request.toolName);
|
|
171
160
|
if (tool && manifest && !isEnabledIn(manifest, tool))
|
|
172
161
|
return undefined;
|
|
173
162
|
return tool;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a model reads (protocol 12): its pi-ai catalog's `input` (text, image) and what the
|
|
3
|
+
* operator added. One function, `capabilitiesOf`, serves the catalog, the accept check, the Model
|
|
4
|
+
* Gate and `read_artifact`.
|
|
5
|
+
*
|
|
6
|
+
* The operator may add only an input our provider path sends natively for the model's API
|
|
7
|
+
* (`NATIVE_INPUTS`): an image on every API; a PDF on the APIs below; Office documents on the
|
|
8
|
+
* OpenAI Responses APIs; audio and video on Google's APIs and OpenAI-compatible completions.
|
|
9
|
+
*/
|
|
10
|
+
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
11
|
+
import { type ModelInput } from "@nylorun/core/contracts";
|
|
12
|
+
/** What `capabilitiesOf` reads of a pi-ai model. */
|
|
13
|
+
export type ModelShape = Pick<Model<Api>, "api" | "input">;
|
|
14
|
+
/** The inputs each API carries natively, beyond text. Any other API: images only. */
|
|
15
|
+
export declare const NATIVE_INPUTS: Readonly<Record<string, readonly ModelInput[]>>;
|
|
16
|
+
/** What the operator may add to `model`: the inputs its API carries that its catalog lacks. */
|
|
17
|
+
export declare function addableInputs(model: ModelShape): ModelInput[];
|
|
18
|
+
/**
|
|
19
|
+
* What `model` reads: text, its catalog's inputs and those of `added` its API carries, in
|
|
20
|
+
* `MODEL_INPUTS` order.
|
|
21
|
+
*/
|
|
22
|
+
export declare function capabilitiesOf(model: ModelShape, added?: readonly ModelInput[]): {
|
|
23
|
+
readonly inputs: ModelInput[];
|
|
24
|
+
};
|
|
25
|
+
/** Why `inputs` cannot be set for `model`, or undefined when they can. */
|
|
26
|
+
export declare function inputsError(model: ModelShape, inputs: readonly ModelInput[]): string | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { MODEL_INPUTS } from "@nylorun/core/contracts";
|
|
2
|
+
/** The inputs each API carries natively, beyond text. Any other API: images only. */
|
|
3
|
+
export const NATIVE_INPUTS = {
|
|
4
|
+
"anthropic-messages": ["image", "pdf"],
|
|
5
|
+
"openai-responses": ["image", "pdf", "office"],
|
|
6
|
+
"azure-openai-responses": ["image", "pdf", "office"],
|
|
7
|
+
"openai-completions": ["image", "pdf", "audio", "video"],
|
|
8
|
+
"google-generative-ai": ["image", "pdf", "audio", "video"],
|
|
9
|
+
"google-vertex": ["image", "pdf", "audio", "video"],
|
|
10
|
+
};
|
|
11
|
+
function nativeInputs(model) {
|
|
12
|
+
return NATIVE_INPUTS[model.api] ?? ["image"];
|
|
13
|
+
}
|
|
14
|
+
function ordered(inputs) {
|
|
15
|
+
const set = new Set(inputs);
|
|
16
|
+
return MODEL_INPUTS.filter((input) => set.has(input));
|
|
17
|
+
}
|
|
18
|
+
/** What the operator may add to `model`: the inputs its API carries that its catalog lacks. */
|
|
19
|
+
export function addableInputs(model) {
|
|
20
|
+
const own = model.input;
|
|
21
|
+
return ordered(nativeInputs(model).filter((input) => !own.includes(input)));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* What `model` reads: text, its catalog's inputs and those of `added` its API carries, in
|
|
25
|
+
* `MODEL_INPUTS` order.
|
|
26
|
+
*/
|
|
27
|
+
export function capabilitiesOf(model, added = []) {
|
|
28
|
+
const native = nativeInputs(model);
|
|
29
|
+
return {
|
|
30
|
+
inputs: ordered([
|
|
31
|
+
"text",
|
|
32
|
+
...model.input,
|
|
33
|
+
...added.filter((input) => native.includes(input)),
|
|
34
|
+
]),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Why `inputs` cannot be set for `model`, or undefined when they can. */
|
|
38
|
+
export function inputsError(model, inputs) {
|
|
39
|
+
const allowed = new Set(["text", ...model.input, ...nativeInputs(model)]);
|
|
40
|
+
const refused = ordered(inputs.filter((input) => !allowed.has(input)));
|
|
41
|
+
if (refused.length === 0)
|
|
42
|
+
return undefined;
|
|
43
|
+
return `This model's API (${model.api}) cannot carry ${refused.join(", ")}; it can read ${ordered(allowed).join(", ")}.`;
|
|
44
|
+
}
|
package/dist/model/catalog.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { HostModelCatalog, HostModelView, ModelInput } from "@nylorun/core/contracts";
|
|
3
|
+
import type { SessionStore } from "../store/types.js";
|
|
2
4
|
export type { HostModelCatalog };
|
|
3
5
|
/**
|
|
4
6
|
* The context window, in tokens, of the Tenant's model (`GET /v1/tenant/model`'s view): the
|
|
@@ -14,5 +16,34 @@ export declare function contextWindowOf(view: {
|
|
|
14
16
|
contextWindow?: number;
|
|
15
17
|
};
|
|
16
18
|
}): number;
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Public provider and model names, and what each model reads with the operator's additions
|
|
21
|
+
* (`added`, by `<provider>/<model>`) and what may be added (protocol 12). No credentials.
|
|
22
|
+
*/
|
|
23
|
+
export declare function hostModelCatalog(added?: Readonly<Record<string, readonly ModelInput[]>>): HostModelCatalog;
|
|
24
|
+
/** A catalog model, by provider and id; undefined for one the catalog does not know. */
|
|
25
|
+
export declare function catalogModel(provider: string, model: string): Model<Api> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* What a configured model reads (protocol 12): a custom endpoint's `settings.inputs` (text only
|
|
28
|
+
* by default), else its catalog's inputs and the operator's additions (`added`). Undefined for no
|
|
29
|
+
* model, or one the catalog does not know.
|
|
30
|
+
*/
|
|
31
|
+
export declare function inputsOfHostModel(view: {
|
|
32
|
+
configured: boolean;
|
|
33
|
+
provider?: string;
|
|
34
|
+
model?: string;
|
|
35
|
+
baseUrl?: string;
|
|
36
|
+
settings?: {
|
|
37
|
+
inputs?: readonly ModelInput[];
|
|
38
|
+
};
|
|
39
|
+
}, added?: Readonly<Record<string, readonly ModelInput[]>>): ModelInput[] | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* What the Tenant's model reads now, for the accept check and `read_artifact`: undefined when no
|
|
42
|
+
* model is in the vault (a test's fake provider, say), and the check is skipped.
|
|
43
|
+
*/
|
|
44
|
+
export declare function currentModelInputs(ctx: {
|
|
45
|
+
readonly store: SessionStore;
|
|
46
|
+
readonly vault: {
|
|
47
|
+
getHostModel(): Promise<HostModelView>;
|
|
48
|
+
};
|
|
49
|
+
}): Promise<ModelInput[] | undefined>;
|
package/dist/model/catalog.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readAddedInputs } from "../tenant/model-setting.js";
|
|
2
|
+
import { addableInputs, capabilitiesOf } from "./capabilities.js";
|
|
1
3
|
import { CUSTOM_CONTEXT_WINDOW, modelsFor } from "./models.js";
|
|
2
4
|
const emptyStore = {
|
|
3
5
|
async read() {
|
|
@@ -24,8 +26,11 @@ export function contextWindowOf(view) {
|
|
|
24
26
|
const models = modelsFor({ provider: "", model: "" }, emptyStore, { environment: false });
|
|
25
27
|
return models.getModel(view.provider, view.model)?.contextWindow ?? CUSTOM_CONTEXT_WINDOW;
|
|
26
28
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Public provider and model names, and what each model reads with the operator's additions
|
|
31
|
+
* (`added`, by `<provider>/<model>`) and what may be added (protocol 12). No credentials.
|
|
32
|
+
*/
|
|
33
|
+
export function hostModelCatalog(added = {}) {
|
|
29
34
|
const models = modelsFor({ provider: "", model: "" }, emptyStore, {
|
|
30
35
|
environment: false,
|
|
31
36
|
});
|
|
@@ -36,7 +41,38 @@ export function hostModelCatalog() {
|
|
|
36
41
|
models: models.getModels(provider.id).map((model) => ({
|
|
37
42
|
id: model.id,
|
|
38
43
|
name: model.name,
|
|
44
|
+
inputs: capabilitiesOf(model, added[`${provider.id}/${model.id}`]).inputs,
|
|
45
|
+
addableInputs: addableInputs(model),
|
|
39
46
|
})),
|
|
40
47
|
})),
|
|
41
48
|
};
|
|
42
49
|
}
|
|
50
|
+
/** A catalog model, by provider and id; undefined for one the catalog does not know. */
|
|
51
|
+
export function catalogModel(provider, model) {
|
|
52
|
+
return modelsFor({ provider: "", model: "" }, emptyStore, { environment: false }).getModel(provider, model);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* What a configured model reads (protocol 12): a custom endpoint's `settings.inputs` (text only
|
|
56
|
+
* by default), else its catalog's inputs and the operator's additions (`added`). Undefined for no
|
|
57
|
+
* model, or one the catalog does not know.
|
|
58
|
+
*/
|
|
59
|
+
export function inputsOfHostModel(view, added = {}) {
|
|
60
|
+
if (!view.configured || !view.provider || !view.model)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (view.baseUrl) {
|
|
63
|
+
const inputs = view.settings?.inputs ?? [];
|
|
64
|
+
return capabilitiesOf({ api: "openai-completions", input: inputs.includes("image") ? ["text", "image"] : ["text"] }, inputs).inputs;
|
|
65
|
+
}
|
|
66
|
+
const model = catalogModel(view.provider, view.model);
|
|
67
|
+
return model && capabilitiesOf(model, added[`${view.provider}/${view.model}`]).inputs;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What the Tenant's model reads now, for the accept check and `read_artifact`: undefined when no
|
|
71
|
+
* model is in the vault (a test's fake provider, say), and the check is skipped.
|
|
72
|
+
*/
|
|
73
|
+
export async function currentModelInputs(ctx) {
|
|
74
|
+
const view = await ctx.vault.getHostModel();
|
|
75
|
+
if (!view.configured)
|
|
76
|
+
return undefined;
|
|
77
|
+
return inputsOfHostModel(view, await ctx.store.tx((t) => readAddedInputs(t)));
|
|
78
|
+
}
|