@nylorun/runtime 0.45.0-beta → 0.46.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 +30 -0
- package/dist/api/a2a/tasks.d.ts +2 -1
- package/dist/api/a2a/tasks.js +5 -1
- package/dist/api/components.d.ts +17 -0
- package/dist/artifacts/disk.js +1 -0
- package/dist/artifacts/folders.js +1 -0
- package/dist/artifacts/service.d.ts +3 -1
- package/dist/artifacts/service.js +3 -0
- package/dist/harness-api/artifacts.js +1 -0
- package/dist/management-openapi.json +1 -1
- package/dist/openapi.json +37 -1
- package/dist/sandbox/pods/lifecycle.d.ts +2 -0
- package/dist/sandbox/pods/lifecycle.js +9 -1
- package/dist/sandbox/tools.d.ts +5 -0
- package/dist/sandbox/tools.js +17 -0
- package/dist/store/postgres/drizzle/0046_artifacts_audience.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +7 -0
- package/dist/store/postgres/reads.js +2 -0
- package/dist/store/postgres/schema.d.ts +17 -0
- package/dist/store/postgres/schema.js +5 -0
- package/dist/store/postgres/store.js +2 -1
- package/dist/tenant/triggers.d.ts +6 -1
- package/dist/tenant/triggers.js +21 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.46.0-beta
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b6a7c1d: An agent sees the images and PDFs it makes in its sandbox (ADR-139). `read` of a file the turn's model reads as media, known by its extension (an image, a PDF, an Office document, audio or video), comes back as the file itself, shown to the model in the turn's files, instead of numbered lines of decoded bytes. Our engine runs it in the harness: it reads the bytes, checks they start as the type says, and stores them as an artifact for the model only. A model that can't read the kind is told so before anything is read or stored (`sandbox.unreadable`), and a file that isn't what its name says fails `sandbox.binary_file`.
|
|
8
|
+
|
|
9
|
+
- **Model-only artifacts.** `artifact.write` `begin` takes `audience: "model"` (Harness API 5, schema revision 5, `harness-api/v5.5.json`; only our own engine sends it). Such an artifact is readable by id and carries `audience: "model"` in its view and its `artifact.created` event, but is never listed (`GET /v1/artifacts`, a session's artifacts, pages) and is no A2A task file. Runtime store migration 0046 (`artifacts.audience`, nullable) runs at start.
|
|
10
|
+
- **Binary files.** The sandbox's `read` of any other binary file fails `sandbox.binary_file`, in words, instead of answering decoded bytes as text.
|
|
11
|
+
- **A cap per call.** A model call carries at most the 6 newest files from tool results as media; older ones in the same turn go as a note naming them, which `read_artifact` brings back. A person's own files are never capped.
|
|
12
|
+
- `read`'s description says what it now does, so the prompt prefix of every agent with a sandbox changes once: its first call after the upgrade misses the prompt cache.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- b6a7c1d: Trigger runs fired in the same millisecond now list in the order they fired: run ids a Runtime makes strictly increase, instead of breaking a same-millisecond tie on their random part.
|
|
17
|
+
- 522e6d7: A pod Agent's idle period now runs from when its pod became ready, not from when it was asked to start. A slow start, such as a cold node pulling the image, no longer uses up the idle period: on the Agent Substrate exit test, a pod that took 56 s to start was suspended as idle 3.6 s after it could first take a turn. Becoming ready moves the pod's last activity to that moment, which the idle timer, the idle decision and the Tenant's sweep all read.
|
|
18
|
+
- f1ac19f: Pods on Agent Substrate (preview): a wake no longer waits on a DNS lookup of the edge. The sandboxes service pins the edge's name to the address `enable` found in each actor's `/etc/hosts` (when the image lets the engine's user write it), so a restored actor's first lookup, which can be lost, is never made; the exit test's rerun measured 1.15–1.51 s in four of ten wakes from that lookup's retry. `nylorun local sandbox enable --backend substrate` also tries the pod's lookup of the Docker host three times before refusing the context, since a pod's first lookup can find no address on a cluster that just started.
|
|
19
|
+
- Pin core to the tested release.
|
|
20
|
+
- Pin harness to the tested release.
|
|
21
|
+
- Updated dependencies [b6a7c1d]
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @nylorun/core@0.40.0-beta
|
|
24
|
+
- @nylorun/harness@0.36.0-beta
|
|
25
|
+
|
|
26
|
+
## 0.45.1-beta
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 40820b8: Pods on Agent Substrate (preview): `nylorun local sandbox enable --backend substrate` no longer fails at the Tenant's atespace (`access_policy.metadata.atespace: Forbidden: must not be set`), and a pod that ran before wakes again instead of failing every later apply with `name: Required value`. The sandboxes service now writes the atespace's access policy without an atespace, as Substrate v1.0 requires of a global-scoped policy, and names the actor's egress policy (`default`) when it reads it back.
|
|
31
|
+
- 1740a16: Pods on Agent Substrate (preview): a pod's first start on a node that lacks its image no longer fails. The sandboxes service tries a resume that times out or finds Substrate busy again, every 5 s for up to 10 minutes while the pod should still be running; before, the first resume gave up after 2 minutes during a long image pull and the actor stayed RESUMING. Actors also get `RES_OPTIONS=timeout:1 attempts:3`, so a wake whose first DNS lookup of the edge is lost waits about 1 s instead of 5 s (an Agent's own `RES_OPTIONS` wins).
|
|
32
|
+
|
|
3
33
|
## 0.45.0-beta
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/dist/api/a2a/tasks.d.ts
CHANGED
|
@@ -84,7 +84,8 @@ export declare function telemetryOf(payload: unknown, traceId: string | undefine
|
|
|
84
84
|
export declare function fileUrl(baseUrl: string | undefined, artifactId: string, version: number): string;
|
|
85
85
|
/**
|
|
86
86
|
* The A2A artifact of a file the turn wrote (`artifact.created`, `artifact.version.created`), with
|
|
87
|
-
* `files/v1`, or undefined for the caller's own uploads
|
|
87
|
+
* `files/v1`, or undefined for the caller's own uploads and for a file stored only for the model
|
|
88
|
+
* (ADR-139). A folder is served as its zip.
|
|
88
89
|
*/
|
|
89
90
|
export declare function fileArtifact(payload: unknown, baseUrl: string | undefined): Artifact | undefined;
|
|
90
91
|
/**
|
package/dist/api/a2a/tasks.js
CHANGED
|
@@ -246,13 +246,17 @@ export function fileUrl(baseUrl, artifactId, version) {
|
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
248
|
* The A2A artifact of a file the turn wrote (`artifact.created`, `artifact.version.created`), with
|
|
249
|
-
* `files/v1`, or undefined for the caller's own uploads
|
|
249
|
+
* `files/v1`, or undefined for the caller's own uploads and for a file stored only for the model
|
|
250
|
+
* (ADR-139). A folder is served as its zip.
|
|
250
251
|
*/
|
|
251
252
|
export function fileArtifact(payload, baseUrl) {
|
|
252
253
|
if (!isRecord(payload) || typeof payload.artifactId !== "string" || typeof payload.name !== "string")
|
|
253
254
|
return undefined;
|
|
254
255
|
if (payload.source === "upload")
|
|
255
256
|
return undefined;
|
|
257
|
+
// A file stored only for the model to see (ADR-139) is no output of the task.
|
|
258
|
+
if (payload.audience === "model")
|
|
259
|
+
return undefined;
|
|
256
260
|
const version = Number(payload.version);
|
|
257
261
|
const folder = payload.kind === "folder";
|
|
258
262
|
return {
|
package/dist/api/components.d.ts
CHANGED
|
@@ -1805,6 +1805,7 @@ export declare const ArtifactView: z.ZodObject<{
|
|
|
1805
1805
|
agentId: z.ZodOptional<z.ZodString>;
|
|
1806
1806
|
latestVersion: z.ZodNumber;
|
|
1807
1807
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1808
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
1808
1809
|
createdAt: z.ZodString;
|
|
1809
1810
|
updatedAt: z.ZodString;
|
|
1810
1811
|
versions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1833,6 +1834,7 @@ export declare const ArtifactListItem: z.ZodObject<{
|
|
|
1833
1834
|
agentId: z.ZodOptional<z.ZodString>;
|
|
1834
1835
|
latestVersion: z.ZodNumber;
|
|
1835
1836
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1837
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
1836
1838
|
createdAt: z.ZodString;
|
|
1837
1839
|
updatedAt: z.ZodString;
|
|
1838
1840
|
}, z.core.$strict>;
|
|
@@ -1850,6 +1852,7 @@ export declare const ArtifactPage: z.ZodObject<{
|
|
|
1850
1852
|
agentId: z.ZodOptional<z.ZodString>;
|
|
1851
1853
|
latestVersion: z.ZodNumber;
|
|
1852
1854
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1855
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
1853
1856
|
createdAt: z.ZodString;
|
|
1854
1857
|
updatedAt: z.ZodString;
|
|
1855
1858
|
}, z.core.$strict>>;
|
|
@@ -1867,6 +1870,7 @@ export declare const ListArtifactsResponse: z.ZodObject<{
|
|
|
1867
1870
|
agentId: z.ZodOptional<z.ZodString>;
|
|
1868
1871
|
latestVersion: z.ZodNumber;
|
|
1869
1872
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1873
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
1870
1874
|
createdAt: z.ZodString;
|
|
1871
1875
|
updatedAt: z.ZodString;
|
|
1872
1876
|
versions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1897,6 +1901,7 @@ export declare const UploadArtifactResponse: z.ZodObject<{
|
|
|
1897
1901
|
agentId: z.ZodOptional<z.ZodString>;
|
|
1898
1902
|
latestVersion: z.ZodNumber;
|
|
1899
1903
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1904
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
1900
1905
|
createdAt: z.ZodString;
|
|
1901
1906
|
updatedAt: z.ZodString;
|
|
1902
1907
|
versions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -2844,6 +2849,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
2844
2849
|
snapshot: "snapshot";
|
|
2845
2850
|
upload: "upload";
|
|
2846
2851
|
}>;
|
|
2852
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
2847
2853
|
callId: z.ZodOptional<z.ZodString>;
|
|
2848
2854
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
2849
2855
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -3154,6 +3160,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
3154
3160
|
snapshot: "snapshot";
|
|
3155
3161
|
upload: "upload";
|
|
3156
3162
|
}>;
|
|
3163
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
3157
3164
|
callId: z.ZodOptional<z.ZodString>;
|
|
3158
3165
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
3159
3166
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -6075,6 +6082,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
6075
6082
|
snapshot: "snapshot";
|
|
6076
6083
|
upload: "upload";
|
|
6077
6084
|
}>;
|
|
6085
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
6078
6086
|
callId: z.ZodOptional<z.ZodString>;
|
|
6079
6087
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
6080
6088
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -6385,6 +6393,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
6385
6393
|
snapshot: "snapshot";
|
|
6386
6394
|
upload: "upload";
|
|
6387
6395
|
}>;
|
|
6396
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
6388
6397
|
callId: z.ZodOptional<z.ZodString>;
|
|
6389
6398
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
6390
6399
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -9309,6 +9318,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
9309
9318
|
snapshot: "snapshot";
|
|
9310
9319
|
upload: "upload";
|
|
9311
9320
|
}>;
|
|
9321
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
9312
9322
|
callId: z.ZodOptional<z.ZodString>;
|
|
9313
9323
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
9314
9324
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -9619,6 +9629,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
9619
9629
|
snapshot: "snapshot";
|
|
9620
9630
|
upload: "upload";
|
|
9621
9631
|
}>;
|
|
9632
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
9622
9633
|
callId: z.ZodOptional<z.ZodString>;
|
|
9623
9634
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
9624
9635
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -12540,6 +12551,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
12540
12551
|
snapshot: "snapshot";
|
|
12541
12552
|
upload: "upload";
|
|
12542
12553
|
}>;
|
|
12554
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
12543
12555
|
callId: z.ZodOptional<z.ZodString>;
|
|
12544
12556
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
12545
12557
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -12850,6 +12862,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
12850
12862
|
snapshot: "snapshot";
|
|
12851
12863
|
upload: "upload";
|
|
12852
12864
|
}>;
|
|
12865
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
12853
12866
|
callId: z.ZodOptional<z.ZodString>;
|
|
12854
12867
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
12855
12868
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -16694,6 +16707,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
16694
16707
|
snapshot: "snapshot";
|
|
16695
16708
|
upload: "upload";
|
|
16696
16709
|
}>;
|
|
16710
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
16697
16711
|
callId: z.ZodOptional<z.ZodString>;
|
|
16698
16712
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
16699
16713
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -17004,6 +17018,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
17004
17018
|
snapshot: "snapshot";
|
|
17005
17019
|
upload: "upload";
|
|
17006
17020
|
}>;
|
|
17021
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
17007
17022
|
callId: z.ZodOptional<z.ZodString>;
|
|
17008
17023
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
17009
17024
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -19925,6 +19940,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
19925
19940
|
snapshot: "snapshot";
|
|
19926
19941
|
upload: "upload";
|
|
19927
19942
|
}>;
|
|
19943
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
19928
19944
|
callId: z.ZodOptional<z.ZodString>;
|
|
19929
19945
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
19930
19946
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -20235,6 +20251,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
20235
20251
|
snapshot: "snapshot";
|
|
20236
20252
|
upload: "upload";
|
|
20237
20253
|
}>;
|
|
20254
|
+
audience: z.ZodOptional<z.ZodLiteral<"model">>;
|
|
20238
20255
|
callId: z.ZodOptional<z.ZodString>;
|
|
20239
20256
|
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
20240
20257
|
claimed: z.ZodOptional<z.ZodBoolean>;
|
package/dist/artifacts/disk.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ArtifactSource, ArtifactVersionView, ArtifactView, FolderManifest } from "@nylorun/core/contracts";
|
|
1
|
+
import type { ArtifactAudience, ArtifactSource, ArtifactVersionView, ArtifactView, FolderManifest } from "@nylorun/core/contracts";
|
|
2
2
|
import { type BlobBody } from "../blob/index.js";
|
|
3
3
|
import type { ArtifactRow, ArtifactVersionRow, Tx } from "../store/types.js";
|
|
4
4
|
import { type SessionAccess, type TenantContext } from "../tenant/context.js";
|
|
@@ -18,6 +18,8 @@ export interface UploadInput {
|
|
|
18
18
|
/** The body's declared length (`Content-Length`): one past the limits is refused unread. */
|
|
19
19
|
readonly declaredBytes?: number;
|
|
20
20
|
readonly source: ArtifactSource;
|
|
21
|
+
/** `model`: a new artifact stored only for the model to see (ADR-139). */
|
|
22
|
+
readonly audience?: ArtifactAudience;
|
|
21
23
|
/** The turn that saved it (a harness's `artifact.write`), for the event. */
|
|
22
24
|
readonly turnId?: string | null;
|
|
23
25
|
/** The tool call that saved it, for the event. */
|
|
@@ -85,6 +85,7 @@ export function artifactView(row, versions) {
|
|
|
85
85
|
...(row.environmentId === null ? {} : { agentId: row.environmentId }),
|
|
86
86
|
latestVersion: row.latestVersion,
|
|
87
87
|
...(row.labelsJson === null ? {} : { labels: JSON.parse(row.labelsJson) }),
|
|
88
|
+
...(row.audience === null ? {} : { audience: row.audience }),
|
|
88
89
|
createdAt: row.createdAt,
|
|
89
90
|
updatedAt: row.updatedAt,
|
|
90
91
|
...(versions === undefined ? {} : { versions: versions.map(versionView) }),
|
|
@@ -236,6 +237,7 @@ export async function uploadArtifact(ctx, input, body, access, signal) {
|
|
|
236
237
|
createdAt,
|
|
237
238
|
updatedAt: createdAt,
|
|
238
239
|
environmentId: null,
|
|
240
|
+
audience: input.audience ?? null,
|
|
239
241
|
};
|
|
240
242
|
version = {
|
|
241
243
|
artifactId,
|
|
@@ -260,6 +262,7 @@ export async function uploadArtifact(ctx, input, body, access, signal) {
|
|
|
260
262
|
size: version.size,
|
|
261
263
|
sha256: version.sha256,
|
|
262
264
|
source: version.source,
|
|
265
|
+
...(row.audience === null ? {} : { audience: row.audience }),
|
|
263
266
|
...(input.callId === undefined ? {} : { callId: input.callId }),
|
|
264
267
|
});
|
|
265
268
|
return { artifact: artifactView(row), version: versionView(version), created: true };
|
|
@@ -202,6 +202,7 @@ export function createArtifactSeam(ctx) {
|
|
|
202
202
|
...(contentType === undefined ? {} : { contentType }),
|
|
203
203
|
sessionId,
|
|
204
204
|
source: "engine",
|
|
205
|
+
...(params.audience === undefined || params.artifactId !== undefined ? {} : { audience: params.audience }),
|
|
205
206
|
turnId: scope.turnId,
|
|
206
207
|
...(begun.callId === undefined ? {} : { callId: begun.callId }),
|
|
207
208
|
writeKey,
|
package/dist/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.2.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Nylorun Runtime API",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.46.0-beta",
|
|
6
6
|
"x-nylorun-protocol": {
|
|
7
7
|
"min": 16,
|
|
8
8
|
"max": 18,
|
|
@@ -17563,6 +17563,12 @@
|
|
|
17563
17563
|
"snapshot"
|
|
17564
17564
|
]
|
|
17565
17565
|
},
|
|
17566
|
+
"audience": {
|
|
17567
|
+
"type": "string",
|
|
17568
|
+
"enum": [
|
|
17569
|
+
"model"
|
|
17570
|
+
]
|
|
17571
|
+
},
|
|
17566
17572
|
"callId": {
|
|
17567
17573
|
"type": "string"
|
|
17568
17574
|
},
|
|
@@ -17805,6 +17811,12 @@
|
|
|
17805
17811
|
"snapshot"
|
|
17806
17812
|
]
|
|
17807
17813
|
},
|
|
17814
|
+
"audience": {
|
|
17815
|
+
"type": "string",
|
|
17816
|
+
"enum": [
|
|
17817
|
+
"model"
|
|
17818
|
+
]
|
|
17819
|
+
},
|
|
17808
17820
|
"callId": {
|
|
17809
17821
|
"type": "string"
|
|
17810
17822
|
},
|
|
@@ -25717,6 +25729,12 @@
|
|
|
25717
25729
|
"type": "string"
|
|
25718
25730
|
}
|
|
25719
25731
|
},
|
|
25732
|
+
"audience": {
|
|
25733
|
+
"type": "string",
|
|
25734
|
+
"enum": [
|
|
25735
|
+
"model"
|
|
25736
|
+
]
|
|
25737
|
+
},
|
|
25720
25738
|
"createdAt": {
|
|
25721
25739
|
"type": "string"
|
|
25722
25740
|
},
|
|
@@ -25868,6 +25886,12 @@
|
|
|
25868
25886
|
"type": "string"
|
|
25869
25887
|
}
|
|
25870
25888
|
},
|
|
25889
|
+
"audience": {
|
|
25890
|
+
"type": "string",
|
|
25891
|
+
"enum": [
|
|
25892
|
+
"model"
|
|
25893
|
+
]
|
|
25894
|
+
},
|
|
25871
25895
|
"createdAt": {
|
|
25872
25896
|
"type": "string"
|
|
25873
25897
|
},
|
|
@@ -25995,6 +26019,12 @@
|
|
|
25995
26019
|
"type": "string"
|
|
25996
26020
|
}
|
|
25997
26021
|
},
|
|
26022
|
+
"audience": {
|
|
26023
|
+
"type": "string",
|
|
26024
|
+
"enum": [
|
|
26025
|
+
"model"
|
|
26026
|
+
]
|
|
26027
|
+
},
|
|
25998
26028
|
"createdAt": {
|
|
25999
26029
|
"type": "string"
|
|
26000
26030
|
},
|
|
@@ -26049,6 +26079,12 @@
|
|
|
26049
26079
|
"type": "string"
|
|
26050
26080
|
}
|
|
26051
26081
|
},
|
|
26082
|
+
"audience": {
|
|
26083
|
+
"type": "string",
|
|
26084
|
+
"enum": [
|
|
26085
|
+
"model"
|
|
26086
|
+
]
|
|
26087
|
+
},
|
|
26052
26088
|
"createdAt": {
|
|
26053
26089
|
"type": "string"
|
|
26054
26090
|
},
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* reconciled, whichever path woke it: a turn's end arms it too, but a wake with no turn end
|
|
20
20
|
* (a disk copy's `wakePod`, commands through the session's sandbox route) armed nothing and
|
|
21
21
|
* ran on for days. A timer that fires during a turn looks again one idle period later.
|
|
22
|
+
* Becoming ready moves `lastActiveAt` to that moment, so a slow start doesn't use up the
|
|
23
|
+
* idle period before the pod can take a turn.
|
|
22
24
|
* - **Lost**: an incarnation that has run (a pod joined) whose Sandbox is gone or whose volume
|
|
23
25
|
* is missing is `lost` (`agent.lost`): its host epoch moves, its Sandbox is deleted, and
|
|
24
26
|
* only a reset brings the Environment back. agent-sandbox recreates a deleted claim empty, so
|
|
@@ -171,9 +171,17 @@ export function decide(facts) {
|
|
|
171
171
|
if (pod.observed === "failed" && pod.reason?.startsWith(SETUP_FAILED))
|
|
172
172
|
return done();
|
|
173
173
|
if (status.ready) {
|
|
174
|
+
// Becoming ready counts as activity: the idle period runs from when the pod could first take
|
|
175
|
+
// a turn, so a slow start (a cold node's image pull) doesn't use it up (P1.8 rerun: a 56 s
|
|
176
|
+
// start was suspended as idle 3.6 s after it ran).
|
|
177
|
+
let lastActive = Date.parse(pod.lastActiveAt ?? row.createdAt);
|
|
174
178
|
if (pod.observed !== "running") {
|
|
175
179
|
patch.observed = "running";
|
|
176
180
|
patch.reason = null;
|
|
181
|
+
if (now > lastActive) {
|
|
182
|
+
patch.lastActiveAt = new Date(now).toISOString();
|
|
183
|
+
lastActive = now;
|
|
184
|
+
}
|
|
177
185
|
}
|
|
178
186
|
// The image it runs, pinned by digest from now on (Q14).
|
|
179
187
|
const digest = pod.imageDigest === undefined ? imageDigestOf(status.imageID, facts.image) : undefined;
|
|
@@ -181,7 +189,7 @@ export function decide(facts) {
|
|
|
181
189
|
patch.imageDigest = digest;
|
|
182
190
|
// Whatever woke it, a running pod has an idle timer (the idle trigger armed its own above).
|
|
183
191
|
if (facts.trigger !== "idle")
|
|
184
|
-
arm.push({ timer: "idle", at:
|
|
192
|
+
arm.push({ timer: "idle", at: lastActive + facts.config.idleMs });
|
|
185
193
|
return done();
|
|
186
194
|
}
|
|
187
195
|
const startedAt = Date.parse(pod.startedAt ?? row.updatedAt);
|
package/dist/sandbox/tools.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface SandboxToolReport {
|
|
|
15
15
|
* mounting a skill, a tool's own helper command): `harness.helperCommandTimeoutMs`.
|
|
16
16
|
*/
|
|
17
17
|
export declare const helperCommandTimeoutMs: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Whether decoded file content is binary: a NUL among its first 8000 characters, or a run of
|
|
20
|
+
* replacement characters where invalid UTF-8 was (more than 1 in 10). Text never has NULs.
|
|
21
|
+
*/
|
|
22
|
+
export declare function looksBinary(content: string): boolean;
|
|
18
23
|
export declare function quote(value: string): string;
|
|
19
24
|
/**
|
|
20
25
|
* An absolute path inside the sandbox. Relative paths are relative to the workspace; on a backend
|
package/dist/sandbox/tools.js
CHANGED
|
@@ -13,6 +13,20 @@ import { hostTuning } from "../tuning.js";
|
|
|
13
13
|
* mounting a skill, a tool's own helper command): `harness.helperCommandTimeoutMs`.
|
|
14
14
|
*/
|
|
15
15
|
export const helperCommandTimeoutMs = () => hostTuning().harness.helperCommandTimeoutMs;
|
|
16
|
+
/**
|
|
17
|
+
* Whether decoded file content is binary: a NUL among its first 8000 characters, or a run of
|
|
18
|
+
* replacement characters where invalid UTF-8 was (more than 1 in 10). Text never has NULs.
|
|
19
|
+
*/
|
|
20
|
+
export function looksBinary(content) {
|
|
21
|
+
const head = content.slice(0, 8000);
|
|
22
|
+
if (head.includes("\u0000"))
|
|
23
|
+
return true;
|
|
24
|
+
let replaced = 0;
|
|
25
|
+
for (const char of head)
|
|
26
|
+
if (char === "\ufffd")
|
|
27
|
+
replaced += 1;
|
|
28
|
+
return head.length > 0 && replaced / head.length > 0.1;
|
|
29
|
+
}
|
|
16
30
|
export function quote(value) {
|
|
17
31
|
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
18
32
|
}
|
|
@@ -75,6 +89,9 @@ environment) {
|
|
|
75
89
|
const content = await handle.readFile(path);
|
|
76
90
|
if (content === undefined)
|
|
77
91
|
return failed("sandbox.not_found", `No file at ${path}`);
|
|
92
|
+
// A binary file decodes to garbage the model can't tell from text (ADR-139): say so instead.
|
|
93
|
+
if (looksBinary(content))
|
|
94
|
+
return failed("sandbox.binary_file", `${path} is a binary file, not text. read shows text files, and images, PDFs and other files your model reads by their extension; use bash to inspect this one.`);
|
|
78
95
|
const lines = content.split("\n");
|
|
79
96
|
if (lines.at(-1) === "")
|
|
80
97
|
lines.pop();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "nylorun"."artifacts" ADD COLUMN "audience" text;
|
|
@@ -323,6 +323,13 @@
|
|
|
323
323
|
"when": 1793954783377,
|
|
324
324
|
"tag": "0045_session_queue_delivery",
|
|
325
325
|
"breakpoints": true
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"idx": 46,
|
|
329
|
+
"version": "7",
|
|
330
|
+
"when": 1794240246972,
|
|
331
|
+
"tag": "0046_artifacts_audience",
|
|
332
|
+
"breakpoints": true
|
|
326
333
|
}
|
|
327
334
|
]
|
|
328
335
|
}
|
|
@@ -179,6 +179,8 @@ export function createPostgresReadStore(source, tenantId) {
|
|
|
179
179
|
.where(and(eq(sessions.id, artifacts.sessionId), accessWhere(access)))), filters.sessionId === undefined
|
|
180
180
|
? undefined
|
|
181
181
|
: eq(artifacts.sessionId, filters.sessionId), filters.kind === undefined ? undefined : eq(artifacts.kind, filters.kind),
|
|
182
|
+
// A file stored only for the model (ADR-139) is never listed.
|
|
183
|
+
isNull(artifacts.audience),
|
|
182
184
|
// Labels are a flat string map serialized by JSON.stringify. Match its exact
|
|
183
185
|
// key/value pair: jsonb rejects NUL/unpaired surrogate escapes labels may hold.
|
|
184
186
|
...Object.entries(filters.labels).map(([k, v]) => sql `strpos(${artifacts.labelsJson}, ${JSON.stringify(k) + ":" + JSON.stringify(v)}) > 0`), key ? sql `(${artifacts.createdAt}, ${artifacts.id}) < (${key[0]}, ${key[1]})` : undefined))
|
|
@@ -4995,6 +4995,23 @@ export declare const artifacts: import("drizzle-orm/pg-core").PgTableWithColumns
|
|
|
4995
4995
|
}, {}, {
|
|
4996
4996
|
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
4997
4997
|
}>;
|
|
4998
|
+
audience: import("drizzle-orm/pg-core").PgColumn<{
|
|
4999
|
+
name: "audience";
|
|
5000
|
+
tableName: "artifacts";
|
|
5001
|
+
dataType: "string";
|
|
5002
|
+
columnType: "PgText";
|
|
5003
|
+
data: "model";
|
|
5004
|
+
driverParam: string;
|
|
5005
|
+
notNull: false;
|
|
5006
|
+
hasDefault: false;
|
|
5007
|
+
isPrimaryKey: false;
|
|
5008
|
+
isAutoincrement: false;
|
|
5009
|
+
hasRuntimeDefault: false;
|
|
5010
|
+
enumValues: ["model"];
|
|
5011
|
+
baseColumn: never;
|
|
5012
|
+
identity: undefined;
|
|
5013
|
+
generated: undefined;
|
|
5014
|
+
}, {}, {}>;
|
|
4998
5015
|
};
|
|
4999
5016
|
dialect: 'pg';
|
|
5000
5017
|
}>;
|
|
@@ -626,6 +626,11 @@ export const artifacts = nylorun.table("artifacts", {
|
|
|
626
626
|
updatedAt: text().notNull(),
|
|
627
627
|
/** The Agent whose disk versions this folder holds (R2d step 3); one per Agent. */
|
|
628
628
|
environmentId: textC(),
|
|
629
|
+
/**
|
|
630
|
+
* `model`: our engine stored it only for its model to see (ADR-139); null for an output.
|
|
631
|
+
* Such an artifact is readable by id and never listed.
|
|
632
|
+
*/
|
|
633
|
+
audience: text({ enum: ["model"] }),
|
|
629
634
|
}, (t) => [
|
|
630
635
|
index("artifacts_session").on(t.sessionId, t.createdAt, t.id),
|
|
631
636
|
uniqueIndex("artifacts_environment_disk").on(t.environmentId).where(sql `environment_id IS NOT NULL`),
|
|
@@ -1581,7 +1581,8 @@ class PostgresTx {
|
|
|
1581
1581
|
return this.db
|
|
1582
1582
|
.select()
|
|
1583
1583
|
.from(artifacts)
|
|
1584
|
-
|
|
1584
|
+
// A file stored only for the model (ADR-139) is never listed.
|
|
1585
|
+
.where(and(isNull(artifacts.audience), filter.sessionId === undefined ? undefined : eq(artifacts.sessionId, filter.sessionId)))
|
|
1585
1586
|
.orderBy(artifacts.createdAt, artifacts.id);
|
|
1586
1587
|
}
|
|
1587
1588
|
async insertArtifact(row, version) {
|
|
@@ -8,7 +8,12 @@ export declare const triggerTimerKey: (agentId: string, triggerId: string) => st
|
|
|
8
8
|
export declare const newEndpointId: () => string;
|
|
9
9
|
/** A webhook endpoint's path, under the Runtime API's origin. */
|
|
10
10
|
export declare const webhookPath: (endpointId: string) => string;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* A new run id: its time in ms then a random 64-bit suffix, so runs list newest first by id. Ids
|
|
13
|
+
* this process makes strictly increase: one in the same ms as the last (or with the clock moved
|
|
14
|
+
* back) keeps the last's time and adds one to its suffix, so two runs fired back to back never
|
|
15
|
+
* list in the wrong order.
|
|
16
|
+
*/
|
|
12
17
|
export declare function newRunId(now?: number): string;
|
|
13
18
|
/** A schedule's cron in its time zone (UTC by default); throws on a bad pattern or zone. */
|
|
14
19
|
export declare function cronOf(trigger: Pick<Trigger, "schedule" | "timezone">): Cron;
|
package/dist/tenant/triggers.js
CHANGED
|
@@ -59,9 +59,28 @@ function parseTimerKey(key) {
|
|
|
59
59
|
export const newEndpointId = () => `wh_${randomBytes(16).toString("hex")}`;
|
|
60
60
|
/** A webhook endpoint's path, under the Runtime API's origin. */
|
|
61
61
|
export const webhookPath = (endpointId) => `/v1/webhooks/${endpointId}`;
|
|
62
|
-
/**
|
|
62
|
+
/** The last run id this process made: its time and 64-bit suffix, for `newRunId`'s tie-break. */
|
|
63
|
+
let lastRunId;
|
|
64
|
+
const SUFFIX_MAX = (1n << 64n) - 1n;
|
|
65
|
+
/**
|
|
66
|
+
* A new run id: its time in ms then a random 64-bit suffix, so runs list newest first by id. Ids
|
|
67
|
+
* this process makes strictly increase: one in the same ms as the last (or with the clock moved
|
|
68
|
+
* back) keeps the last's time and adds one to its suffix, so two runs fired back to back never
|
|
69
|
+
* list in the wrong order.
|
|
70
|
+
*/
|
|
63
71
|
export function newRunId(now = Date.now()) {
|
|
64
|
-
|
|
72
|
+
let ms = now;
|
|
73
|
+
let suffix = BigInt(`0x${randomBytes(8).toString("hex")}`);
|
|
74
|
+
if (lastRunId && ms <= lastRunId.ms) {
|
|
75
|
+
ms = lastRunId.ms;
|
|
76
|
+
suffix = lastRunId.suffix + 1n;
|
|
77
|
+
if (suffix > SUFFIX_MAX) {
|
|
78
|
+
ms += 1;
|
|
79
|
+
suffix = 0n;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
lastRunId = { ms, suffix };
|
|
83
|
+
return `run_${ms.toString(36).padStart(9, "0")}${suffix.toString(16).padStart(16, "0")}`;
|
|
65
84
|
}
|
|
66
85
|
/** A schedule's cron in its time zone (UTC by default); throws on a bad pattern or zone. */
|
|
67
86
|
export function cronOf(trigger) {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const RUNTIME_VERSION = "0.
|
|
1
|
+
export declare const RUNTIME_VERSION = "0.46.0-beta";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Kept in step with package.json by runtime/server/scripts/check-package.mjs, which runs in npm run check.
|
|
2
2
|
// release:prepare also rewrites this when it bumps @nylorun/runtime.
|
|
3
|
-
export const RUNTIME_VERSION = "0.
|
|
3
|
+
export const RUNTIME_VERSION = "0.46.0-beta";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0-beta",
|
|
4
4
|
"description": "Nylorun Runtime: the agent execution Host on Postgres, Restate and S2, and model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"@hono/node-server": "^2.1.5",
|
|
66
66
|
"@hono/zod-openapi": "^1.6.3",
|
|
67
67
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
68
|
-
"@nylorun/core": "0.
|
|
69
|
-
"@nylorun/harness": "0.
|
|
68
|
+
"@nylorun/core": "0.40.0-beta",
|
|
69
|
+
"@nylorun/harness": "0.36.0-beta",
|
|
70
70
|
"@restatedev/restate-sdk": "1.17.3",
|
|
71
71
|
"@restatedev/restate-sdk-clients": "1.17.3",
|
|
72
72
|
"@s2-dev/streamstore": "0.28.0",
|