@nylorun/runtime 0.25.0-beta → 0.27.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 (326) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +26 -16
  3. package/dist/adapters/execution/restate.d.ts +15 -18
  4. package/dist/adapters/execution/restate.js +31 -27
  5. package/dist/adapters/replication/pgoutput.d.ts +1 -1
  6. package/dist/adapters/replication/pgoutput.js +3 -2
  7. package/dist/adapters/sandbox/local.js +8 -5
  8. package/dist/adapters/sandbox/virtual.js +2 -2
  9. package/dist/adapters/streams/s2.d.ts +1 -1
  10. package/dist/adapters/streams/s2.js +18 -14
  11. package/dist/api/a2a/card.js +1 -1
  12. package/dist/api/a2a/endpoint.js +3 -4
  13. package/dist/api/a2a/protocol.js +4 -0
  14. package/dist/api/a2a/routes.d.ts +2 -6
  15. package/dist/api/a2a/routes.js +12 -18
  16. package/dist/api/ag-ui/endpoint.js +2 -3
  17. package/dist/api/ag-ui/routes.js +4 -4
  18. package/dist/api/components.d.ts +326 -45
  19. package/dist/api/components.js +5 -1
  20. package/dist/api/gate/keys.js +7 -4
  21. package/dist/api/gate/routes.d.ts +6 -2
  22. package/dist/api/gate/routes.js +15 -11
  23. package/dist/api/http/app.d.ts +2 -2
  24. package/dist/api/http/app.js +2 -2
  25. package/dist/api/http/body.d.ts +15 -3
  26. package/dist/api/http/body.js +15 -7
  27. package/dist/api/http/define.d.ts +1 -1
  28. package/dist/api/http/respond.js +7 -3
  29. package/dist/api/http/routes/access.js +5 -4
  30. package/dist/api/http/routes/artifacts.js +19 -7
  31. package/dist/api/http/routes/coverage.js +1 -1
  32. package/dist/api/http/routes/environment-manifests.js +1 -1
  33. package/dist/api/http/routes/environments.js +6 -6
  34. package/dist/api/http/routes/files.d.ts +2 -1
  35. package/dist/api/http/routes/files.js +31 -5
  36. package/dist/api/http/routes/mcp.js +1 -1
  37. package/dist/api/http/routes/reads.d.ts +35 -0
  38. package/dist/api/http/routes/reads.js +50 -22
  39. package/dist/api/http/routes/sessions.js +12 -11
  40. package/dist/api/http/routes/tenant.d.ts +2 -2
  41. package/dist/api/http/routes/tenant.js +69 -16
  42. package/dist/api/inbound-files.d.ts +3 -9
  43. package/dist/api/inbound-files.js +18 -24
  44. package/dist/api/openapi.js +6 -2
  45. package/dist/artifacts/disk.d.ts +0 -4
  46. package/dist/artifacts/disk.js +77 -73
  47. package/dist/artifacts/files.d.ts +13 -4
  48. package/dist/artifacts/files.js +27 -9
  49. package/dist/artifacts/folder-upload.d.ts +75 -0
  50. package/dist/artifacts/folder-upload.js +263 -0
  51. package/dist/artifacts/folders.d.ts +14 -8
  52. package/dist/artifacts/folders.js +19 -11
  53. package/dist/artifacts/links.js +7 -6
  54. package/dist/artifacts/parts.d.ts +9 -14
  55. package/dist/artifacts/parts.js +11 -9
  56. package/dist/artifacts/pipe.d.ts +15 -0
  57. package/dist/artifacts/pipe.js +71 -0
  58. package/dist/artifacts/quota.d.ts +36 -0
  59. package/dist/artifacts/quota.js +44 -0
  60. package/dist/artifacts/service.d.ts +25 -1
  61. package/dist/artifacts/service.js +70 -25
  62. package/dist/blob/fs.js +2 -1
  63. package/dist/blob/s3.d.ts +6 -2
  64. package/dist/blob/s3.js +9 -7
  65. package/dist/blob/types.d.ts +1 -1
  66. package/dist/blob/types.js +1 -1
  67. package/dist/core/limits.d.ts +11 -35
  68. package/dist/core/limits.js +5 -73
  69. package/dist/core/sandbox-routes.js +0 -1
  70. package/dist/core/turn-manifest.d.ts +1 -2
  71. package/dist/core/turn-manifest.js +4 -28
  72. package/dist/execution/memory.d.ts +8 -5
  73. package/dist/execution/memory.js +8 -6
  74. package/dist/execution/types.d.ts +1 -6
  75. package/dist/execution/types.js +0 -5
  76. package/dist/gates/contract.d.ts +3 -2
  77. package/dist/gates/contract.js +1 -1
  78. package/dist/gates/egress-credentials.js +4 -3
  79. package/dist/gates/egress.d.ts +9 -9
  80. package/dist/gates/egress.js +19 -19
  81. package/dist/gates/fixture-model.js +13 -2
  82. package/dist/gates/handler.d.ts +1 -3
  83. package/dist/gates/handler.js +4 -3
  84. package/dist/gates/http-client.d.ts +4 -3
  85. package/dist/gates/http-client.js +5 -7
  86. package/dist/gates/http-tool.d.ts +24 -4
  87. package/dist/gates/http-tool.js +53 -17
  88. package/dist/gates/in-process.d.ts +2 -1
  89. package/dist/gates/in-process.js +17 -9
  90. package/dist/gates/inflight.d.ts +2 -2
  91. package/dist/gates/inflight.js +3 -2
  92. package/dist/gates/journal.js +5 -7
  93. package/dist/gates/mcp-handler.d.ts +4 -3
  94. package/dist/gates/mcp-handler.js +15 -5
  95. package/dist/gates/model-gate.d.ts +11 -2
  96. package/dist/gates/policy.d.ts +28 -5
  97. package/dist/gates/policy.js +60 -17
  98. package/dist/gates/provider-gate.d.ts +22 -0
  99. package/dist/gates/provider-gate.js +30 -0
  100. package/dist/gates/tool-calls.d.ts +1 -3
  101. package/dist/gates/tool-calls.js +2 -3
  102. package/dist/gates/tool-client.d.ts +1 -1
  103. package/dist/gates/tool-client.js +5 -6
  104. package/dist/gates/tool-contract.d.ts +8 -5
  105. package/dist/gates/tool-contract.js +1 -1
  106. package/dist/gates/tool-gate.d.ts +18 -7
  107. package/dist/gates/tool-gate.js +49 -7
  108. package/dist/harness/calls.d.ts +27 -25
  109. package/dist/harness/calls.js +40 -46
  110. package/dist/harness/executors.d.ts +10 -3
  111. package/dist/harness/executors.js +53 -23
  112. package/dist/harness/main.js +2 -2
  113. package/dist/harness/pod.d.ts +0 -2
  114. package/dist/harness/pod.js +7 -6
  115. package/dist/harness/run-tokens.d.ts +4 -1
  116. package/dist/harness/run-tokens.js +6 -2
  117. package/dist/harness/service.d.ts +17 -14
  118. package/dist/harness/service.js +21 -35
  119. package/dist/harness/setup.d.ts +0 -2
  120. package/dist/harness/setup.js +4 -9
  121. package/dist/harness/ws-client.d.ts +2 -2
  122. package/dist/harness/ws-client.js +7 -5
  123. package/dist/harness/ws-port.d.ts +3 -4
  124. package/dist/harness/ws-port.js +3 -4
  125. package/dist/harness-api/artifacts.d.ts +20 -0
  126. package/dist/harness-api/artifacts.js +478 -0
  127. package/dist/harness-api/in-process.d.ts +2 -2
  128. package/dist/harness-api/in-process.js +18 -16
  129. package/dist/harness-api/record.d.ts +10 -9
  130. package/dist/harness-api/record.js +102 -157
  131. package/dist/harness-api/renew.d.ts +1 -1
  132. package/dist/harness-api/renew.js +2 -2
  133. package/dist/harness-api/server.d.ts +1 -16
  134. package/dist/harness-api/server.js +82 -73
  135. package/dist/harness-api/start.d.ts +20 -2
  136. package/dist/harness-api/start.js +57 -18
  137. package/dist/harness-api/tool-journal.d.ts +15 -10
  138. package/dist/harness-api/tool-journal.js +26 -24
  139. package/dist/harness-api/workspace.d.ts +0 -4
  140. package/dist/harness-api/workspace.js +2 -45
  141. package/dist/harness-api/ws-server.js +10 -10
  142. package/dist/host/create-host.js +2 -3
  143. package/dist/host/execution.js +2 -3
  144. package/dist/host/gates.d.ts +2 -9
  145. package/dist/host/gates.js +15 -12
  146. package/dist/host/http.d.ts +0 -2
  147. package/dist/host/http.js +0 -27
  148. package/dist/host/main.js +10 -3
  149. package/dist/host/operate.js +12 -3
  150. package/dist/host/stack-config.d.ts +11 -0
  151. package/dist/host/stack-config.js +21 -1
  152. package/dist/index.d.ts +0 -1
  153. package/dist/index.js +0 -1
  154. package/dist/infra/index.js +2 -1
  155. package/dist/infra/readiness.d.ts +0 -2
  156. package/dist/infra/readiness.js +4 -3
  157. package/dist/keys/client.d.ts +1 -0
  158. package/dist/keys/client.js +2 -3
  159. package/dist/keys/contract.d.ts +1 -3
  160. package/dist/keys/contract.js +1 -3
  161. package/dist/keys/egress-ca.d.ts +0 -2
  162. package/dist/keys/egress-ca.js +2 -3
  163. package/dist/keys/keys.js +6 -1
  164. package/dist/keys/x509.d.ts +8 -4
  165. package/dist/keys/x509.js +14 -5
  166. package/dist/management-openapi.json +1961 -994
  167. package/dist/mcp/connect.d.ts +35 -26
  168. package/dist/mcp/connect.js +112 -141
  169. package/dist/mcp/pool.d.ts +27 -22
  170. package/dist/mcp/pool.js +34 -48
  171. package/dist/mcp/preview.d.ts +13 -6
  172. package/dist/mcp/preview.js +37 -20
  173. package/dist/mcp/snapshot.d.ts +35 -86
  174. package/dist/mcp/snapshot.js +93 -135
  175. package/dist/model/auth-store.js +5 -3
  176. package/dist/model/capabilities.d.ts +1 -1
  177. package/dist/model/catalog.d.ts +9 -36
  178. package/dist/model/catalog.js +6 -33
  179. package/dist/model/descriptor.d.ts +51 -0
  180. package/dist/model/descriptor.js +83 -0
  181. package/dist/model/models.d.ts +0 -3
  182. package/dist/model/models.js +3 -5
  183. package/dist/model/native-blocks.js +1 -1
  184. package/dist/model/pi-model.d.ts +16 -5
  185. package/dist/model/pi-model.js +86 -105
  186. package/dist/openapi.json +866 -1218
  187. package/dist/reads/cursor.js +3 -1
  188. package/dist/record/append.d.ts +34 -2
  189. package/dist/record/append.js +50 -1
  190. package/dist/record/environment.d.ts +2 -0
  191. package/dist/record/environment.js +2 -0
  192. package/dist/record/index.d.ts +1 -1
  193. package/dist/record/index.js +1 -1
  194. package/dist/redact.d.ts +1 -1
  195. package/dist/redact.js +3 -2
  196. package/dist/sandbox/egress-token.d.ts +3 -3
  197. package/dist/sandbox/egress-token.js +3 -3
  198. package/dist/sandbox/join.js +3 -2
  199. package/dist/sandbox/manager.d.ts +41 -41
  200. package/dist/sandbox/manager.js +112 -44
  201. package/dist/sandbox/placement.d.ts +1 -1
  202. package/dist/sandbox/placement.js +5 -8
  203. package/dist/sandbox/pods/client.d.ts +1 -10
  204. package/dist/sandbox/pods/client.js +8 -4
  205. package/dist/sandbox/pods/lifecycle.d.ts +19 -11
  206. package/dist/sandbox/pods/lifecycle.js +45 -23
  207. package/dist/sandbox/pods/network-gate.d.ts +4 -5
  208. package/dist/sandbox/pods/network-gate.js +7 -7
  209. package/dist/sandbox/pods/reconcile.js +4 -1
  210. package/dist/sandbox/pods/spec.js +8 -5
  211. package/dist/sandbox/policy.d.ts +7 -1
  212. package/dist/sandbox/policy.js +10 -3
  213. package/dist/sandbox/resolve.d.ts +8 -3
  214. package/dist/sandbox/resolve.js +12 -2
  215. package/dist/sandbox/setup.d.ts +3 -1
  216. package/dist/sandbox/setup.js +34 -11
  217. package/dist/sandbox/share.d.ts +5 -14
  218. package/dist/sandbox/share.js +5 -34
  219. package/dist/sandbox/skills.d.ts +7 -13
  220. package/dist/sandbox/skills.js +16 -31
  221. package/dist/sandbox/tenant-config.d.ts +2 -2
  222. package/dist/sandbox/tenant-config.js +4 -3
  223. package/dist/sandbox/tools.d.ts +7 -1
  224. package/dist/sandbox/tools.js +26 -26
  225. package/dist/sandbox/types.d.ts +10 -3
  226. package/dist/sandbox/types.js +9 -0
  227. package/dist/store/postgres/connect.d.ts +6 -5
  228. package/dist/store/postgres/connect.js +14 -11
  229. package/dist/store/postgres/control.js +13 -13
  230. package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
  231. package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
  232. package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
  233. package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
  234. package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
  235. package/dist/store/postgres/migrate.js +1 -1
  236. package/dist/store/postgres/reads.js +10 -2
  237. package/dist/store/postgres/schema.d.ts +19 -0
  238. package/dist/store/postgres/schema.js +7 -0
  239. package/dist/store/postgres/store.js +55 -26
  240. package/dist/store/types.d.ts +17 -7
  241. package/dist/streams/relay/core.d.ts +3 -3
  242. package/dist/streams/relay/core.js +9 -10
  243. package/dist/tenant/advance.js +21 -31
  244. package/dist/tenant/commands.js +9 -16
  245. package/dist/tenant/context.d.ts +14 -17
  246. package/dist/tenant/definition-files.d.ts +25 -4
  247. package/dist/tenant/definition-files.js +85 -47
  248. package/dist/tenant/effects.js +9 -36
  249. package/dist/tenant/environment-manifests.js +9 -1
  250. package/dist/tenant/environments.d.ts +0 -2
  251. package/dist/tenant/environments.js +54 -30
  252. package/dist/tenant/ephemeral.d.ts +1 -1
  253. package/dist/tenant/ephemeral.js +2 -1
  254. package/dist/tenant/history.d.ts +1 -1
  255. package/dist/tenant/history.js +1 -1
  256. package/dist/tenant/host-token.d.ts +3 -3
  257. package/dist/tenant/host-token.js +12 -11
  258. package/dist/tenant/http.d.ts +5 -8
  259. package/dist/tenant/http.js +9 -0
  260. package/dist/tenant/identity-file.d.ts +24 -1
  261. package/dist/tenant/identity-file.js +35 -7
  262. package/dist/tenant/issuers.d.ts +5 -5
  263. package/dist/tenant/issuers.js +31 -23
  264. package/dist/tenant/jwt.d.ts +8 -2
  265. package/dist/tenant/jwt.js +10 -2
  266. package/dist/tenant/limits.d.ts +90 -0
  267. package/dist/tenant/limits.js +175 -0
  268. package/dist/tenant/module.d.ts +4 -1
  269. package/dist/tenant/module.js +9 -8
  270. package/dist/tenant/outbound.d.ts +17 -19
  271. package/dist/tenant/outbound.js +18 -21
  272. package/dist/tenant/run-grants.js +3 -2
  273. package/dist/tenant/run-token.d.ts +0 -4
  274. package/dist/tenant/run-token.js +6 -11
  275. package/dist/tenant/runtime-limits.d.ts +24 -0
  276. package/dist/tenant/runtime-limits.js +27 -0
  277. package/dist/tenant/runtime.js +30 -43
  278. package/dist/tenant/session-streams.js +7 -6
  279. package/dist/tenant/session.d.ts +1 -1
  280. package/dist/tenant/session.js +1 -1
  281. package/dist/tenant/sessions.js +32 -29
  282. package/dist/tenant/signing-keys.d.ts +1 -1
  283. package/dist/tenant/signing-keys.js +5 -6
  284. package/dist/tenant/status.js +4 -3
  285. package/dist/tenant/streams.js +18 -20
  286. package/dist/tenant/sweep.d.ts +1 -21
  287. package/dist/tenant/sweep.js +39 -48
  288. package/dist/tenant/transcript.d.ts +70 -23
  289. package/dist/tenant/transcript.js +28 -22
  290. package/dist/tenant/types.d.ts +11 -16
  291. package/dist/tenant/worker.d.ts +2 -10
  292. package/dist/tenant/worker.js +5 -14
  293. package/dist/traces/ids.js +5 -1
  294. package/dist/traces/map.d.ts +9 -6
  295. package/dist/traces/map.js +9 -11
  296. package/dist/traces/otlp.d.ts +3 -3
  297. package/dist/traces/otlp.js +5 -3
  298. package/dist/traces/projector.d.ts +9 -4
  299. package/dist/traces/projector.js +13 -7
  300. package/dist/traces/read.js +6 -1
  301. package/dist/tuning.d.ts +383 -0
  302. package/dist/tuning.js +658 -0
  303. package/dist/vault/headers.js +4 -2
  304. package/dist/version.d.ts +1 -1
  305. package/dist/version.js +1 -1
  306. package/package.json +3 -3
  307. package/dist/artifacts/export.d.ts +0 -8
  308. package/dist/artifacts/export.js +0 -204
  309. package/dist/artifacts/media-types.d.ts +0 -30
  310. package/dist/artifacts/media-types.js +0 -137
  311. package/dist/artifacts/workspace.d.ts +0 -60
  312. package/dist/artifacts/workspace.js +0 -45
  313. package/dist/media.d.ts +0 -10
  314. package/dist/media.js +0 -58
  315. package/dist/sandbox/runtime-tools.d.ts +0 -9
  316. package/dist/sandbox/runtime-tools.js +0 -16
  317. package/dist/sandbox/session-sandbox.d.ts +0 -16
  318. package/dist/sandbox/session-sandbox.js +0 -77
  319. package/dist/tenant/artifact-tool.d.ts +0 -13
  320. package/dist/tenant/artifact-tool.js +0 -243
  321. package/dist/tenant/skill-tool.d.ts +0 -20
  322. package/dist/tenant/skill-tool.js +0 -67
  323. package/dist/tenant/tool-results.d.ts +0 -57
  324. package/dist/tenant/tool-results.js +0 -298
  325. package/dist/tenant/tool-search.d.ts +0 -39
  326. package/dist/tenant/tool-search.js +0 -103
