@nylorun/runtime 0.13.0-beta → 0.15.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.
Files changed (309) hide show
  1. package/CHANGELOG.md +434 -0
  2. package/README.md +137 -41
  3. package/dist/adapters/execution/restate.d.ts +7 -2
  4. package/dist/adapters/execution/restate.js +40 -10
  5. package/dist/adapters/replication/pgoutput.d.ts +21 -0
  6. package/dist/adapters/replication/pgoutput.js +170 -0
  7. package/dist/adapters/streams/s2.js +37 -20
  8. package/dist/admin-openapi.json +570 -0
  9. package/dist/api/a2a/card.d.ts +15 -0
  10. package/dist/api/a2a/card.js +24 -0
  11. package/dist/api/a2a/endpoint.d.ts +8 -0
  12. package/dist/api/a2a/endpoint.js +81 -0
  13. package/dist/api/a2a/protocol.d.ts +144 -0
  14. package/dist/api/a2a/protocol.js +188 -0
  15. package/dist/api/a2a/routes.d.ts +19 -0
  16. package/dist/api/a2a/routes.js +289 -0
  17. package/dist/api/a2a/tasks.d.ts +50 -0
  18. package/dist/api/a2a/tasks.js +186 -0
  19. package/dist/api/ag-ui/endpoint.d.ts +8 -0
  20. package/dist/api/ag-ui/endpoint.js +126 -0
  21. package/dist/api/ag-ui/history.d.ts +7 -0
  22. package/dist/api/ag-ui/history.js +60 -0
  23. package/dist/api/ag-ui/routes.d.ts +32 -0
  24. package/dist/api/ag-ui/routes.js +305 -0
  25. package/dist/api/ag-ui/session-id.d.ts +1 -0
  26. package/dist/api/ag-ui/session-id.js +12 -0
  27. package/dist/api/ag-ui/sse.d.ts +9 -0
  28. package/dist/api/ag-ui/sse.js +7 -0
  29. package/dist/api/ag-ui/translate.d.ts +38 -0
  30. package/dist/api/ag-ui/translate.js +222 -0
  31. package/dist/api/components.d.ts +8065 -0
  32. package/dist/api/components.js +82 -0
  33. package/dist/api/gate/keys.d.ts +14 -0
  34. package/dist/api/gate/keys.js +59 -0
  35. package/dist/api/gate/routes.d.ts +34 -0
  36. package/dist/api/gate/routes.js +235 -0
  37. package/dist/api/http/app.d.ts +18 -0
  38. package/dist/api/http/app.js +58 -0
  39. package/dist/api/http/body.d.ts +4 -0
  40. package/dist/api/http/body.js +37 -0
  41. package/dist/api/http/define.d.ts +39 -0
  42. package/dist/api/http/define.js +122 -0
  43. package/dist/api/http/respond.d.ts +9 -0
  44. package/dist/api/http/respond.js +44 -0
  45. package/dist/api/http/routes/access.d.ts +24 -0
  46. package/dist/api/http/routes/access.js +266 -0
  47. package/dist/api/http/routes/actions.d.ts +8 -0
  48. package/dist/api/http/routes/actions.js +76 -0
  49. package/dist/api/http/routes/endpoints.d.ts +7 -0
  50. package/dist/api/http/routes/endpoints.js +100 -0
  51. package/dist/api/http/routes/sessions.d.ts +3 -0
  52. package/dist/api/http/routes/sessions.js +205 -0
  53. package/dist/api/http/routes/tenant.d.ts +11 -0
  54. package/dist/api/http/routes/tenant.js +244 -0
  55. package/dist/api/http/routes/vaults.d.ts +8 -0
  56. package/dist/api/http/routes/vaults.js +167 -0
  57. package/dist/api/openapi.d.ts +19 -0
  58. package/dist/api/openapi.js +137 -0
  59. package/dist/api/route.d.ts +12 -0
  60. package/dist/api/route.js +4 -0
  61. package/dist/core/bearer.d.ts +8 -0
  62. package/dist/core/bearer.js +11 -0
  63. package/dist/core/flow-host.d.ts +7 -15
  64. package/dist/core/flow-host.js +16 -41
  65. package/dist/core/sandbox-routes.d.ts +12 -7
  66. package/dist/core/sandbox-routes.js +24 -25
  67. package/dist/execution/memory.d.ts +8 -5
  68. package/dist/execution/memory.js +33 -13
  69. package/dist/execution/types.d.ts +38 -6
  70. package/dist/execution/types.js +12 -3
  71. package/dist/gates/contract.d.ts +51 -0
  72. package/dist/gates/contract.js +37 -0
  73. package/dist/gates/handler.d.ts +21 -0
  74. package/dist/gates/handler.js +55 -0
  75. package/dist/gates/http-client.d.ts +12 -0
  76. package/dist/gates/http-client.js +160 -0
  77. package/dist/gates/in-process.d.ts +32 -0
  78. package/dist/gates/in-process.js +42 -0
  79. package/dist/gates/inflight.d.ts +39 -0
  80. package/dist/gates/inflight.js +70 -0
  81. package/dist/gates/mcp-handler.d.ts +35 -0
  82. package/dist/gates/mcp-handler.js +142 -0
  83. package/dist/gates/meter.d.ts +24 -0
  84. package/dist/gates/meter.js +165 -0
  85. package/dist/gates/model-gate.d.ts +45 -0
  86. package/dist/gates/model-gate.js +1 -0
  87. package/dist/gates/tenant-vaults.d.ts +64 -0
  88. package/dist/gates/tenant-vaults.js +94 -0
  89. package/dist/gates/tool-calls.d.ts +51 -0
  90. package/dist/gates/tool-calls.js +64 -0
  91. package/dist/gates/tool-client.d.ts +12 -0
  92. package/dist/gates/tool-client.js +201 -0
  93. package/dist/gates/tool-contract.d.ts +116 -0
  94. package/dist/gates/tool-contract.js +64 -0
  95. package/dist/gates/tool-gate.d.ts +45 -0
  96. package/dist/gates/tool-gate.js +10 -0
  97. package/dist/host/admin-api.d.ts +23 -0
  98. package/dist/host/admin-api.js +74 -0
  99. package/dist/host/app.d.ts +34 -0
  100. package/dist/host/app.js +181 -0
  101. package/dist/host/config-for.d.ts +3 -1
  102. package/dist/host/config-for.js +3 -2
  103. package/dist/host/config.d.ts +11 -0
  104. package/dist/host/cors.d.ts +27 -0
  105. package/dist/host/cors.js +64 -0
  106. package/dist/host/create-host.d.ts +36 -8
  107. package/dist/host/create-host.js +161 -330
  108. package/dist/host/execution.d.ts +20 -18
  109. package/dist/host/execution.js +2 -2
  110. package/dist/host/gates.d.ts +58 -0
  111. package/dist/host/gates.js +127 -0
  112. package/dist/host/http.d.ts +20 -4
  113. package/dist/host/http.js +81 -23
  114. package/dist/host/index.d.ts +1 -1
  115. package/dist/host/main.js +189 -58
  116. package/dist/host/stack-config.d.ts +91 -19
  117. package/dist/host/stack-config.js +246 -17
  118. package/dist/infra/database.d.ts +2 -2
  119. package/dist/infra/execution.d.ts +5 -5
  120. package/dist/infra/execution.js +8 -6
  121. package/dist/infra/index.d.ts +1 -1
  122. package/dist/infra/workers.d.ts +17 -17
  123. package/dist/infra/workers.js +9 -9
  124. package/dist/keys/client.d.ts +9 -0
  125. package/dist/keys/client.js +70 -0
  126. package/dist/keys/contract.d.ts +24 -0
  127. package/dist/keys/contract.js +12 -0
  128. package/dist/keys/keys.d.ts +41 -0
  129. package/dist/keys/keys.js +50 -0
  130. package/dist/mcp/connect.d.ts +43 -3
  131. package/dist/mcp/connect.js +12 -5
  132. package/dist/mcp/pool.d.ts +39 -3
  133. package/dist/mcp/pool.js +74 -11
  134. package/dist/model/catalog.d.ts +2 -10
  135. package/dist/model/classify.d.ts +13 -0
  136. package/dist/model/classify.js +61 -0
  137. package/dist/model/models.d.ts +10 -1
  138. package/dist/model/models.js +14 -6
  139. package/dist/model/pi-model.d.ts +17 -2
  140. package/dist/model/pi-model.js +366 -222
  141. package/dist/openapi.json +25889 -0
  142. package/dist/record/append.d.ts +51 -0
  143. package/dist/record/append.js +20 -0
  144. package/dist/record/envelope.d.ts +19 -0
  145. package/dist/record/envelope.js +49 -0
  146. package/dist/record/index.d.ts +11 -0
  147. package/dist/record/index.js +11 -0
  148. package/dist/sandbox/manager.d.ts +13 -1
  149. package/dist/sandbox/manager.js +8 -11
  150. package/dist/sandbox/resolve.d.ts +33 -0
  151. package/dist/sandbox/resolve.js +81 -0
  152. package/dist/sandbox/session-sandbox.d.ts +11 -0
  153. package/dist/sandbox/session-sandbox.js +51 -0
  154. package/dist/sandbox/share.d.ts +14 -2
  155. package/dist/sandbox/share.js +33 -3
  156. package/dist/sandbox/tenant-config.d.ts +37 -0
  157. package/dist/sandbox/tenant-config.js +51 -0
  158. package/dist/sandbox/tools.d.ts +7 -9
  159. package/dist/sandbox/tools.js +11 -3
  160. package/dist/sandbox/types.d.ts +8 -2
  161. package/dist/store/postgres/connect.d.ts +25 -9
  162. package/dist/store/postgres/connect.js +27 -10
  163. package/dist/store/postgres/db.d.ts +16 -0
  164. package/dist/store/postgres/db.js +28 -0
  165. package/dist/store/postgres/drizzle/0000_foundation.sql +22 -0
  166. package/dist/store/postgres/drizzle/0001_baseline.sql +255 -0
  167. package/dist/store/postgres/drizzle/0002_stream_relay.sql +4 -0
  168. package/dist/store/postgres/drizzle/0003_tool_crossings.sql +9 -0
  169. package/dist/store/postgres/drizzle/meta/_journal.json +34 -0
  170. package/dist/store/postgres/migrate.d.ts +68 -0
  171. package/dist/store/postgres/migrate.js +183 -0
  172. package/dist/store/postgres/record-writer.d.ts +4 -0
  173. package/dist/store/postgres/record-writer.js +34 -0
  174. package/dist/store/postgres/record.d.ts +5 -0
  175. package/dist/store/postgres/record.js +60 -0
  176. package/dist/store/postgres/schema.d.ts +3096 -0
  177. package/dist/store/postgres/schema.js +363 -0
  178. package/dist/store/postgres/store.d.ts +2 -4
  179. package/dist/store/postgres/store.js +590 -434
  180. package/dist/store/postgres/tenant.d.ts +56 -0
  181. package/dist/store/postgres/tenant.js +154 -0
  182. package/dist/store/types.d.ts +183 -132
  183. package/dist/store/types.js +0 -1
  184. package/dist/streams/basin.d.ts +18 -1
  185. package/dist/streams/basin.js +34 -2
  186. package/dist/streams/control.d.ts +18 -0
  187. package/dist/streams/control.js +33 -0
  188. package/dist/streams/memory.d.ts +3 -1
  189. package/dist/streams/memory.js +14 -8
  190. package/dist/streams/relay/core.d.ts +35 -0
  191. package/dist/streams/relay/core.js +366 -0
  192. package/dist/streams/relay/types.d.ts +78 -0
  193. package/dist/streams/relay/types.js +8 -0
  194. package/dist/streams/types.d.ts +71 -36
  195. package/dist/streams/types.js +18 -53
  196. package/dist/tenant/access-policy.d.ts +30 -0
  197. package/dist/tenant/access-policy.js +52 -0
  198. package/dist/tenant/actions.d.ts +10 -149
  199. package/dist/tenant/actions.js +5 -167
  200. package/dist/tenant/advance.d.ts +7 -2
  201. package/dist/tenant/advance.js +125 -14
  202. package/dist/tenant/auth.d.ts +19 -17
  203. package/dist/tenant/auth.js +90 -93
  204. package/dist/tenant/browser.d.ts +15 -0
  205. package/dist/tenant/browser.js +39 -0
  206. package/dist/tenant/cause.d.ts +25 -0
  207. package/dist/tenant/cause.js +45 -0
  208. package/dist/tenant/commands.d.ts +18 -2
  209. package/dist/tenant/commands.js +111 -115
  210. package/dist/tenant/context.d.ts +101 -21
  211. package/dist/tenant/context.js +14 -10
  212. package/dist/tenant/delivery-token.d.ts +41 -0
  213. package/dist/tenant/delivery-token.js +104 -0
  214. package/dist/tenant/delivery.d.ts +62 -0
  215. package/dist/tenant/delivery.js +481 -0
  216. package/dist/tenant/effects.d.ts +20 -1
  217. package/dist/tenant/effects.js +159 -42
  218. package/dist/tenant/endpoints.d.ts +67 -0
  219. package/dist/tenant/endpoints.js +90 -0
  220. package/dist/tenant/ephemeral.d.ts +22 -7
  221. package/dist/tenant/ephemeral.js +83 -125
  222. package/dist/tenant/history.d.ts +64 -0
  223. package/dist/tenant/history.js +120 -0
  224. package/dist/tenant/http.d.ts +8 -9
  225. package/dist/tenant/http.js +13 -27
  226. package/dist/tenant/jwt.d.ts +16 -0
  227. package/dist/tenant/jwt.js +50 -0
  228. package/dist/tenant/model-setting.d.ts +2 -2
  229. package/dist/tenant/module.d.ts +17 -28
  230. package/dist/tenant/module.js +133 -279
  231. package/dist/tenant/outbound.d.ts +44 -0
  232. package/dist/tenant/outbound.js +127 -0
  233. package/dist/tenant/paths.d.ts +11 -16
  234. package/dist/tenant/paths.js +24 -68
  235. package/dist/tenant/pool.d.ts +1 -3
  236. package/dist/tenant/pool.js +1 -19
  237. package/dist/tenant/principals.d.ts +23 -11
  238. package/dist/tenant/principals.js +61 -49
  239. package/dist/tenant/reset.d.ts +0 -4
  240. package/dist/tenant/reset.js +0 -5
  241. package/dist/tenant/runtime.d.ts +28 -20
  242. package/dist/tenant/runtime.js +95 -64
  243. package/dist/tenant/scheduler.d.ts +10 -3
  244. package/dist/tenant/scheduler.js +9 -5
  245. package/dist/tenant/session-streams.d.ts +127 -0
  246. package/dist/tenant/session-streams.js +404 -0
  247. package/dist/tenant/sessions.d.ts +28 -4
  248. package/dist/tenant/sessions.js +118 -24
  249. package/dist/tenant/signing-keys.d.ts +55 -0
  250. package/dist/tenant/signing-keys.js +172 -0
  251. package/dist/tenant/slim.d.ts +8 -0
  252. package/dist/tenant/slim.js +21 -0
  253. package/dist/tenant/status.d.ts +3 -3
  254. package/dist/tenant/status.js +20 -13
  255. package/dist/tenant/store-pg.d.ts +9 -6
  256. package/dist/tenant/store-pg.js +60 -125
  257. package/dist/tenant/streams.d.ts +62 -85
  258. package/dist/tenant/streams.js +143 -226
  259. package/dist/tenant/subject-limits.d.ts +16 -0
  260. package/dist/tenant/subject-limits.js +45 -0
  261. package/dist/tenant/sweep.d.ts +1 -10
  262. package/dist/tenant/sweep.js +29 -69
  263. package/dist/tenant/tokens.d.ts +14 -0
  264. package/dist/tenant/tokens.js +180 -0
  265. package/dist/tenant/transcript.d.ts +48 -5
  266. package/dist/tenant/transcript.js +58 -1
  267. package/dist/tenant/types.d.ts +69 -98
  268. package/dist/tenant/types.js +4 -15
  269. package/dist/tenant/worker.d.ts +3 -1
  270. package/dist/tenant/worker.js +13 -7
  271. package/dist/vault/host-model.d.ts +31 -0
  272. package/dist/vault/host-model.js +57 -0
  273. package/dist/vault/service.d.ts +44 -17
  274. package/dist/vault/service.js +126 -121
  275. package/dist/version.d.ts +1 -1
  276. package/dist/version.js +1 -1
  277. package/package.json +25 -9
  278. package/dist/core/executors.d.ts +0 -44
  279. package/dist/core/executors.js +0 -95
  280. package/dist/store/memory.d.ts +0 -57
  281. package/dist/store/memory.js +0 -645
  282. package/dist/store/postgres/migrations/001_initial.d.ts +0 -27
  283. package/dist/store/postgres/migrations/001_initial.js +0 -196
  284. package/dist/store/postgres/migrations/002_session_owner.d.ts +0 -6
  285. package/dist/store/postgres/migrations/002_session_owner.js +0 -13
  286. package/dist/store/postgres/migrations/index.d.ts +0 -49
  287. package/dist/store/postgres/migrations/index.js +0 -76
  288. package/dist/store/postgres/names.d.ts +0 -11
  289. package/dist/store/postgres/names.js +0 -42
  290. package/dist/store/postgres/tenants.d.ts +0 -90
  291. package/dist/store/postgres/tenants.js +0 -214
  292. package/dist/streams/relay.d.ts +0 -37
  293. package/dist/streams/relay.js +0 -254
  294. package/dist/tenant/envelope.d.ts +0 -7
  295. package/dist/tenant/envelope.js +0 -22
  296. package/dist/tenant/live.d.ts +0 -92
  297. package/dist/tenant/live.js +0 -290
  298. package/dist/tenant/quarantine-error.d.ts +0 -6
  299. package/dist/tenant/quarantine-error.js +0 -9
  300. package/dist/tenant/quarantine.d.ts +0 -27
  301. package/dist/tenant/quarantine.js +0 -72
  302. package/dist/tenant/routes-tenant.d.ts +0 -12
  303. package/dist/tenant/routes-tenant.js +0 -137
  304. package/dist/tenant/routes.d.ts +0 -9
  305. package/dist/tenant/routes.js +0 -151
  306. package/dist/tenant/store-memory.d.ts +0 -16
  307. package/dist/tenant/store-memory.js +0 -111
  308. /package/dist/{store → record}/cursor.d.ts +0 -0
  309. /package/dist/{store → record}/cursor.js +0 -0
