@nylorun/agents 0.29.1-beta → 0.30.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 +16 -0
- package/dist/files.d.ts +15 -3
- package/dist/files.js +36 -4
- package/dist/http.js +7 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @nylorun/agents
|
|
2
2
|
|
|
3
|
+
## 0.30.0-beta
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2f3fc06: A skill file can be uploaded from a stream, so a client never holds a large one in memory (ADR-93).
|
|
8
|
+
|
|
9
|
+
- **`SkillFileSource.stream()`**, optional: each call opens a new stream of the file's bytes. When a source has it, `client.files.ensure` (and so `agentManifests.save`) sends the stream instead of `read()`'s bytes.
|
|
10
|
+
- **`client.files.uploadStream(stream, { sha256 })`** sends one file half-duplex, up to the Tenant's skill limit (2 GiB by default). The Runtime already streams the body to its hash.
|
|
11
|
+
- **A stream is never sent twice by the transport.** After an expired token or a protocol check, `ensure` opens a new stream and sends it once more.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Pin core to the tested release.
|
|
16
|
+
- Updated dependencies [2f3fc06]
|
|
17
|
+
- @nylorun/core@0.31.0-beta
|
|
18
|
+
|
|
3
19
|
## 0.29.1-beta
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/files.d.ts
CHANGED
|
@@ -17,14 +17,26 @@ export declare class FilesClient {
|
|
|
17
17
|
signal?: AbortSignal;
|
|
18
18
|
}): Promise<boolean>;
|
|
19
19
|
/**
|
|
20
|
-
* Uploads one file, at most 2 GiB. The Runtime checks its
|
|
21
|
-
* their hash) and keeps a file it already holds as it is.
|
|
20
|
+
* Uploads one file, at most the Tenant's skill limit (2 GiB by default). The Runtime checks its
|
|
21
|
+
* bytes hash to `sha256` (default: their hash) and keeps a file it already holds as it is.
|
|
22
22
|
*/
|
|
23
23
|
upload(bytes: Uint8Array, options?: {
|
|
24
24
|
sha256?: string;
|
|
25
25
|
signal?: AbortSignal;
|
|
26
26
|
}): Promise<DefinitionFileView>;
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Uploads one file from a stream, so a large file never sits in memory (ADR-93). `sha256` is
|
|
29
|
+
* required: the bytes aren't read before they are sent. The Runtime refuses a body with another
|
|
30
|
+
* hash and stores nothing.
|
|
31
|
+
*/
|
|
32
|
+
uploadStream(stream: ReadableStream<Uint8Array>, options: {
|
|
33
|
+
sha256: string;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}): Promise<DefinitionFileView>;
|
|
36
|
+
/**
|
|
37
|
+
* Uploads each of `files` the Runtime does not hold yet: from its `stream()` when the source has
|
|
38
|
+
* one, else from `read()`.
|
|
39
|
+
*/
|
|
28
40
|
ensure(files: ReadonlyMap<string, SkillFileSource>, options?: {
|
|
29
41
|
signal?: AbortSignal;
|
|
30
42
|
}): Promise<void>;
|
package/dist/files.js
CHANGED
|
@@ -37,8 +37,8 @@ export class FilesClient {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Uploads one file, at most 2 GiB. The Runtime checks its
|
|
41
|
-
* their hash) and keeps a file it already holds as it is.
|
|
40
|
+
* Uploads one file, at most the Tenant's skill limit (2 GiB by default). The Runtime checks its
|
|
41
|
+
* bytes hash to `sha256` (default: their hash) and keeps a file it already holds as it is.
|
|
42
42
|
*/
|
|
43
43
|
async upload(bytes, options = {}) {
|
|
44
44
|
const response = await this.transport.request(pathOf(options.sha256 ?? (await definitionFileHash(bytes))), {
|
|
@@ -49,12 +49,44 @@ export class FilesClient {
|
|
|
49
49
|
});
|
|
50
50
|
return (await response.json());
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Uploads one file from a stream, so a large file never sits in memory (ADR-93). `sha256` is
|
|
54
|
+
* required: the bytes aren't read before they are sent. The Runtime refuses a body with another
|
|
55
|
+
* hash and stores nothing.
|
|
56
|
+
*/
|
|
57
|
+
async uploadStream(stream, options) {
|
|
58
|
+
const response = await this.transport.request(pathOf(options.sha256), {
|
|
59
|
+
method: "PUT",
|
|
60
|
+
body: stream,
|
|
61
|
+
headers: { "content-type": "application/octet-stream" },
|
|
62
|
+
// Node's fetch sends a stream body only half-duplex.
|
|
63
|
+
duplex: "half",
|
|
64
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
65
|
+
});
|
|
66
|
+
return (await response.json());
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Uploads each of `files` the Runtime does not hold yet: from its `stream()` when the source has
|
|
70
|
+
* one, else from `read()`.
|
|
71
|
+
*/
|
|
53
72
|
async ensure(files, options = {}) {
|
|
54
73
|
for (const [sha256, source] of files) {
|
|
55
74
|
if (await this.has(sha256, options))
|
|
56
75
|
continue;
|
|
57
|
-
|
|
76
|
+
if (!source.stream) {
|
|
77
|
+
await this.upload(await source.read(), { sha256, ...options });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
await this.uploadStream(source.stream(), { sha256, ...options });
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
// The transport doesn't resend a stream: once more with a new one after an expired token
|
|
85
|
+
// or a protocol check, which the transport has handled for the next request.
|
|
86
|
+
if (!(error instanceof RuntimeError) || (error.status !== 401 && error.status !== 426))
|
|
87
|
+
throw error;
|
|
88
|
+
await this.uploadStream(source.stream(), { sha256, ...options });
|
|
89
|
+
}
|
|
58
90
|
}
|
|
59
91
|
}
|
|
60
92
|
}
|
package/dist/http.js
CHANGED
|
@@ -138,18 +138,22 @@ export class Transport {
|
|
|
138
138
|
headers: await this.authHeaders(init),
|
|
139
139
|
redirect: "error",
|
|
140
140
|
});
|
|
141
|
+
// A stream body can't be sent twice: its caller sends a new one (FilesClient.ensure).
|
|
142
|
+
const resendable = !(typeof ReadableStream !== "undefined" && init.body instanceof ReadableStream);
|
|
141
143
|
// An expired token: get a new one and try once more.
|
|
142
144
|
if (response.status === 401 && this.token && !options.retried401) {
|
|
143
145
|
const body = (await response.clone().json().catch(() => undefined));
|
|
144
146
|
if (body?.code === "token_expired") {
|
|
145
|
-
await response.body?.cancel().catch(() => { });
|
|
146
147
|
this.token.invalidate();
|
|
147
|
-
|
|
148
|
+
if (resendable) {
|
|
149
|
+
await response.body?.cancel().catch(() => { });
|
|
150
|
+
return this.request(path, init, { ...options, retried401: true });
|
|
151
|
+
}
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
if (response.status === 426) {
|
|
151
155
|
this.clearCompatibilityCache();
|
|
152
|
-
if (!options.retried426) {
|
|
156
|
+
if (!options.retried426 && resendable) {
|
|
153
157
|
await this.ensureCompatible(init.signal === null ? undefined : init.signal);
|
|
154
158
|
return this.request(path, init, { retried426: true });
|
|
155
159
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0-beta",
|
|
4
4
|
"description": "Nylorun agent definitions and session client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test": "vitest run --passWithNoTests"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@nylorun/core": "0.
|
|
46
|
+
"@nylorun/core": "0.31.0-beta",
|
|
47
47
|
"gray-matter": "^4.0.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|