@kaoruisaac/pedelec 0.1.17 → 0.1.18
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/README.md +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +9 -4
- package/dist/index.type-test.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -138,12 +138,12 @@ const assets = await session.listAssets();
|
|
|
138
138
|
`assets/` is shared by uploads and files written by the agent. `listAssets()` lists only its first level, ordered by filesystem modification time (newest first), and may run while the agent runs. One session can only upload one file at a time, but uploads can run alongside prepare or agent execution.
|
|
139
139
|
|
|
140
140
|
```ts
|
|
141
|
-
const text = await session.readAsset("
|
|
142
|
-
const json = await session.readAsset<{ ok: boolean }>("
|
|
143
|
-
const result = await session.readAsset("
|
|
141
|
+
const text = await session.readAsset("/report.txt", "text");
|
|
142
|
+
const json = await session.readAsset<{ ok: boolean }>("/result.json", "json");
|
|
143
|
+
const result = await session.readAsset("/model.glb", "file");
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
Public asset paths use `/...` with `assets/` as their implicit root; nested paths such as `/results/model.glb` are supported up to 100 MiB.
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type JsonPrimitive = string | number | boolean | null;
|
|
|
6
6
|
export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
7
7
|
[key: string]: JsonValue;
|
|
8
8
|
};
|
|
9
|
-
export type SandboxAssetPath =
|
|
9
|
+
export type SandboxAssetPath = `/${string}`;
|
|
10
10
|
export type ReadAssetType = "text" | "json" | "file";
|
|
11
11
|
export type SandboxAsset = {
|
|
12
12
|
name: string;
|
|
@@ -276,6 +276,7 @@ export declare class PedelecSession<TToolName extends string = string> {
|
|
|
276
276
|
onTool(handler: GenericToolHandler<TToolName>): () => void;
|
|
277
277
|
onTool<TArgs = unknown, TResult = unknown>(toolName: TToolName, handler: ToolSpecificHandler<TArgs, TResult>): () => void;
|
|
278
278
|
uploadAsset(file: File): Promise<SandboxAssetPath>;
|
|
279
|
+
uploadAsset(file: File, targetPath: SandboxAssetPath): Promise<SandboxAssetPath>;
|
|
279
280
|
listAssets(): Promise<SandboxAsset[]>;
|
|
280
281
|
readAsset(path: SandboxAssetPath, type: "text"): Promise<string>;
|
|
281
282
|
readAsset<T = JsonValue>(path: SandboxAssetPath, type: "json"): Promise<T>;
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ function normalizeListAssetsResponse(response) {
|
|
|
12
12
|
return invalidListAssetsResponse({ index, asset });
|
|
13
13
|
const { name, path, sizeBytes, modifiedAt } = asset;
|
|
14
14
|
const validName = typeof name === "string" && name.length > 0 && name !== "." && name !== ".." && !name.includes("/") && !name.includes("\\");
|
|
15
|
-
const validPath = typeof path === "string" &&
|
|
15
|
+
const validPath = typeof path === "string" && path === `/${name}` && isValidAssetPath(path);
|
|
16
16
|
const validNumber = (value) => typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= 0;
|
|
17
17
|
if (!validName || !validPath || !validNumber(sizeBytes) || !validNumber(modifiedAt)) {
|
|
18
18
|
return invalidListAssetsResponse({ index, asset });
|
|
@@ -24,8 +24,8 @@ function invalidListAssetsResponse(details) {
|
|
|
24
24
|
throw makeError("SDK_PROTOCOL_ERROR", "list_assets response had an invalid shape", { response: details });
|
|
25
25
|
}
|
|
26
26
|
function isValidAssetPath(path) {
|
|
27
|
-
return typeof path === "string" &&
|
|
28
|
-
path.split("/").every((part, index) => index === 0 || (part
|
|
27
|
+
return typeof path === "string" && /^\/(?:[^/\\\x00-\x1f]+)(?:\/[^/\\\x00-\x1f]+)*$/.test(path) &&
|
|
28
|
+
path.split("/").every((part, index) => index === 0 || (part !== "." && part !== ".."));
|
|
29
29
|
}
|
|
30
30
|
const MAX_ASSET_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
31
31
|
const TOOL_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_.-]*$/;
|
|
@@ -559,7 +559,7 @@ export class PedelecSession {
|
|
|
559
559
|
}
|
|
560
560
|
};
|
|
561
561
|
}
|
|
562
|
-
uploadAsset(file) {
|
|
562
|
+
uploadAsset(file, targetPath) {
|
|
563
563
|
if (this.ending || this.status === "ended")
|
|
564
564
|
return Promise.reject(makeError("SESSION_ENDED", "session has ended", { sessionId: this.sessionId }));
|
|
565
565
|
if (this.uploadPromise) {
|
|
@@ -570,8 +570,11 @@ export class PedelecSession {
|
|
|
570
570
|
}
|
|
571
571
|
if (file.size > MAX_ASSET_UPLOAD_BYTES)
|
|
572
572
|
return Promise.reject(makeError("ASSET_TOO_LARGE", "asset exceeds the 100 MiB limit"));
|
|
573
|
+
if (targetPath !== undefined && !isValidAssetPath(targetPath))
|
|
574
|
+
return Promise.reject(makeError("ASSET_PATH_INVALID", "asset target path is invalid"));
|
|
573
575
|
this.uploadPromise = this.client.request("create_asset_upload", {
|
|
574
576
|
sessionId: this.sessionId, filename: file.name, sizeBytes: file.size, mimeType: file.type,
|
|
577
|
+
...(targetPath === undefined ? {} : { targetPath }),
|
|
575
578
|
}).then(async (ticket) => {
|
|
576
579
|
if (!ticket?.uploadUrl || !ticket.token)
|
|
577
580
|
throw makeError("SDK_PROTOCOL_ERROR", "asset upload ticket was invalid");
|
|
@@ -591,6 +594,8 @@ export class PedelecSession {
|
|
|
591
594
|
throw normalizeError(payload?.error, "ASSET_UPLOAD_FAILED", "asset upload failed");
|
|
592
595
|
if (!isValidAssetPath(payload?.path))
|
|
593
596
|
throw makeError("SDK_PROTOCOL_ERROR", "asset upload response had an invalid path");
|
|
597
|
+
if (targetPath !== undefined && payload.path !== targetPath)
|
|
598
|
+
throw makeError("SDK_PROTOCOL_ERROR", "asset upload response path did not match target path");
|
|
594
599
|
return payload.path;
|
|
595
600
|
}).finally(() => { this.uploadPromise = null; });
|
|
596
601
|
return this.uploadPromise;
|
package/dist/index.type-test.js
CHANGED
|
@@ -96,6 +96,20 @@ async function listAssetsHasPublicTypes() {
|
|
|
96
96
|
const path = assets[0].path;
|
|
97
97
|
path;
|
|
98
98
|
}
|
|
99
|
+
async function assetPathsUseAssetsAsAnImplicitRoot() {
|
|
100
|
+
const pedelec = new Pedelec();
|
|
101
|
+
const session = await pedelec.resumeSession("thread_1");
|
|
102
|
+
const file = new File(["asset"], "original.txt", { type: "text/plain" });
|
|
103
|
+
const generated = await session.uploadAsset(file);
|
|
104
|
+
generated;
|
|
105
|
+
const exact = await session.uploadAsset(file, "/img/image.txt");
|
|
106
|
+
exact;
|
|
107
|
+
const namedAssetsDirectory = "/assets/image.txt";
|
|
108
|
+
void namedAssetsDirectory;
|
|
109
|
+
// @ts-expect-error asset paths must begin with a slash
|
|
110
|
+
const missingSlash = "assets/image.txt";
|
|
111
|
+
void missingSlash;
|
|
112
|
+
}
|
|
99
113
|
async function availabilityHasPublicType() {
|
|
100
114
|
const pedelec = new Pedelec();
|
|
101
115
|
const availability = await pedelec.checkAvailability();
|