@@ -0,0 +1,41 @@
1
+ import type { CreateCredentialRequest, CredentialInfo, HostModelView, PutHostModelRequest, RotateCredentialRequest, SelectHostModelRequest, SigningKeyView } from "@nylorun/core/contracts";
2
+ import type { SessionStore } from "../store/types.js";
3
+ import { type SigningKeys } from "../tenant/signing-keys.js";
4
+ import type { VaultService } from "../vault/service.js";
5
+ /** One JWT to sign: its `typ` and every claim, `iss`, `aud`, `sub`, `iat`, `exp` and `jti` included. */
6
+ export interface SignRequest {
7
+ readonly typ: string;
8
+ readonly claims: Readonly<Record<string, unknown>>;
9
+ }
10
+ export interface Signed {
11
+ readonly token: string;
12
+ /** The signing key's id, the token's `kid`. */
13
+ readonly keyId: string;
14
+ }
15
+ export interface Keys {
16
+ createCredential(vaultId: string, body: CreateCredentialRequest): Promise<CredentialInfo>;
17
+ rotateCredential(vaultId: string, id: string, body: RotateCredentialRequest): Promise<CredentialInfo>;
18
+ putHostModel(body: PutHostModelRequest): Promise<HostModelView>;
19
+ selectHostModel(body: SelectHostModelRequest): Promise<HostModelView>;
20
+ /** Signs with the current key, creating the Tenant's keys if it has none. */
21
+ sign(request: SignRequest): Promise<Signed>;
22
+ /** Rotates the signing keys (`SigningKeys.rotate`); 409 while the previous key may verify live tokens. */
23
+ rotateSigningKeys(request: {
24
+ maxTtlSeconds: number;
25
+ force: boolean;
26
+ }): Promise<SigningKeyView[]>;
27
+ /** Creates the current and standby keys when the Tenant has none. */
28
+ ensureSigningKeys(): Promise<void>;
29
+ }
30
+ /** The operations, by the name the HTTP route carries. */
31
+ export declare const KEYS_OPERATIONS: readonly ["createCredential", "rotateCredential", "putHostModel", "selectHostModel", "sign", "rotateSigningKeys", "ensureSigningKeys"];
32
+ export type KeysOperation = (typeof KEYS_OPERATIONS)[number];
33
+ export interface InProcessKeysOptions {
34
+ readonly store: SessionStore;
35
+ /** Its vault key is `kek`. */
36
+ readonly vault: VaultService;
37
+ readonly signingKeys: SigningKeys;
38
+ /** The vault key. */
39
+ readonly kek: () => Buffer;
40
+ }
41
+ export declare function inProcessKeys(options: InProcessKeysOptions): Keys;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The keys seam (blueprint §14, F4.2): everything that needs the vault key. Vault writes that
3
+ * touch a secret (creating and rotating a credential, setting and selecting the host model;
4
+ * rotation and selection decrypt the old secret first) and all token signing (subject and
5
+ * delivery tokens, signing-key rotation) run here, whole, so the process that calls them never
6
+ * holds the key or a private signing key.
7
+ *
8
+ * Two implementations: `inProcessKeys` (embedding, the ephemeral Runtime, tests, and the gates
9
+ * service itself, which serves the HTTP routes with it), and `httpKeys` (`client.ts`), the
10
+ * runtime container's client of the `keys` service in the gateway.
11
+ */
12
+ import { SignJWT } from "jose";
13
+ import { signingKeyView } from "../tenant/signing-keys.js";
14
+ /** The operations, by the name the HTTP route carries. */
15
+ export const KEYS_OPERATIONS = [
16
+ "createCredential",
17
+ "rotateCredential",
18
+ "putHostModel",
19
+ "selectHostModel",
20
+ "sign",
21
+ "rotateSigningKeys",
22
+ "ensureSigningKeys",
23
+ ];
24
+ export function inProcessKeys(options) {
25
+ const { store, vault, signingKeys, kek } = options;
26
+ return {
27
+ createCredential: (vaultId, body) => vault.createCredential(vaultId, body),
28
+ rotateCredential: (vaultId, id, body) => vault.rotateCredential(vaultId, id, body),
29
+ putHostModel: (body) => vault.putHostModel(body),
30
+ selectHostModel: (body) => vault.selectHostModel(body),
31
+ async sign(request) {
32
+ const key = kek();
33
+ const row = await store.tx((t) => signingKeys.ensure(t, key));
34
+ const signer = await signingKeys.privateKey(row, key);
35
+ const token = await new SignJWT({ ...request.claims })
36
+ .setProtectedHeader({ alg: "ES256", typ: request.typ, kid: signer.id })
37
+ .sign(signer.key);
38
+ return { token, keyId: signer.id };
39
+ },
40
+ async rotateSigningKeys(request) {
41
+ const key = kek();
42
+ const rows = await store.tx((t) => signingKeys.rotate(t, key, request.maxTtlSeconds, request.force));
43
+ return rows.map(signingKeyView);
44
+ },
45
+ async ensureSigningKeys() {
46
+ const key = kek();
47
+ await store.tx((t) => signingKeys.ensure(t, key));
48
+ },
49
+ };
50
+ }
@@ -2,10 +2,49 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import type { McpServerManifest } from "@nylorun/core/define";
3
3
  import type { AuthorizeResult } from "../vault/service.js";
