@kaoruisaac/pedelec 0.2.11 → 0.2.12
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 +13 -11
- package/dist/index.d.ts +15 -15
- package/dist/index.js +18 -18
- package/dist/index.type-test.js +12 -8
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ A web application can use Pedelec to:
|
|
|
28
28
|
- send user instructions and receive streamed assistant text;
|
|
29
29
|
- expose narrowly scoped browser-side tools to the agent;
|
|
30
30
|
- resume or end sessions; and
|
|
31
|
-
- upload and list completed
|
|
31
|
+
- upload and list completed workspace assets; and
|
|
32
32
|
- show connection, approval, provider, and lifecycle state in the UI.
|
|
33
33
|
|
|
34
34
|
## Why Pedelec exists
|
|
@@ -146,7 +146,7 @@ const path = await session.uploadAsset(file);
|
|
|
146
146
|
const assets = await session.listAssets();
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
The physical shared App/Agent directory is `.pedelec-
|
|
149
|
+
The physical shared App/Agent directory is `.pedelec-runtime/assets/`. In the SDK contract, `assets/` is its implicit root: `listAssets()` recursively lists regular files at every level as a flat array, ordered by filesystem modification time (newest first) and then by name; nested paths such as `/results/report.json` are returned in full. Directory entries and symlinks are excluded, as are `.pedelec-*` entries at every level; other dotfiles are included. It 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.
|
|
150
150
|
|
|
151
151
|
```ts
|
|
152
152
|
const text = await session.readAsset("/report.txt", "text");
|
|
@@ -156,37 +156,39 @@ const result = await session.readAsset("/model.glb", "file");
|
|
|
156
156
|
|
|
157
157
|
Public asset paths use `/...` with `assets/` as their implicit root; nested paths such as `/results/model.glb` are supported up to 100 MiB.
|
|
158
158
|
|
|
159
|
-
##
|
|
159
|
+
## Workspace
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
Workspace is the filesystem root in which the Agent works. Pedelec stores its private runtime data under `<workspace>/.pedelec-runtime/`.
|
|
162
|
+
|
|
163
|
+
By default, each session receives a temporary Desktop-managed workspace. To use an application-owned workspace that can persist across sessions, pass an absolute path:
|
|
162
164
|
|
|
163
165
|
```ts
|
|
164
166
|
const session = await pedelec.createSession({
|
|
165
167
|
provider: "codex",
|
|
166
|
-
|
|
168
|
+
workspace: { path: "C:\\workspace\\project-a" },
|
|
167
169
|
});
|
|
168
170
|
```
|
|
169
171
|
|
|
170
|
-
Pedelec creates `.pedelec-
|
|
172
|
+
Pedelec creates `.pedelec-runtime/` with missing `assets/`, `logs/`, `skills/`, and `tmp/` subdirectories, preserving existing project files and existing private data. It never deletes an explicit workspace, and multiple active sessions may share it. Filesystem write conflicts are the application's responsibility. An explicit path must not overlap Pedelec's managed workspace root.
|
|
171
173
|
|
|
172
174
|
## Selecting an Application Workspace
|
|
173
175
|
|
|
174
|
-
Use `
|
|
176
|
+
Use `workspaceFolderPicker()` when the application wants the user to choose a local workspace before creating a session:
|
|
175
177
|
|
|
176
178
|
```ts
|
|
177
|
-
const folder = await pedelec.
|
|
179
|
+
const folder = await pedelec.workspaceFolderPicker();
|
|
178
180
|
if (!folder) return; // The user cancelled the native picker.
|
|
179
181
|
|
|
180
|
-
if (!folder.isEmptyFolder && !folder.
|
|
182
|
+
if (!folder.isEmptyFolder && !folder.hasWorkspaceConfig) {
|
|
181
183
|
// The application decides whether to warn the user.
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
const session = await pedelec.createSession({
|
|
185
|
-
|
|
187
|
+
workspace: { path: folder.path },
|
|
186
188
|
});
|
|
187
189
|
```
|
|
188
190
|
|
|
189
|
-
`
|
|
191
|
+
`workspaceFolderPicker()` returns `Promise<WorkspaceFolderPickerResult | null>`. It is a read-only snapshot: it does not validate or initialize the selected folder, create workspace directories, or create the workspace marker. `isEmptyFolder` only reports whether the selected folder root has any filesystem entry. `hasWorkspaceConfig` is true only when `.pedelec-workspace.json` exists as a regular file; its JSON is not parsed. The picker requires the same origin approval as other sensitive Desktop APIs, and cancellation returns `null`. `createSession()` still applies the full workspace rules and creates the marker after successful custom workspace initialization. The marker currently records the SDK version and normalized caller origin but does not restrict reuse by origin or SDK version.
|
|
190
192
|
|
|
191
193
|
---
|
|
192
194
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,11 @@ export type JsonPrimitive = string | number | boolean | null;
|
|
|
7
7
|
export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
8
8
|
[key: string]: JsonValue;
|
|
9
9
|
};
|
|
10
|
-
export type
|
|
10
|
+
export type AssetPath = `/${string}`;
|
|
11
11
|
export type ReadAssetType = "text" | "json" | "file";
|
|
12
|
-
export type
|
|
12
|
+
export type Asset = {
|
|
13
13
|
name: string;
|
|
14
|
-
path:
|
|
14
|
+
path: AssetPath;
|
|
15
15
|
sizeBytes: number;
|
|
16
16
|
modifiedAt: number;
|
|
17
17
|
};
|
|
@@ -83,26 +83,26 @@ export type SerializableSkillsManifest = {
|
|
|
83
83
|
guidance: string;
|
|
84
84
|
tools: SerializableToolManifest[];
|
|
85
85
|
};
|
|
86
|
-
export type
|
|
86
|
+
export type CreateSessionWorkspaceInput = {
|
|
87
87
|
path: string;
|
|
88
88
|
};
|
|
89
|
-
export interface
|
|
89
|
+
export interface WorkspaceFolderPickerResult {
|
|
90
90
|
path: string;
|
|
91
91
|
isEmptyFolder: boolean;
|
|
92
|
-
|
|
92
|
+
hasWorkspaceConfig: boolean;
|
|
93
93
|
}
|
|
94
94
|
type CreateSessionInputWithProvider<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = {
|
|
95
95
|
provider: ProviderCode;
|
|
96
96
|
effortLevel?: EffortLevel;
|
|
97
97
|
skills?: SkillsInput<TTools>;
|
|
98
|
-
|
|
98
|
+
workspace?: CreateSessionWorkspaceInput;
|
|
99
99
|
autoEndOnDisconnect?: boolean;
|
|
100
100
|
};
|
|
101
101
|
type CreateSessionInputWithDefaults<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = {
|
|
102
102
|
provider?: undefined;
|
|
103
103
|
effortLevel?: EffortLevel;
|
|
104
104
|
skills?: SkillsInput<TTools>;
|
|
105
|
-
|
|
105
|
+
workspace?: CreateSessionWorkspaceInput;
|
|
106
106
|
autoEndOnDisconnect?: boolean;
|
|
107
107
|
};
|
|
108
108
|
export type CreateSessionInput<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = CreateSessionInputWithProvider<TTools> | CreateSessionInputWithDefaults<TTools>;
|
|
@@ -238,7 +238,7 @@ export declare class Pedelec {
|
|
|
238
238
|
constructor(options?: PedelecOptions);
|
|
239
239
|
createSession(): Promise<PedelecSession<string>>;
|
|
240
240
|
createSession<const TTools extends readonly ToolDefinition[]>(input: CreateSessionInput<TTools>): Promise<PedelecSession<ToolNameOf<TTools>>>;
|
|
241
|
-
|
|
241
|
+
workspaceFolderPicker(): Promise<WorkspaceFolderPickerResult | null>;
|
|
242
242
|
listProviders(): Promise<ProviderInfo[]>;
|
|
243
243
|
getSettings(): Promise<PedelecSettings>;
|
|
244
244
|
getApprovalStatus(): Promise<ApprovalStatus>;
|
|
@@ -288,12 +288,12 @@ export declare class PedelecSession<TToolName extends string = string> {
|
|
|
288
288
|
onChat(handler: ChatHandler): () => void;
|
|
289
289
|
onTool(handler: GenericToolHandler<TToolName>): () => void;
|
|
290
290
|
onTool<TArgs = unknown, TResult = unknown>(toolName: TToolName, handler: ToolSpecificHandler<TArgs, TResult>): () => void;
|
|
291
|
-
uploadAsset(file: File): Promise<
|
|
292
|
-
uploadAsset(file: File, targetPath:
|
|
293
|
-
listAssets(): Promise<
|
|
294
|
-
readAsset(path:
|
|
295
|
-
readAsset<T = JsonValue>(path:
|
|
296
|
-
readAsset(path:
|
|
291
|
+
uploadAsset(file: File): Promise<AssetPath>;
|
|
292
|
+
uploadAsset(file: File, targetPath: AssetPath): Promise<AssetPath>;
|
|
293
|
+
listAssets(): Promise<Asset[]>;
|
|
294
|
+
readAsset(path: AssetPath, type: "text"): Promise<string>;
|
|
295
|
+
readAsset<T = JsonValue>(path: AssetPath, type: "json"): Promise<T>;
|
|
296
|
+
readAsset(path: AssetPath, type: "file"): Promise<File>;
|
|
297
297
|
onError(handler: ErrorHandler): () => void;
|
|
298
298
|
onStatus(handler: StatusHandler): () => void;
|
|
299
299
|
onEnded(handler: EndedHandler): () => void;
|
package/dist/index.js
CHANGED
|
@@ -141,7 +141,7 @@ export class Pedelec {
|
|
|
141
141
|
provider: resolvedInput.provider,
|
|
142
142
|
effortLevel: resolvedInput.effortLevel,
|
|
143
143
|
skills: resolvedInput.skills,
|
|
144
|
-
|
|
144
|
+
workspace: resolvedInput.workspace,
|
|
145
145
|
autoEndOnDisconnect: resolvedInput.autoEndOnDisconnect,
|
|
146
146
|
},
|
|
147
147
|
});
|
|
@@ -150,9 +150,9 @@ export class Pedelec {
|
|
|
150
150
|
}
|
|
151
151
|
return this.registerSession(result.sessionId, resolvedInput.provider, resolvedInput.effortLevel, resolvedInput.inlineToolHandlers);
|
|
152
152
|
}
|
|
153
|
-
async
|
|
154
|
-
const result = await this.requestWithOptions("
|
|
155
|
-
return
|
|
153
|
+
async workspaceFolderPicker() {
|
|
154
|
+
const result = await this.requestWithOptions("pick_workspace_folder", {}, { timeoutMs: null });
|
|
155
|
+
return normalizeWorkspaceFolderPickerResponse(result);
|
|
156
156
|
}
|
|
157
157
|
async listProviders() {
|
|
158
158
|
return normalizeProviderInfoList(await this.request("list_providers"));
|
|
@@ -258,15 +258,15 @@ export class Pedelec {
|
|
|
258
258
|
}
|
|
259
259
|
const autoEndOnDisconnect = raw.autoEndOnDisconnect !== false;
|
|
260
260
|
const normalizedSkills = normalizeSkillsInput(raw.skills);
|
|
261
|
-
const
|
|
261
|
+
const workspace = normalizeCreateSessionWorkspaceInput(raw.workspace);
|
|
262
262
|
if (!hasProvider) {
|
|
263
|
-
return this.resolveDefaultCreateSessionInput(effortLevel, normalizedSkills,
|
|
263
|
+
return this.resolveDefaultCreateSessionInput(effortLevel, normalizedSkills, workspace, autoEndOnDisconnect);
|
|
264
264
|
}
|
|
265
265
|
return {
|
|
266
266
|
provider: provider,
|
|
267
267
|
effortLevel,
|
|
268
268
|
skills: normalizedSkills.manifest,
|
|
269
|
-
|
|
269
|
+
workspace,
|
|
270
270
|
inlineToolHandlers: normalizedSkills.handlers,
|
|
271
271
|
autoEndOnDisconnect,
|
|
272
272
|
};
|
|
@@ -323,7 +323,7 @@ export class Pedelec {
|
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
-
async resolveDefaultCreateSessionInput(effortLevel, normalizedSkills,
|
|
326
|
+
async resolveDefaultCreateSessionInput(effortLevel, normalizedSkills, workspace, autoEndOnDisconnect) {
|
|
327
327
|
const settings = await this.getSettings();
|
|
328
328
|
if (!settings.defaultProvider) {
|
|
329
329
|
throw makeError("DEFAULT_PROVIDER_NOT_SET", "Default provider is not set. Open the Pedelec desktop app Settings page and choose a default provider.");
|
|
@@ -333,7 +333,7 @@ export class Pedelec {
|
|
|
333
333
|
provider: settings.defaultProvider,
|
|
334
334
|
effortLevel,
|
|
335
335
|
skills: normalizedSkills.manifest,
|
|
336
|
-
|
|
336
|
+
workspace,
|
|
337
337
|
inlineToolHandlers: normalizedSkills.handlers,
|
|
338
338
|
autoEndOnDisconnect,
|
|
339
339
|
};
|
|
@@ -462,18 +462,18 @@ export class Pedelec {
|
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
|
-
function
|
|
465
|
+
function normalizeCreateSessionWorkspaceInput(value) {
|
|
466
466
|
if (value === undefined)
|
|
467
467
|
return undefined;
|
|
468
468
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
469
|
-
throw makeError("INVALID_INPUT", "
|
|
469
|
+
throw makeError("INVALID_INPUT", "workspace must be an object");
|
|
470
470
|
}
|
|
471
471
|
const path = value.path;
|
|
472
472
|
if (typeof path !== "string") {
|
|
473
|
-
throw makeError("INVALID_INPUT", "
|
|
473
|
+
throw makeError("INVALID_INPUT", "workspace.path must be a string");
|
|
474
474
|
}
|
|
475
475
|
if (path.trim().length === 0) {
|
|
476
|
-
throw makeError("INVALID_INPUT", "
|
|
476
|
+
throw makeError("INVALID_INPUT", "workspace.path must not be empty");
|
|
477
477
|
}
|
|
478
478
|
return { path };
|
|
479
479
|
}
|
|
@@ -1033,21 +1033,21 @@ function normalizePedelecSettings(value) {
|
|
|
1033
1033
|
}
|
|
1034
1034
|
return { defaultProvider: value.defaultProvider };
|
|
1035
1035
|
}
|
|
1036
|
-
function
|
|
1036
|
+
function normalizeWorkspaceFolderPickerResponse(value) {
|
|
1037
1037
|
if (!isPlainObject(value) || !("path" in value)) {
|
|
1038
|
-
throw makeError("SDK_PROTOCOL_ERROR", "
|
|
1038
|
+
throw makeError("SDK_PROTOCOL_ERROR", "pick_workspace_folder response had an invalid shape");
|
|
1039
1039
|
}
|
|
1040
1040
|
const path = value.path;
|
|
1041
1041
|
if (path === null)
|
|
1042
1042
|
return null;
|
|
1043
1043
|
if (typeof path !== "string" || path.length === 0 ||
|
|
1044
|
-
typeof value.isEmptyFolder !== "boolean" || typeof value.
|
|
1045
|
-
throw makeError("SDK_PROTOCOL_ERROR", "
|
|
1044
|
+
typeof value.isEmptyFolder !== "boolean" || typeof value.hasWorkspaceConfig !== "boolean") {
|
|
1045
|
+
throw makeError("SDK_PROTOCOL_ERROR", "pick_workspace_folder response had an invalid shape");
|
|
1046
1046
|
}
|
|
1047
1047
|
return {
|
|
1048
1048
|
path,
|
|
1049
1049
|
isEmptyFolder: value.isEmptyFolder,
|
|
1050
|
-
|
|
1050
|
+
hasWorkspaceConfig: value.hasWorkspaceConfig,
|
|
1051
1051
|
};
|
|
1052
1052
|
}
|
|
1053
1053
|
function normalizeProviderInfoList(value) {
|
package/dist/index.type-test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Pedelec, defineTool, } from "./index";
|
|
2
|
-
function
|
|
2
|
+
function workspaceInputHasPublicType() {
|
|
3
3
|
return { path: "C:\\workspace\\project" };
|
|
4
4
|
}
|
|
5
5
|
async function typedOnToolNameFromCreateSession() {
|
|
@@ -84,10 +84,10 @@ async function noSkillsFallsBackToString() {
|
|
|
84
84
|
const pedelec = new Pedelec();
|
|
85
85
|
const session = await pedelec.createSession({
|
|
86
86
|
provider: "codex",
|
|
87
|
-
|
|
87
|
+
workspace: { path: "C:\\workspace\\project" },
|
|
88
88
|
});
|
|
89
|
-
const
|
|
90
|
-
void
|
|
89
|
+
const typedWorkspace = workspaceInputHasPublicType();
|
|
90
|
+
void typedWorkspace;
|
|
91
91
|
session.onTool((name) => {
|
|
92
92
|
const anyString = name;
|
|
93
93
|
return anyString;
|
|
@@ -100,6 +100,10 @@ async function effortLevelPublicTypeContract() {
|
|
|
100
100
|
const pedelec = new Pedelec();
|
|
101
101
|
await pedelec.createSession({ effortLevel: "high" });
|
|
102
102
|
const session = await pedelec.createSession({ provider: "codex", effortLevel: "low" });
|
|
103
|
+
// @ts-expect-error the removed sandbox input is not part of the public contract
|
|
104
|
+
pedelec.createSession({ provider: "codex", sandbox: { path: "C:\\workspace\\legacy" } });
|
|
105
|
+
// @ts-expect-error the removed sandbox picker is not part of the public contract
|
|
106
|
+
pedelec.sandboxFolderPicker();
|
|
103
107
|
// @ts-expect-error model is no longer a createSession option
|
|
104
108
|
pedelec.createSession({ provider: "codex", model: "gpt-5" });
|
|
105
109
|
// @ts-expect-error session no longer exposes provider model
|
|
@@ -136,14 +140,14 @@ async function availabilityHasPublicType() {
|
|
|
136
140
|
void availability;
|
|
137
141
|
void promise;
|
|
138
142
|
}
|
|
139
|
-
async function
|
|
143
|
+
async function workspaceFolderPickerHasPublicType() {
|
|
140
144
|
const pedelec = new Pedelec();
|
|
141
|
-
const result = pedelec.
|
|
145
|
+
const result = pedelec.workspaceFolderPicker();
|
|
142
146
|
void result;
|
|
143
147
|
}
|
|
144
148
|
function directoryPickerIsRemoved() {
|
|
145
149
|
const pedelec = new Pedelec();
|
|
146
|
-
// @ts-expect-error directoryPicker was removed in favor of
|
|
150
|
+
// @ts-expect-error directoryPicker was removed in favor of workspaceFolderPicker
|
|
147
151
|
pedelec.directoryPicker();
|
|
148
152
|
}
|
|
149
153
|
function publicSecurityTypesAreRestricted() {
|
|
@@ -164,7 +168,7 @@ void noSkillsFallsBackToString;
|
|
|
164
168
|
void effortLevelPublicTypeContract;
|
|
165
169
|
void listAssetsHasPublicTypes;
|
|
166
170
|
void availabilityHasPublicType;
|
|
167
|
-
void
|
|
171
|
+
void workspaceFolderPickerHasPublicType;
|
|
168
172
|
void directoryPickerIsRemoved;
|
|
169
173
|
void publicSecurityTypesAreRestricted;
|
|
170
174
|
const baseContext = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.2.
|
|
1
|
+
export declare const SDK_VERSION = "0.2.12";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from sdk/package.json. Do not edit manually.
|
|
2
|
-
export const SDK_VERSION = "0.2.
|
|
2
|
+
export const SDK_VERSION = "0.2.12";
|