@@ -1,77 +0,0 @@
1
- /**
2
- * Gives a session the sandbox chosen when it was opened, and the Runtime tools its agents need.
3
- * An agent session's pinned manifest is its definition with a `runtime` block
4
- * (`runtimeManifestFor`) on each agent of the tree:
5
- *
6
- * - with a sandbox, the six sandbox tools, their instructions and the resolved spec, and
7
- * `save_artifact`, so files the agent makes reach the user (F8.1). The agents it uses as tools
8
- * get the same spec, so the tree shares one sandbox. The sandbox's instructions name the
9
- * agent's skills' folders (`/skills/<name>@<hash>/`);
10
- * - with or without a sandbox, `read_artifact` (R2b C11, protocol 12): the Runtime stores a result
11
- * of an MCP or HTTP tool too large to show as an artifact, and the model reads it in pages; a
12
- * file of an earlier turn is a reference line the model reads again with it;
13
- * - with skills, `load_skill`, `read_skill_resource` and the skill catalog.
14
- *
15
- * `tool_search` and `tool_call` are not pinned: they are session tools, given per run when the
16
- * session defers some MCP tools (R2b C10). An author tool may not take any of these names (the
17
- * manifest schema refuses it), so a tool's name alone says whose it is. The definition in the
18
- * registry never changes.
19
- */
20
- import { AgentManifestSchema } from "@nylorun/core/contracts";
21
- import { hashManifest, runtimeManifestFor, } from "@nylorun/core/define";
22
- function isAgentManifest(value) {
23
- return (typeof value === "object" &&
24
- value !== null &&
25
- value.kind !== "workflow" &&
26
- typeof value.id === "string");
27
- }
28
- /** `manifest` with its `runtime` block, and each agent it uses as a tool with its own. */
29
- function pinRuntime(manifest, spec) {
30
- let changed = false;
31
- const tools = manifest.tools?.map((tool) => {
32
- // Agents used as tools share the session's sandbox; flow agents used as tools run in linked
33
- // sessions that inherit it.
34
- if (tool.agent === undefined || !isAgentManifest(tool.agent))
35
- return tool;
36
- const agent = pinRuntime(tool.agent, spec);
37
- if (agent === tool.agent)
38
- return tool;
39
- changed = true;
40
- return { ...tool, agent };
41
- });
42
- const runtime = runtimeManifestFor(manifest, {
43
- ...(spec === undefined ? {} : { sandbox: spec }),
44
- save: spec !== undefined,
45
- read: true,
46
- });
47
- if (runtime === undefined && !changed)
48
- return manifest;
49
- return {
50
- ...manifest,
51
- ...(changed ? { tools } : {}),
52
- ...(runtime === undefined ? {} : { runtime }),
53
- };
54
- }
55
- /** `pinned` checked as a manifest, with its hash. */
56
- function checked(original, pinned) {
57
- const parsed = AgentManifestSchema.safeParse(pinned);
58
- if (!parsed.success) {
59
- const issues = parsed.error.issues.map((issue) => issue.message);
60
- return {
61
- ok: false,
62
- message: `'${original.id}' cannot take the Runtime's tools: ${[...new Set(issues)].join("; ")}`,
63
- };
64
- }
65
- return { ok: true, manifest: pinned, manifestHash: hashManifest(pinned) };
66
- }
67
- /** The agent's pinned manifest with the session's sandbox, or why it cannot take one. */
68
- export function withSandbox(manifest, spec) {
69
- return checked(manifest, pinRuntime(manifest, spec));
70
- }
71
- /**
72
- * The pinned manifest of an agent session without a sandbox: `read_artifact` for each agent of
73
- * the tree (R2b C11, protocol 12), and the skill tools for each with skills.
74
- */
75
- export function withRuntimeTools(manifest) {
76
- return checked(manifest, pinRuntime(manifest, undefined));
77
- }
@@ -1,13 +0,0 @@
1
- import type { SandboxToolOutcome } from "@nylorun/core/contracts";
2
- import { type ToolResultFile } from "@nylorun/core/define";
3
- import type { HostEffect } from "@nylorun/harness/run";
4
- import { type TenantContext } from "./context.js";
5
- export { isReadArtifactCall, isSaveArtifactCall } from "../harness/calls.js";
6
- export declare function callSaveArtifact(ctx: TenantContext, request: HostEffect, signal: AbortSignal): Promise<SandboxToolOutcome>;
7
- /** What `read_artifact` returns: a page of a text artifact, or a file the model reads. */
8
- interface ReadOutcome {
9
- readonly kind: "completed";
10
- readonly output: Record<string, unknown>;
11
- readonly files?: readonly ToolResultFile[];
12
- }
13
- export declare function callReadArtifact(ctx: TenantContext, request: HostEffect, signal: AbortSignal): Promise<ReadOutcome | SandboxToolOutcome>;
@@ -1,243 +0,0 @@
1
- /**
2
- * Our engine's built-in artifact tools, which the Runtime pins in a session agent's `runtime`
3
- * block (`sandbox/session-sandbox.ts`). The Runtime runs them itself, like the sandbox tools.
4
- *
5
- * `save_artifact` (F8.1), which comes with a session's sandbox, saves a file as an artifact of
6
- * its session:
7
- * - `path`: a file in the session's sandbox, read as bytes in the sandbox's queue;
8
- * - `content`: text the model passes.
9
- * The version commits with `artifact.created` (or `artifact.version.created`) on the session's
10
- * stream, carrying the turn and the tool call.
11
- *
12
- * `read_artifact` (R2b C11, Q24; every agent since protocol 12) reads a text artifact in pages of
13
- * at most 32 KiB, from a byte `offset`: how the model reads a tool result the Runtime stored
14
- * because it was too large to show (`tool-results.ts`), and a file of an earlier turn again, by
15
- * its reference line. Another file is shown as a file of the result when the Tenant's model reads
16
- * its type, and refused (`artifact.unsupported`) when it does not. It reaches the session's own
17
- * artifacts and the Tenant-wide ones its messages named (`Session.fileArtifacts`), never another
18
- * session's. `version` picks a version; the latest by default.
19
- *
20
- * Expected problems (no such file, too large, the Tenant's total reached, not text) are failed
21
- * outcomes the model sees; only infrastructure errors throw.
22
- */
23
- import { basename } from "node:path";
24
- import { READ_ARTIFACT_MAX_BYTES } from "@nylorun/core/define";
25
- import { isArtifactId } from "@nylorun/core/compatibility";
26
- import { readArtifactLimits } from "../artifacts/config.js";
27
- import { contentTypeFor, essence, isText, normalizeContentType, unreadableReason, } from "../artifacts/media-types.js";
28
- import { currentModelInputs } from "../model/catalog.js";
29
- import { uploadArtifact } from "../artifacts/service.js";
30
- import { DEFAULT_CONTENT_TYPE } from "../blob/index.js";
31
- import { sandboxToolSpec } from "../sandbox/manager.js";
32
- import { sandboxWorkspaceOf } from "../sandbox/share.js";
33
- import { sessionOf } from "./context.js";
34
- import { HttpError } from "./http.js";
35
- import { manifestFor } from "./session.js";
36
- import { jsonBytes, utf8Boundary } from "./tool-results.js";
37
- import { toolIds } from "./transcript.js";
38
- export { isReadArtifactCall, isSaveArtifactCall } from "../harness/calls.js";
39
- const failed = (code, message) => ({
40
- kind: "failed",
41
- code,
42
- message,
43
- });
44
- export async function callSaveArtifact(ctx, request, signal) {
45
- const input = (request.input ?? {});
46
- const path = typeof input.path === "string" && input.path !== "" ? input.path : undefined;
47
- const content = typeof input.content === "string" ? input.content : undefined;
48
- if ((path === undefined) === (content === undefined))
49
- return failed("artifact.invalid_input", "Give path or content, not both.");
50
- const artifactId = typeof input.artifactId === "string" ? input.artifactId : undefined;
51
- const { s, workspace, limits, ours } = await ctx.store.tx(async (t) => {
52
- const s = await sessionOf(t, request.sessionId);
53
- // A new version only of an artifact of this session.
54
- const ours = artifactId === undefined ||
55
- (isArtifactId(artifactId) && (await t.artifact(artifactId))?.sessionId === s.id);
56
- return {
57
- s,
58
- workspace: sandboxWorkspaceOf(s),
59
- limits: await readArtifactLimits(t),
60
- ours,
61
- };
62
- });
63
- if (!ours)
64
- return failed("artifact.not_found", `Artifact ${artifactId} is not an artifact of this session.`);
65
- let bytes;
66
- let fileName;
67
- if (path !== undefined) {
68
- const spec = sandboxToolSpec(manifestFor(s.manifest, request.agent), "read");
69
- if (!spec)
70
- return failed("artifact.no_sandbox", "This session has no sandbox to read a path from.");
71
- const read = await ctx.sandbox.readBytes({
72
- id: workspace.ownerId,
73
- activeTurnId: s.activeTurnId,
74
- manifest: s.manifest,
75
- ...(workspace.environmentId === undefined ? {} : { environmentId: workspace.environmentId }),
76
- }, spec, path, limits.fileBytes, signal);
77
- if (read.kind === "failed")
78
- return read;
79
- if (read.kind === "missing")
80
- return failed("artifact.not_found", `${read.path} does not exist in the sandbox.`);
81
- bytes = read.bytes;
82
- fileName = basename(read.path);
83
- }
84
- else {
85
- bytes = new TextEncoder().encode(content);
86
- fileName = "artifact.txt";
87
- }
88
- const name = typeof input.name === "string" && input.name !== "" ? input.name : fileName;
89
- let contentType;
90
- if (typeof input.contentType === "string") {
91
- const declared = normalizeContentType(input.contentType);
92
- if (declared === undefined)
93
- return failed("artifact.invalid_input", `${input.contentType} is not a media type.`);
94
- contentType = declared;
95
- }
96
- else {
97
- contentType = contentTypeFor(name);
98
- if (content !== undefined && contentType === DEFAULT_CONTENT_TYPE)
99
- contentType = "text/plain; charset=utf-8";
100
- }
101
- const ids = toolIds(request.context);
102
- try {
103
- const saved = await uploadArtifact(ctx, {
104
- ...(artifactId !== undefined ? { artifactId } : { name }),
105
- contentType,
106
- sessionId: s.id,
107
- source: "engine",
108
- turnId: request.turnId,
109
- ...("callId" in ids ? { callId: ids.callId } : {}),
110
- }, bytes,
111
- // Our engine saves into its own session only.
112
- { owner: s.ownerUserId }, signal);
113
- return {
114
- kind: "completed",
115
- output: {
116
- artifactId: saved.artifact.artifactId,
117
- version: saved.version.version,
118
- name: saved.artifact.name,
119
- contentType: saved.version.contentType,
120
- size: saved.version.size,
121
- sha256: saved.version.sha256,
122
- },
123
- };
124
- }
125
- catch (error) {
126
- if (error instanceof HttpError)
127
- return failed(error.rejection.code === "limit_exceeded" ? "artifact.too_large" : "artifact.rejected", error.message);
128
- throw error;
129
- }
130
- }
131
- export async function callReadArtifact(ctx, request, signal) {
132
- const input = (request.input ?? {});
133
- const artifactId = typeof input.artifactId === "string" ? input.artifactId : "";
134
- const wanted = input.version;
135
- const offset = input.offset ?? 0;
136
- const length = input.length ?? READ_ARTIFACT_MAX_BYTES;
137
- if (artifactId === "" ||
138
- (wanted !== undefined &&
139
- (typeof wanted !== "number" || !Number.isSafeInteger(wanted) || wanted < 1)) ||
140
- typeof offset !== "number" ||
141
- !Number.isSafeInteger(offset) ||
142
- offset < 0 ||
143
- typeof length !== "number" ||
144
- !Number.isSafeInteger(length) ||
145
- length < 1 ||
146
- length > READ_ARTIFACT_MAX_BYTES)
147
- return failed("artifact.invalid_input", `Give artifactId, a version of 1 or more if any, an offset of 0 or more, and a length of 1 to ${READ_ARTIFACT_MAX_BYTES}.`);
148
- const found = await ctx.store.tx(async (t) => {
149
- const s = await sessionOf(t, request.sessionId);
150
- if (!isArtifactId(artifactId))
151
- return undefined;
152
- // An artifact of this session, or a Tenant-wide one its messages named; never another
153
- // session's.
154
- const artifact = await t.artifact(artifactId);
155
- if (!artifact ||
156
- (artifact.sessionId !== s.id &&
157
- !(artifact.sessionId === null && s.fileArtifacts?.includes(artifact.id))))
158
- return undefined;
159
- const version = await t.artifactVersion(artifact.id, typeof wanted === "number" ? wanted : artifact.latestVersion);
160
- return { artifact, version };
161
- });
162
- if (!found)
163
- return failed("artifact.not_found", `Artifact ${artifactId} is not an artifact of this session.`);
164
- if (!found.version)
165
- return failed("artifact.not_found", `Artifact ${artifactId} has no version ${String(wanted)}.`);
166
- const { artifact, version } = found;
167
- const about = {
168
- artifactId: artifact.id,
169
- version: version.version,
170
- name: artifact.name,
171
- contentType: version.contentType,
172
- size: version.size,
173
- };
174
- if (artifact.kind !== "file")
175
- return failed("artifact.not_text", `${artifact.name} is a folder; read_artifact reads a file.`);
176
- if (!isText(version.contentType)) {
177
- // A file the Tenant's model reads goes to it beside the result (protocol 12). Without a
178
- // model in the vault (a test's fake provider), text and images.
179
- const inputs = (await currentModelInputs(ctx)) ?? ["text", "image"];
180
- const reason = unreadableReason(version.contentType, inputs);
181
- if (reason)
182
- return failed("artifact.unsupported", `${artifact.name} is ${essence(version.contentType)}: ${reason}.`);
183
- return {
184
- kind: "completed",
185
- output: about,
186
- files: [
187
- {
188
- mediaType: version.contentType,
189
- reference: {
190
- artifactId: artifact.id,
191
- version: version.version,
192
- name: artifact.name,
193
- size: version.size,
194
- },
195
- },
196
- ],
197
- };
198
- }
199
- if (offset > version.size || (offset === version.size && version.size > 0))
200
- return failed("artifact.invalid_input", `Offset ${offset} is past the end of ${artifact.name}, which is ${version.size} bytes.`);
201
- const end = Math.min(offset + length, version.size);
202
- const bytes = end === offset ? new Uint8Array() : await readRange(ctx, version.blobKey, offset, end - 1, signal);
203
- const page = textPage(bytes, end === version.size);
204
- const next = offset + page.bytes;
205
- return {
206
- kind: "completed",
207
- output: {
208
- ...about,
209
- offset,
210
- content: page.text,
211
- ...(next < version.size ? { nextOffset: next } : {}),
212
- },
213
- };
214
- }
215
- /** Bytes `start` to `end` (both inclusive) of a version's blob. */
216
- async function readRange(ctx, blobKey, start, end, signal) {
217
- const got = await ctx.blobs.get(blobKey, { range: { start, end }, signal });
218
- if (!got)
219
- throw new Error("The artifact's bytes are missing from the Object store");
220
- return new Uint8Array(await new Response(got.body).arrayBuffer());
221
- }
222
- /**
223
- * The text of a page of UTF-8 `bytes` in whole characters, at most `READ_ARTIFACT_MAX_BYTES`
224
- * once escaped as JSON, and how many bytes it used: the next page starts there. A page that
225
- * starts inside a character skips its rest, and one that ends inside one (not `last`) stops
226
- * before it.
227
- */
228
- function textPage(bytes, last) {
229
- const from = utf8Boundary(bytes, 0, "up");
230
- let to = last ? bytes.byteLength : utf8Boundary(bytes, bytes.byteLength, "down");
231
- // A page shorter than one character: take what there is.
232
- if (to <= from)
233
- to = bytes.byteLength;
234
- const decode = () => Buffer.from(bytes.subarray(from, to)).toString("utf8");
235
- let text = decode();
236
- // Escaped (quotes, newlines, control characters), text takes more room than its bytes: each
237
- // byte left out frees at least one.
238
- for (let size = jsonBytes(text); to > from && size > READ_ARTIFACT_MAX_BYTES; size = jsonBytes(text)) {
239
- to = utf8Boundary(bytes, Math.max(from, to - (size - READ_ARTIFACT_MAX_BYTES)), "down");
240
- text = decode();
241
- }
242
- return { text, bytes: to };
243
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * The skill tools (track R2 M4): `load_skill` and `read_skill_resource`, which the Runtime pins
3
- * in the `runtime` block of an agent with skills. The Runtime runs them itself, like `save_artifact`, from the
4
- * definition files uploaded with the agent: no developer process is involved.
5
- *
6
- * - `load_skill`: the skill's instructions (its `SKILL.md` after the frontmatter), the paths of
7
- * its other files, and, when the session has a sandbox, where they are in it
8
- * (`/skills/<name>@<hash>/`, read-only, D66).
9
- * - `read_skill_resource`: one text file of the skill. A binary file is refused: the model reads
10
- * it in the sandbox, when there is one.
11
- *
12
- * Expected problems are failed outcomes the model sees; only infrastructure errors throw.
13
- */
14
- import type { SandboxToolOutcome } from "@nylorun/core/contracts";
15
- import { type AgentManifest } from "@nylorun/core/define";
16
- import type { HostEffect } from "@nylorun/harness/run";
17
- import type { TenantContext } from "./context.js";
18
- /** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
19
- export declare function isSkillToolCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
20
- export declare function callSkillTool(ctx: TenantContext, manifest: AgentManifest, request: HostEffect, signal: AbortSignal): Promise<SandboxToolOutcome>;
@@ -1,67 +0,0 @@
1
- import { LOAD_SKILL_TOOL, SKILL_ENTRY, skillFolderOf, isSkillTool, skillInstructions, } from "@nylorun/core/define";
2
- import { sandboxToolSpec } from "../sandbox/runtime-tools.js";
3
- import { readDefinitionFile } from "./definition-files.js";
4
- const failed = (code, message) => ({ kind: "failed", code, message });
5
- /** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
6
- export function isSkillToolCall(manifest, request) {
7
- return request.kind === "tool" && isSkillTool(manifest, request.toolName);
8
- }
9
- /** Every skill of the agent, by name. */
10
- function skillsOf(manifest) {
11
- return new Map(Object.values(manifest.skills ?? {}).map((skill) => [skill.name, skill]));
12
- }
13
- /** UTF-8 text, or undefined for bytes that are not (a NUL byte, or invalid UTF-8). */
14
- function textOf(bytes) {
15
- if (bytes.includes(0))
16
- return undefined;
17
- try {
18
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
19
- }
20
- catch {
21
- return undefined;
22
- }
23
- }
24
- export async function callSkillTool(ctx, manifest, request, signal) {
25
- const input = (request.input ?? {});
26
- const skills = skillsOf(manifest);
27
- const name = typeof input.name === "string" ? input.name : "";
28
- const skill = skills.get(name);
29
- if (!skill)
30
- return request.toolName === LOAD_SKILL_TOOL
31
- ? { kind: "completed", output: { unknown: name, available: [...skills.keys()].sort() } }
32
- : failed("skill.unknown", `There is no skill '${name}'.`);
33
- const sandboxed = sandboxToolSpec(manifest, "bash") !== undefined;
34
- const directory = `${skillFolderOf(skill)}/`;
35
- const read = async (path) => {
36
- const bytes = await readDefinitionFile(ctx.blobs, skill.files[path], signal);
37
- if (!bytes)
38
- throw new Error(`The bytes of ${skill.files[path]} (${skill.name}/${path}) are missing from the Object store`);
39
- return bytes;
40
- };
41
- if (request.toolName === LOAD_SKILL_TOOL) {
42
- const text = textOf(await read(SKILL_ENTRY));
43
- if (text === undefined)
44
- return failed("skill.binary_resource", `${SKILL_ENTRY} of '${skill.name}' is not text.`);
45
- const resources = Object.keys(skill.files)
46
- .filter((path) => path !== SKILL_ENTRY)
47
- .sort();
48
- return {
49
- kind: "completed",
50
- output: {
51
- name: skill.name,
52
- content: skillInstructions(text),
53
- ...(resources.length === 0 ? {} : { resources }),
54
- ...(sandboxed ? { sandboxPath: directory } : {}),
55
- },
56
- };
57
- }
58
- const path = typeof input.path === "string" ? input.path : "";
59
- if (skill.files[path] === undefined)
60
- return failed("skill.unknown_resource", `Skill '${skill.name}' has no resource '${path}'.`);
61
- const content = textOf(await read(path));
62
- if (content === undefined)
63
- return failed("skill.binary_resource", sandboxed
64
- ? `${path} is not a text file. It is in the sandbox at ${directory}${path}; use it there.`
65
- : `${path} is not a text file; only text files can be read without a sandbox.`);
66
- return { kind: "completed", output: { name: skill.name, path, content } };
67
- }
@@ -1,57 +0,0 @@
1
- import type { HostEffect } from "@nylorun/harness/run";
2
- import type { TenantContext } from "./context.js";
3
- /** The most of one tool result that is recorded inline (Q22): 32 KiB, as JSON. */
4
- export declare const TOOL_RESULT_INLINE_BYTES: number;
5
- /** How much of a stored result's start, and of its end, the preview keeps. */
6
- export declare const PREVIEW_HEAD_BYTES: number;
7
- export declare const PREVIEW_TAIL_BYTES = 1024;
8
- /**
9
- * The most one step's results may hold together: a step's results are one transcript entry, so
10
- * one event, which must stay well under S2's 1 MiB record.
11
- */
12
- export declare const STEP_RESULTS_BUDGET_BYTES: number;
13
- /** A result's cap once its step's budget is spent: a stub naming its artifact. */
14
- export declare const TOOL_RESULT_STUB_BYTES = 512;
15
- /** A result this small is never shaped, nor counted against its step's budget. */
16
- export declare const TOOL_RESULT_SMALL_BYTES = 1024;
17
- /** The call whose outcome is shaped, and the session its artifacts belong to. */
18
- export interface ShapedCall {
19
- readonly request: HostEffect;
20
- readonly session: {
21
- readonly id: string;
22
- readonly ownerUserId: string;
23
- };
24
- /** A remote MCP tool's: its output may be the server's content parts. */
25
- readonly mcp: boolean;
26
- /** This result's cap (`resultLimit`). Default `TOOL_RESULT_INLINE_BYTES`. */
27
- readonly limit?: number;
28
- }
29
- /** A result's cap when the other results of its step already took `used` bytes. */
30
- export declare function resultLimit(used: number): number;
31
- /** The JSON size of `value` in bytes: what it adds to an event or a prompt. */
32
- export declare function jsonBytes(value: unknown): number;
33
- /**
34
- * What a tool outcome's result weighs in its step's transcript entry: a completed one's output,
35
- * a failed one's message; 0 for anything else, such as a model call's outcome.
36
- */
37
- export declare function resultBytes(value: unknown): number;
38
- /**
39
- * False for an outcome `shapeToolOutcome` returns as it is, whatever made it: a model call's, a
40
- * small tool result with no parts. Spares a look at the effect for most outcomes.
41
- */
42
- export declare function mayNeedShaping(value: unknown): boolean;
43
- /**
44
- * The outcome `value` of `call`, shaped to fit its cap (see the module comment). An outcome that
45
- * fits and has no binary part comes back as it is.
46
- */
47
- export declare function shapeToolOutcome(ctx: TenantContext, call: ShapedCall, value: unknown, signal: AbortSignal): Promise<unknown>;
48
- /**
49
- * The start and end of `text` in whole characters, `budget` bytes split four to one: by default
50
- * the first `PREVIEW_HEAD_BYTES` and the last `PREVIEW_TAIL_BYTES`.
51
- */
52
- export declare function previewOf(text: string, budget?: number): string;
53
- /**
54
- * The nearest character boundary of the UTF-8 `bytes` at or before (`down`) or at or after
55
- * (`up`) byte `at`: never inside a character.
56
- */
57
- export declare function utf8Boundary(bytes: Uint8Array, at: number, direction: "down" | "up"): number;