4
4
  import { type McpDiagnostic, type McpToolRecord } from "./snapshot.js";
5
+ /** Options of one MCP request. */
6
+ export interface McpRequestOptions {
7
+ readonly signal?: AbortSignal;
8
+ }
9
+ /** Options of one tool call. */
10
+ export interface McpCallOptions extends McpRequestOptions {
11
+ /**
12
+ * The call's effect id. A gate runs a keyed call once and keeps its outcome, so a re-send
13
+ * after a takeover joins it (F4.1). An in-process connection ignores it.
14
+ */
15
+ readonly key?: string;
16
+ }
17
+ /** A page of `tools/list`, as the MCP SDK returns it. */
18
+ export interface McpToolPage {
19
+ readonly tools: readonly {
20
+ readonly name: string;
21
+ readonly description?: string;
22
+ readonly inputSchema?: unknown;
23
+ readonly outputSchema?: unknown;
24
+ }[];
25
+ readonly nextCursor?: string;
26
+ }
27
+ /**
28
+ * What the pool needs of an MCP client: the SDK `Client` over a transport of this process
29
+ * (`sdkClient`), or a client of the gates service that holds the real connection
30
+ * (`gates/tool-client.ts`).
31
+ */
32
+ export interface McpClient {
33
+ listTools(params?: {
34
+ cursor?: string;
35
+ }, options?: McpRequestOptions): Promise<McpToolPage>;
36
+ /** The raw `CallToolResult`; `callMcpTool` reads it. */
37
+ callTool(params: {
38
+ name: string;
39
+ arguments: Record<string, unknown>;
40
+ }, options?: McpCallOptions): Promise<Record<string, unknown>>;
41
+ }
5
42
  export interface LiveConnection {
6
- readonly client: Client;
43
+ readonly client: McpClient;
7
44
  close(): Promise<void>;
8
45
  }
46
+ /** An SDK `Client` as an `McpClient`. */
47
+ export declare function sdkClient(client: Client): McpClient;
9
48
  export declare function openMcpServer(input: {
10
49
  server: McpServerManifest;
11
50
  authorize?: (url: string) => Promise<AuthorizeResult>;
@@ -13,15 +52,16 @@ export declare function openMcpServer(input: {
13
52
  pluginData: string;
14
53
  childEnv?: Readonly<Record<string, string>>;
15
54
  }): Promise<LiveConnection>;
16
- export declare function listMcpTools(client: Client, input: {
55
+ export declare function listMcpTools(client: McpClient, input: {
17
56
  capabilityId: string;
18
57
  serverName: string;
19
58
  taken: Set<string>;
59
+ signal?: AbortSignal;
20
60
  }): Promise<{
21
61
  tools: McpToolRecord[];
22
62
  omitted: string[];
23
63
  }>;
24
- export declare function callMcpTool(client: Client, serverToolName: string, args: unknown): Promise<{
64
+ export declare function callMcpTool(client: McpClient, serverToolName: string, args: unknown, options?: McpCallOptions): Promise<{
25
65
  kind: "completed";
26
66
  output: unknown;
27
67
  } | {
@@ -5,6 +5,13 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
5
5
  import { schemaFromJSON } from "@nylorun/core/define";
6
6
  import { modelToolName, } from "./snapshot.js";
7
7
  import { prepareStdioLaunch } from "./stdio.js";
8
+ /** An SDK `Client` as an `McpClient`. */
9
+ export function sdkClient(client) {
10
+ return {
11
+ listTools: (params, options) => client.listTools(params, options?.signal ? { signal: options.signal } : undefined),
12
+ callTool: (params, options) => client.callTool(params, undefined, options?.signal ? { signal: options.signal } : undefined),
13
+ };
14
+ }
8
15
  export async function openMcpServer(input) {
9
16
  if (input.server.type === "stdio") {
10
17
  const launch = prepareStdioLaunch(input.server, {
@@ -23,7 +30,7 @@ export async function openMcpServer(input) {
23
30
  transport.stderr?.on("data", () => { });
24
31
  const client = createClient();
25
32
  await client.connect(transport);
26
- return { client, close: () => client.close() };
33
+ return { client: sdkClient(client), close: () => client.close() };
27
34
  }
28
35
  const authorize = input.authorize;
29
36
  if (!authorize)
@@ -42,14 +49,14 @@ export async function openMcpServer(input) {
42
49
  : new StreamableHTTPClientTransport(url, { fetch: fetchImpl });
43
50
  const client = createClient();
44
51
  await client.connect(transport);
45
- return { client, close: () => client.close() };
52
+ return { client: sdkClient(client), close: () => client.close() };
46
53
  }
47
54
  export async function listMcpTools(client, input) {
48
55
  const tools = [];
49
56
  const omitted = [];
50
57
  let cursor;
51
58
  for (let page = 0; page < 100; page += 1) {
52
- const listed = await client.listTools(cursor ? { cursor } : undefined);
59
+ const listed = await client.listTools(cursor ? { cursor } : undefined, input.signal ? { signal: input.signal } : undefined);
53
60
  for (const tool of listed.tools) {
54
61
  if (typeof tool.name !== "string" || tool.name.length === 0)
55
62
  continue;
@@ -81,13 +88,13 @@ export async function listMcpTools(client, input) {
81
88
  }
82
89
  return { tools, omitted };
83
90
  }
84
- export async function callMcpTool(client, serverToolName, args) {
91
+ export async function callMcpTool(client, serverToolName, args, options = {}) {
85
92
  const result = await client.callTool({
86
93
  name: serverToolName,
87
94
  arguments: args && typeof args === "object" && !Array.isArray(args)
88
95
  ? args
89
96
  : {},
90
- });
97
+ }, options);
91
98
  if ("isError" in result && result.isError) {
92
99
  return {
93
100
  kind: "failed",
@@ -1,10 +1,17 @@
1
1
  import type { AgentManifest, McpServerManifest } from "@nylorun/core/define";
2
2
  import type { AuthorizeResult } from "../vault/service.js";
3
- import { callMcpTool } from "./connect.js";
3
+ import { callMcpTool, openMcpServer, type LiveConnection } from "./connect.js";
4
4
  import { type McpDiagnostic, type McpSnapshot, type McpToolRecord } from "./snapshot.js";
5
+ /** A connection unused this long is closed by the sweep; the next call opens it again. */
6
+ export declare const DEFAULT_MCP_IDLE_MS: number;
5
7
  export declare class McpPool {
6
8
  private readonly options;
7
9
  private readonly live;
10
+ /** Connections being opened by `call`, so concurrent calls share one. */
11
+ private readonly opening;
12
+ private readonly idleMs;
13
+ private readonly now;
14
+ private readonly open;
8
15
  constructor(options: {
9
16
  /** Absolute Tenant `plugin-data` directory. */
10
17
  readonly pluginData: string;
@@ -13,6 +20,18 @@ export declare class McpPool {
13
20
  url: string;
14
21
  serverName: string;
15
22
  }) => Promise<AuthorizeResult>;
23
+ /** Default `DEFAULT_MCP_IDLE_MS`. */
24
+ readonly idleMs?: number;
25
+ readonly now?: () => number;
26
+ /** Tests replace how a declared server is opened. */
27
+ readonly open?: typeof openMcpServer;
28
+ /**
29
+ * Opens a remote (`streamable-http` or `sse`) server somewhere else: the gates service
30
+ * holds the connection and its credential, and the loop never sees either (F4.1).
31
+ * Absent: remote servers are opened in this process, with `authorize`. Stdio servers
32
+ * always run here.
33
+ */
34
+ readonly openRemote?: (server: McpServerRef) => Promise<LiveConnection>;
16
35
  });
17
36
  discover(input: {
18
37
  sessionId: string;
@@ -40,13 +59,30 @@ export declare class McpPool {
40
59
  args: unknown;
41
60
  manifest: AgentManifest;
42
61
  pluginRoots: Readonly<Record<string, string>>;
62
+ /** The effect id: a gate runs the call once under it (F4.1). */
63
+ effectId?: string;
64
+ signal?: AbortSignal;
43
65
  }): Promise<Awaited<ReturnType<typeof callMcpTool>>>;
66
+ /**
67
+ * Closes connections unused for the idle timeout (the Tenant sweep). A session that calls
68
+ * one again reconnects, as after a restart; this bounds the stdio processes a Tenant keeps.
69
+ */
70
+ sweep(): Promise<void>;
44
71
  close(): Promise<void>;
72
+ /** Keeps the connection, or closes it when the server is already connected for the session. */
45
73
  private remember;
46
74
  private liveKey;
47
75
  private connectDeclared;
48
76
  }
49
- interface DeclaredServer {
77
+ /** One declared MCP server of a session: what a gate needs to find it in the pinned manifest. */
78
+ export interface McpServerRef {
79
+ readonly sessionId: string;
80
+ /** The agent used as a tool that declares the server; absent for the session's root agent. */
81
+ readonly agentId?: string;
82
+ readonly capabilityId: string;
83
+ readonly serverName: string;
84
+ }
85
+ export interface DeclaredServer {
50
86
  /** Absent for the session's root agent. */
51
87
  readonly agentId?: string;
52
88
  /** The manifest of the agent that declares the server. */
@@ -56,4 +92,4 @@ interface DeclaredServer {
56
92
  }
57
93
  /** Servers of the root agent, then of each agent it uses as a tool. */
58
94
  export declare function serversOf(manifest: AgentManifest): DeclaredServer[];
59
- export {};
95
+ export declare function findServer(manifest: AgentManifest, agentId: string | undefined, capabilityId: string, serverName: string): DeclaredServer | undefined;
package/dist/mcp/pool.js CHANGED
@@ -2,11 +2,21 @@ import { join } from "node:path";
2
2
  import { delegatesOf } from "@nylorun/core/define";
3
3
  import { callMcpTool, diagnosticFromError, listMcpTools, openMcpServer, } from "./connect.js";
4
4
  import { declaredToolNames, } from "./snapshot.js";
5
+ /** A connection unused this long is closed by the sweep; the next call opens it again. */
6
+ export const DEFAULT_MCP_IDLE_MS = 15 * 60_000;
5
7
  export class McpPool {
6
8
  options;
7
9
  live = new Map();
10
+ /** Connections being opened by `call`, so concurrent calls share one. */
11
+ opening = new Map();
12
+ idleMs;
13
+ now;
14
+ open;
8
15
  constructor(options) {
9
16
  this.options = options;
17
+ this.idleMs = options.idleMs ?? DEFAULT_MCP_IDLE_MS;
18
+ this.now = options.now ?? Date.now;
19
+ this.open = options.open ?? openMcpServer;
10
20
  }
11
21
  async discover(input) {
12
22
  // Each agent names its own tools, so collisions are checked per agent.
@@ -27,6 +37,7 @@ export class McpPool {
27
37
  capabilityId: declared.capabilityId,
28
38
  serverName: declared.server.name,
29
39
  taken: taken.get(declared.agentId),
40
+ ...(input.signal ? { signal: input.signal } : {}),
30
41
  });
31
42
  tools.push(...listed.tools.map((tool) => owned(declared, tool)));
32
43
  diagnostics.push({
@@ -62,8 +73,12 @@ export class McpPool {
62
73
  if (seen.has(key))
63
74
  continue;
64
75
  seen.add(key);
65
- if (this.live.has(key))
76
+ const live = this.live.get(key);
77
+ if (live) {
78
+ // The advance is about to use it: not idle.
79
+ live.lastUsedAt = this.now();
66
80
  continue;
81
+ }
67
82
  input.signal?.throwIfAborted();
68
83
  const declared = findServer(input.manifest, tool.agentId, tool.capabilityId, tool.serverName);
69
84
  if (!declared) {
@@ -92,34 +107,82 @@ export class McpPool {
92
107
  const declared = findServer(input.manifest, input.agentId, input.capabilityId, input.serverName);
93
108
  if (!declared)
94
109
  throw new Error(`MCP server '${input.serverName}' is not declared`);
95
- const opened = await this.connectDeclared(input, declared);
110
+ let opening = this.opening.get(key);
111
+ if (!opening) {
112
+ opening = this.connectDeclared(input, declared).finally(() => this.opening.delete(key));
113
+ this.opening.set(key, opening);
114
+ }
115
+ const opened = await opening;
96
116
  if (!opened.ok)
97
117
  throw new Error(opened.diagnostic.message);
98
- this.remember(input.sessionId, declared, opened.connection);
99
- live = this.live.get(key);
118
+ live = this.remember(input.sessionId, declared, opened.connection);
119
+ }
120
+ live.active += 1;
121
+ try {
122
+ return await callMcpTool(live.connection.client, input.serverToolName, input.args, {
123
+ ...(input.effectId === undefined ? {} : { key: input.effectId }),
124
+ ...(input.signal ? { signal: input.signal } : {}),
125
+ });
126
+ }
127
+ finally {
128
+ live.active -= 1;
129
+ live.lastUsedAt = this.now();
130
+ }
131
+ }
132
+ /**
133
+ * Closes connections unused for the idle timeout (the Tenant sweep). A session that calls
134
+ * one again reconnects, as after a restart; this bounds the stdio processes a Tenant keeps.
135
+ */
136
+ async sweep() {
137
+ const now = this.now();
138
+ const idle = [];
139
+ for (const [key, live] of this.live) {
140
+ if (live.active > 0 || now - live.lastUsedAt < this.idleMs)
141
+ continue;
142
+ this.live.delete(key);
143
+ idle.push(live);
100
144
  }
101
- if (!live)
102
- throw new Error(`MCP server '${input.serverName}' is not connected`);
103
- return callMcpTool(live.connection.client, input.serverToolName, input.args);
145
+ await Promise.all(idle.map((item) => item.connection.close().catch(() => { })));
104
146
  }
105
147
  async close() {
106
148
  const connections = [...this.live.values()];
107
149
  this.live.clear();
108
150
  await Promise.all(connections.map((item) => item.connection.close().catch(() => { })));
109
151
  }
152
+ /** Keeps the connection, or closes it when the server is already connected for the session. */
110
153
  remember(sessionId, declared, connection) {
111
- this.live.set(this.liveKey(sessionId, declared.agentId, declared.capabilityId, declared.server.name), {
154
+ const key = this.liveKey(sessionId, declared.agentId, declared.capabilityId, declared.server.name);
155
+ const existing = this.live.get(key);
156
+ if (existing) {
157
+ if (existing.connection !== connection)
158
+ void connection.close().catch(() => { });
159
+ return existing;
160
+ }
161
+ const live = {
112
162
  capabilityId: declared.capabilityId,
113
163
  serverName: declared.server.name,
114
164
  connection,
115
- });
165
+ lastUsedAt: this.now(),
166
+ active: 0,
167
+ };
168
+ this.live.set(key, live);
169
+ return live;
116
170
  }
117
171
  liveKey(sessionId, agentId, capabilityId, serverName) {
118
172
  return JSON.stringify([sessionId, agentId ?? null, capabilityId, serverName]);
119
173
  }
120
174
  async connectDeclared(input, declared) {
121
175
  try {
122
- const connection = await openMcpServer({
176
+ if (declared.server.type !== "stdio" && this.options.openRemote) {
177
+ const connection = await this.options.openRemote({
178
+ sessionId: input.sessionId,
179
+ ...ownerOf(declared),
180
+ capabilityId: declared.capabilityId,
181
+ serverName: declared.server.name,
182
+ });
183
+ return { ok: true, connection };
184
+ }
185
+ const connection = await this.open({
123
186
  server: declared.server,
124
187
  pluginRoot: input.pluginRoots[pluginKey(declared)],
125
188
  pluginData: join(this.options.pluginData, ...pluginKey(declared).split("/")),
@@ -159,7 +222,7 @@ export function serversOf(manifest) {
159
222
  add(child.manifest, child.manifest.id);
160
223
  return servers;
161
224
  }
162
- function findServer(manifest, agentId, capabilityId, serverName) {
225
+ export function findServer(manifest, agentId, capabilityId, serverName) {
163
226
  return serversOf(manifest).find((item) => item.agentId === agentId &&
164
227
  item.capabilityId === capabilityId &&
165
228
  item.server.name === serverName);
@@ -1,12 +1,4 @@
1
- export type HostModelCatalog = {
2
- providers: {
3
- id: string;
4
- name: string;
5
- models: {
6
- id: string;
7
- name: string;
8
- }[];
9
- }[];
10
- };
1
+ import type { HostModelCatalog } from "@nylorun/core/contracts";
2
+ export type { HostModelCatalog };
11
3
  /** Public provider and model names. No credentials. */
12
4
  export declare function hostModelCatalog(): HostModelCatalog;
@@ -0,0 +1,13 @@
1
+ import { type AssistantMessage } from "@earendil-works/pi-ai";
2
+ import type { ModelFailureCode, ModelFailureOutcome } from "@nylorun/core/define";
3
+ /**
4
+ * Classify a failed pi-ai response (`stopReason: "error"`) into a failure outcome
5
+ * (Model Calls §6.1). Context overflow is checked first, with the binding's window so
6
+ * silent overflow is caught too.
7
+ */
8
+ export declare function classifyAssistantError(message: AssistantMessage, contextWindow?: number): ModelFailureOutcome;
9
+ /** Classify an error a model provider threw (gateway, fixture, or a setup failure). */
10
+ export declare function classifyThrown(error: unknown, contextWindow?: number): ModelFailureOutcome;
11
+ export declare function failure(code: ModelFailureCode, message: string, retryable: boolean): ModelFailureOutcome;
12
+ /** A pi-ai error message, for classifying failures that did not come from a stream. */
13
+ export declare function errorMessage(text: string): AssistantMessage;
@@ -0,0 +1,61 @@
1
+ import { isContextOverflow, isRetryableAssistantError, } from "@earendil-works/pi-ai";
2
+ const RATE_LIMITED = /\b429\b|rate.?limit|too many requests/i;
3
+ const QUOTA = /insufficient_quota|quota exceeded|out of budget|billing|usage limit/i;
4
+ const OVERLOADED = /overloaded|\b529\b|\b503\b|service.?unavailable|high demand/i;
5
+ const TIMEOUT = /timed? out|timeout/i;
6
+ const CONTENT_POLICY = /content.?(policy|filter|management)|safety|flagged|moderation/i;
7
+ const AUTH = /\b401\b|\b403\b|unauthori[sz]ed|forbidden|invalid.?api.?key|incorrect api key|authentication|not configured/i;
8
+ /**
9
+ * Classify a failed pi-ai response (`stopReason: "error"`) into a failure outcome
10
+ * (Model Calls §6.1). Context overflow is checked first, with the binding's window so
11
+ * silent overflow is caught too.
12
+ */
13
+ export function classifyAssistantError(message, contextWindow) {
14
+ const text = message.errorMessage ?? `Provider stopped: ${message.stopReason}`;
15
+ if (isContextOverflow(message, contextWindow))
16
+ return failure("context_overflow", text, false);
17
+ if (RATE_LIMITED.test(text))
18
+ return failure("rate_limited", text, !QUOTA.test(text));
19
+ if (QUOTA.test(text))
20
+ return failure("rate_limited", text, false);
21
+ if (OVERLOADED.test(text))
22
+ return failure("overloaded", text, true);
23
+ if (TIMEOUT.test(text))
24
+ return failure("timeout", text, true);
25
+ if (CONTENT_POLICY.test(text))
26
+ return failure("content_policy", text, false);
27
+ if (AUTH.test(text))
28
+ return failure("auth", text, false);
29
+ if (isRetryableAssistantError(message))
30
+ return failure("transient", text, true);
31
+ return failure("invalid_request", text, false);
32
+ }
33
+ /** Classify an error a model provider threw (gateway, fixture, or a setup failure). */
34
+ export function classifyThrown(error, contextWindow) {
35
+ const text = error instanceof Error ? error.message : String(error);
36
+ return classifyAssistantError(errorMessage(text), contextWindow);
37
+ }
38
+ export function failure(code, message, retryable) {
39
+ return { kind: "failed", code, message, retryable };
40
+ }
41
+ /** A pi-ai error message, for classifying failures that did not come from a stream. */
42
+ export function errorMessage(text) {
43
+ return {
44
+ role: "assistant",
45
+ content: [],
46
+ api: "openai-completions",
47
+ provider: "unknown",
48
+ model: "unknown",
49
+ usage: {
50
+ input: 0,
51
+ output: 0,
52
+ cacheRead: 0,
53
+ cacheWrite: 0,
54
+ totalTokens: 0,
55
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
56
+ },
57
+ stopReason: "error",
58
+ errorMessage: text,
59
+ timestamp: 0,
60
+ };
61
+ }
@@ -1,15 +1,24 @@
1
- import { type CredentialStore } from "@earendil-works/pi-ai";
1
+ import { type AuthContext, type CredentialStore } from "@earendil-works/pi-ai";
2
2
  export type Selection = Readonly<{
3
3
  provider: string;
4
4
  model: string;
5
5
  custom?: Readonly<{
6
6
  baseUrl: string;
7
+ /** Model Settings for the endpoint (Model Calls §7); defaults are deliberately small. */
8
+ contextWindow?: number;
9
+ maxTokens?: number;
10
+ reasoning?: boolean;
11
+ compat?: Readonly<Record<string, unknown>>;
7
12
  }>;
8
13
  }>;
14
+ /** A custom endpoint whose window is unknown is assumed small: an early compaction beats a failed call. */
15
+ export declare const CUSTOM_CONTEXT_WINDOW = 32768;
16
+ export declare const CUSTOM_MAX_TOKENS = 8192;
9
17
  /**
10
18
  * Build the pi-ai model registry from explicit credentials only.
11
19
  * Ambient process environment / provider env auth is never consulted (A7, A10).
12
20
  */
13
21
  export declare function modelsFor(selection: Selection, credentials: CredentialStore, options?: {
14
22
  environment?: boolean;
23
+ authContext?: AuthContext;
15
24
  }): import("@earendil-works/pi-ai").MutableModels;
@@ -1,6 +1,9 @@
1
1
  import { createProvider, } from "@earendil-works/pi-ai";
2
2
  import { stream, streamSimple, } from "@earendil-works/pi-ai/api/openai-completions";
3
3
  import { builtinModels } from "@earendil-works/pi-ai/providers/all";
4
+ /** A custom endpoint whose window is unknown is assumed small: an early compaction beats a failed call. */
5
+ export const CUSTOM_CONTEXT_WINDOW = 32_768;
6
+ export const CUSTOM_MAX_TOKENS = 8_192;
4
7
  /**
5
8
  * Build the pi-ai model registry from explicit credentials only.
6
9
  * Ambient process environment / provider env auth is never consulted (A7, A10).
@@ -9,7 +12,10 @@ export function modelsFor(selection, credentials, options = {}) {
9
12
  if (options.environment) {
10
13
  throw new Error("Ambient model environment is not supported; pass credentials explicitly");
11
14
  }
12
- const models = builtinModels({ credentials });
15
+ const models = builtinModels({
16
+ credentials,
17
+ ...(options.authContext ? { authContext: options.authContext } : {}),
18
+ });
13
19
  if (!selection.custom)
14
20
  return models;
15
21
  const model = {
@@ -18,11 +24,14 @@ export function modelsFor(selection, credentials, options = {}) {
18
24
  api: "openai-completions",
19
25
  provider: "custom",
20
26
  baseUrl: selection.custom.baseUrl,
21
- reasoning: false,
27
+ reasoning: selection.custom.reasoning ?? false,
22
28
  input: ["text", "image"],
23
29
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
24
- contextWindow: 128000,
25
- maxTokens: 16384,
30
+ contextWindow: selection.custom.contextWindow ?? CUSTOM_CONTEXT_WINDOW,
31
+ maxTokens: selection.custom.maxTokens ?? CUSTOM_MAX_TOKENS,
32
+ ...(selection.custom.compat
33
+ ? { compat: { ...selection.custom.compat } }
34
+ : {}),
26
35
  };
27
36
  models.setProvider(createProvider({
28
37
  id: "custom",
@@ -30,8 +39,7 @@ export function modelsFor(selection, credentials, options = {}) {
30
39
  baseUrl: selection.custom.baseUrl,
31
40
  auth: {
32
41
  apiKey: {
33
- label: "Custom API key",
34
- schemas: [],
42
+ name: "Custom API key",
35
43
  async resolve() {
36
44
  const credential = await credentials.read("custom");
37
45
  if (!credential || credential.type !== "api_key")
@@ -1,4 +1,4 @@
1
- import type { Credential } from "@earendil-works/pi-ai";
1
+ import { type Credential } from "@earendil-works/pi-ai";
2
2
  import type { RuntimeModelAdapter } from "../contracts.js";
3
3
  import type { RuntimeMedia } from "../adapters/media.js";
4
4
  import type { HostModelSecret } from "../vault/service.js";
@@ -6,12 +6,27 @@ export interface ModelPreview {
6
6
  readonly invocationId: string;
7
7
  readonly text: string;
8
8
  }
9
+ /** Retry, timeout and cache settings for one model call (Model Calls §5, §6). */
10
+ export interface ModelCallSettings {
11
+ /** Attempts per call, including the first. Default 3. */
12
+ readonly attempts?: number;
13
+ /** Base delay between attempts; doubles each time, with jitter. Default 2 s. */
14
+ readonly retryBaseDelayMs?: number;
15
+ /** A stream with no event for this long is aborted and retried. Default 300 s. */
16
+ readonly idleTimeoutMs?: number;
17
+ /** Whole-request timeout passed to the provider SDK. Default 600 s. */
18
+ readonly requestTimeoutMs?: number;
19
+ }
9
20
  export interface PiModelOptions {
10
21
  readonly root?: string;
11
22
  readonly onPreview?: (preview: ModelPreview) => void;
12
23
  readonly media?: Pick<RuntimeMedia, "dataUrl">;
13
24
  readonly readHostModel?: () => HostModelSecret | undefined | Promise<HostModelSecret | undefined>;
14
25
  readonly writeHostCredential?: (credential: Credential) => void | Promise<void>;
26
+ readonly settings?: ModelCallSettings;
15
27
  }
16
- /** Node model adapter. Local provider configuration is read only when invoked. */
28
+ /**
29
+ * Node model adapter. Local provider configuration is read only when invoked.
30
+ * A provider failure is returned as a failure outcome; only an abort is thrown.
31
+ */
17
32
  export declare function piModel(options?: PiModelOptions): RuntimeModelAdapter;