@kaoruisaac/pedelec 0.4.2 → 0.4.4
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 +15 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.js +68 -0
- package/dist/index.type-test.js +12 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/vite.js +26 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -233,6 +233,20 @@ const result = await session.readAsset("/model.glb", "file");
|
|
|
233
233
|
|
|
234
234
|
Public asset paths use `/...` with `assets/` as their implicit root; nested paths such as `/results/model.glb` are supported up to 100 MiB.
|
|
235
235
|
|
|
236
|
+
### Provider-generated assets
|
|
237
|
+
|
|
238
|
+
When a supported provider generates an image or file, Pedelec imports it under `.pedelec-runtime/assets/provider-artifacts/` before notifying the application. `onArtifact()` receives metadata only; binary bytes and provider-private absolute paths are not included in the event. The public `artifact.path` works immediately with `readAsset()` and the same file is included by `listAssets()`.
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
const offArtifact = session.onArtifact(async (artifact) => {
|
|
242
|
+
if (artifact.kind !== "image") return;
|
|
243
|
+
const file = await session.readAsset(artifact.path, "file");
|
|
244
|
+
renderImage(file);
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Use `listAssets()` to discover files from earlier turns; registering an artifact handler does not replay history. Provider artifacts follow the existing per-file 100 MiB asset limit. Availability depends on the selected provider emitting a supported generated artifact, so not every provider or model can generate every artifact kind.
|
|
249
|
+
|
|
236
250
|
## Workspace
|
|
237
251
|
|
|
238
252
|
Workspace is the filesystem root in which the Agent works. Pedelec stores its private runtime data under `<workspace>/.pedelec-runtime/`. There are two supported flows:
|
|
@@ -290,7 +304,7 @@ The default timeout is 60 seconds; `timeoutMs` must be a positive integer. The r
|
|
|
290
304
|
|
|
291
305
|
`workspace.run()` has read and write access to the Workspace, but no network, host environment, subprocess execution, FFI, or `sys` permission. The existing no-remote, cached-only, and no-npm runtime restrictions still apply. This is a direct deterministic capability for an approved Web application to read and modify the opened Workspace; it is not unrestricted host code execution and is not mediated by an Agent.
|
|
292
306
|
|
|
293
|
-
|
|
307
|
+
Multiple Sessions, Agent/provider operations, and `workspace.run()` executions may operate concurrently in the same Workspace. A second turn on the same Session is still rejected while that Session is busy. Pedelec does not provide filesystem-level locking, snapshots, transactions, or conflict resolution between concurrent Workspace actors. Applications are responsible for coordinating shared file access when required.
|
|
294
308
|
|
|
295
309
|
Session `skills.denoModules` belong to the Session/Thread that declares them and are available only to Agent-side `pedelec-deno` execution for that Thread. Workspace runs accept the same Vite-prepared declarations explicitly:
|
|
296
310
|
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,21 @@ export type Asset = {
|
|
|
16
16
|
sizeBytes: number;
|
|
17
17
|
modifiedAt: number;
|
|
18
18
|
};
|
|
19
|
+
export type ProviderArtifactKind = "image" | "audio" | "video" | "file";
|
|
20
|
+
export type ProviderArtifactSource = "image_generation" | "tool_result" | "provider_artifact";
|
|
21
|
+
/** Metadata for a provider-generated file already materialized in Workspace assets. */
|
|
22
|
+
export type ProviderArtifact = {
|
|
23
|
+
id: string;
|
|
24
|
+
provider: ProviderCode;
|
|
25
|
+
path: AssetPath;
|
|
26
|
+
name: string;
|
|
27
|
+
mimeType: string;
|
|
28
|
+
sizeBytes: number;
|
|
29
|
+
kind: ProviderArtifactKind;
|
|
30
|
+
source: ProviderArtifactSource;
|
|
31
|
+
providerArtifactId?: string;
|
|
32
|
+
toolCallId?: string;
|
|
33
|
+
};
|
|
19
34
|
export type DenoModuleDefinition<TName extends string = string> = {
|
|
20
35
|
name: TName;
|
|
21
36
|
description?: string;
|
|
@@ -197,6 +212,14 @@ export type ChatDeltaEventContext = PedelecEventContext & {
|
|
|
197
212
|
turnStartedAt: number;
|
|
198
213
|
eventReceivedAt: number;
|
|
199
214
|
};
|
|
215
|
+
export type ProviderArtifactEventContext = PedelecEventContext & {
|
|
216
|
+
type: "provider_artifact";
|
|
217
|
+
turnId: string;
|
|
218
|
+
turnStartedAt: number;
|
|
219
|
+
turnKind: "user";
|
|
220
|
+
eventReceivedAt: number;
|
|
221
|
+
source: "core";
|
|
222
|
+
};
|
|
200
223
|
export type ToolCallContext = PedelecEventContext & {
|
|
201
224
|
type: "tool_call";
|
|
202
225
|
toolRequestId: string;
|
|
@@ -230,6 +253,13 @@ type SessionEvent = {
|
|
|
230
253
|
seq?: number;
|
|
231
254
|
operationId?: string;
|
|
232
255
|
text: string;
|
|
256
|
+
} | {
|
|
257
|
+
type: "provider_artifact";
|
|
258
|
+
channelId: string;
|
|
259
|
+
sessionId: string;
|
|
260
|
+
seq?: number;
|
|
261
|
+
operationId: string;
|
|
262
|
+
artifact: unknown;
|
|
233
263
|
} | {
|
|
234
264
|
type: "status_changed";
|
|
235
265
|
channelId: string;
|
|
@@ -309,6 +339,7 @@ type EventDispatchMeta = {
|
|
|
309
339
|
};
|
|
310
340
|
type ChatHandler = (text: string, ctx: ChatEventContext) => void;
|
|
311
341
|
type ChatDeltaHandler = (text: string, ctx: ChatDeltaEventContext) => void;
|
|
342
|
+
export type ProviderArtifactHandler = (artifact: ProviderArtifact, ctx: ProviderArtifactEventContext) => void;
|
|
312
343
|
type GenericToolHandler<TToolName extends string = string> = (tool: TToolName, args: unknown, ctx: ToolCallContext) => unknown | Promise<unknown>;
|
|
313
344
|
type ErrorHandler = (error: PedelecError, ctx: ErrorEventContext) => void;
|
|
314
345
|
type StatusHandler = (status: PedelecSessionStatus, ctx: StatusEventContext) => void;
|
|
@@ -418,6 +449,7 @@ export declare class PedelecSession<TToolName extends string = string> {
|
|
|
418
449
|
private readonly namedToolHandlers;
|
|
419
450
|
private readonly chatHandlers;
|
|
420
451
|
private readonly chatDeltaHandlers;
|
|
452
|
+
private readonly artifactHandlers;
|
|
421
453
|
private readonly errorHandlers;
|
|
422
454
|
private readonly statusHandlers;
|
|
423
455
|
private readonly endedHandlers;
|
|
@@ -429,6 +461,7 @@ export declare class PedelecSession<TToolName extends string = string> {
|
|
|
429
461
|
sendText(text: string): Promise<void>;
|
|
430
462
|
onChat(handler: ChatHandler): () => void;
|
|
431
463
|
onChatDelta(handler: ChatDeltaHandler): () => void;
|
|
464
|
+
onArtifact(handler: ProviderArtifactHandler): () => void;
|
|
432
465
|
onTool(handler: GenericToolHandler<TToolName>): () => void;
|
|
433
466
|
onTool<TArgs = unknown, TResult = unknown>(toolName: TToolName, handler: ToolSpecificHandler<TArgs, TResult>): () => void;
|
|
434
467
|
uploadAsset(file: File): Promise<AssetPath>;
|
|
@@ -475,6 +508,7 @@ export declare class PedelecSession<TToolName extends string = string> {
|
|
|
475
508
|
private createBaseContext;
|
|
476
509
|
private createChatContext;
|
|
477
510
|
private createChatDeltaContext;
|
|
511
|
+
private createProviderArtifactContext;
|
|
478
512
|
private createToolCallContext;
|
|
479
513
|
private createStatusContext;
|
|
480
514
|
private createErrorContext;
|
package/dist/index.js
CHANGED
|
@@ -955,6 +955,7 @@ export class PedelecSession {
|
|
|
955
955
|
namedToolHandlers = new Map();
|
|
956
956
|
chatHandlers = new Set();
|
|
957
957
|
chatDeltaHandlers = new Set();
|
|
958
|
+
artifactHandlers = new Set();
|
|
958
959
|
errorHandlers = new Set();
|
|
959
960
|
statusHandlers = new Set();
|
|
960
961
|
endedHandlers = new Set();
|
|
@@ -1072,6 +1073,10 @@ export class PedelecSession {
|
|
|
1072
1073
|
this.chatDeltaHandlers.add(handler);
|
|
1073
1074
|
return () => this.chatDeltaHandlers.delete(handler);
|
|
1074
1075
|
}
|
|
1076
|
+
onArtifact(handler) {
|
|
1077
|
+
this.artifactHandlers.add(handler);
|
|
1078
|
+
return () => this.artifactHandlers.delete(handler);
|
|
1079
|
+
}
|
|
1075
1080
|
onTool(toolNameOrHandler, maybeHandler) {
|
|
1076
1081
|
if (typeof toolNameOrHandler === "string") {
|
|
1077
1082
|
const toolName = toolNameOrHandler;
|
|
@@ -1307,6 +1312,26 @@ export class PedelecSession {
|
|
|
1307
1312
|
}
|
|
1308
1313
|
return;
|
|
1309
1314
|
}
|
|
1315
|
+
if (event.type === "provider_artifact") {
|
|
1316
|
+
let artifact;
|
|
1317
|
+
try {
|
|
1318
|
+
artifact = normalizeProviderArtifact(event.artifact);
|
|
1319
|
+
}
|
|
1320
|
+
catch (error) {
|
|
1321
|
+
this.emitError(normalizeError(error, "SDK_PROTOCOL_ERROR", "provider_artifact event had an invalid payload"), {
|
|
1322
|
+
source: "sdk",
|
|
1323
|
+
eventReceivedAt: meta.eventReceivedAt,
|
|
1324
|
+
});
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const turn = this.requireOperationTurn(event.operationId, "provider_artifact", meta);
|
|
1328
|
+
if (!turn || turn.kind === "prepare")
|
|
1329
|
+
return;
|
|
1330
|
+
for (const handler of this.artifactHandlers) {
|
|
1331
|
+
handler(artifact, this.createProviderArtifactContext(meta, turn));
|
|
1332
|
+
}
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1310
1335
|
if (event.type === "status_changed") {
|
|
1311
1336
|
if (event.operationId && !this.matchesActiveOperation(event.operationId))
|
|
1312
1337
|
return;
|
|
@@ -1690,6 +1715,17 @@ export class PedelecSession {
|
|
|
1690
1715
|
source: "core",
|
|
1691
1716
|
};
|
|
1692
1717
|
}
|
|
1718
|
+
createProviderArtifactContext(meta, turn) {
|
|
1719
|
+
return {
|
|
1720
|
+
...this.createBaseContext(meta, turn),
|
|
1721
|
+
type: "provider_artifact",
|
|
1722
|
+
turnId: turn.turnId,
|
|
1723
|
+
turnStartedAt: turn.turnStartedAt,
|
|
1724
|
+
turnKind: "user",
|
|
1725
|
+
eventReceivedAt: meta.eventReceivedAt ?? Date.now(),
|
|
1726
|
+
source: "core",
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1693
1729
|
createToolCallContext(event, meta, turn) {
|
|
1694
1730
|
return {
|
|
1695
1731
|
...this.createBaseContext(meta, turn),
|
|
@@ -1726,6 +1762,7 @@ export class PedelecSession {
|
|
|
1726
1762
|
function isSessionEvent(message) {
|
|
1727
1763
|
return (message.type === "chat_delta" ||
|
|
1728
1764
|
message.type === "chat_message" ||
|
|
1765
|
+
message.type === "provider_artifact" ||
|
|
1729
1766
|
message.type === "status_changed" ||
|
|
1730
1767
|
message.type === "tool_call" ||
|
|
1731
1768
|
message.type === "operation_completed" ||
|
|
@@ -1746,6 +1783,37 @@ function isEffort(value) {
|
|
|
1746
1783
|
function isPlainObject(value) {
|
|
1747
1784
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1748
1785
|
}
|
|
1786
|
+
function normalizeProviderArtifact(value) {
|
|
1787
|
+
if (!isPlainObject(value)) {
|
|
1788
|
+
throw makeError("SDK_PROTOCOL_ERROR", "provider_artifact event had an invalid artifact object");
|
|
1789
|
+
}
|
|
1790
|
+
const { id, provider, path, name, mimeType, sizeBytes, kind, source } = value;
|
|
1791
|
+
const optionalIdIsValid = (key) => !(key in value) || (typeof value[key] === "string" && value[key].trim().length > 0);
|
|
1792
|
+
const validName = typeof name === "string" && name.trim().length > 0 &&
|
|
1793
|
+
!name.includes("/") && !name.includes("\\") && name !== "." && name !== "..";
|
|
1794
|
+
const validPath = isValidAssetPath(path) && path.slice(path.lastIndexOf("/") + 1) === name;
|
|
1795
|
+
const validSize = typeof sizeBytes === "number" && Number.isFinite(sizeBytes) &&
|
|
1796
|
+
Number.isInteger(sizeBytes) && sizeBytes >= 0;
|
|
1797
|
+
const validKind = kind === "image" || kind === "audio" || kind === "video" || kind === "file";
|
|
1798
|
+
const validSource = source === "image_generation" || source === "tool_result" || source === "provider_artifact";
|
|
1799
|
+
if (typeof id !== "string" || id.trim().length === 0 || !isProviderCode(provider) || !validPath ||
|
|
1800
|
+
!validName || typeof mimeType !== "string" || mimeType.trim().length === 0 || !validSize ||
|
|
1801
|
+
!validKind || !validSource || !optionalIdIsValid("providerArtifactId") || !optionalIdIsValid("toolCallId")) {
|
|
1802
|
+
throw makeError("SDK_PROTOCOL_ERROR", "provider_artifact event had an invalid artifact payload");
|
|
1803
|
+
}
|
|
1804
|
+
return {
|
|
1805
|
+
id,
|
|
1806
|
+
provider,
|
|
1807
|
+
path,
|
|
1808
|
+
name,
|
|
1809
|
+
mimeType,
|
|
1810
|
+
sizeBytes,
|
|
1811
|
+
kind,
|
|
1812
|
+
source,
|
|
1813
|
+
...(value.providerArtifactId === undefined ? {} : { providerArtifactId: value.providerArtifactId }),
|
|
1814
|
+
...(value.toolCallId === undefined ? {} : { toolCallId: value.toolCallId }),
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1749
1817
|
function normalizePedelecSettings(value) {
|
|
1750
1818
|
if (!isPlainObject(value) || (value.defaultProvider !== null && !isProviderCode(value.defaultProvider))) {
|
|
1751
1819
|
throw makeError("SDK_PROTOCOL_ERROR", "get_settings response had invalid shape");
|
package/dist/index.type-test.js
CHANGED
|
@@ -92,6 +92,18 @@ async function typedOnToolNameFromCreateSession() {
|
|
|
92
92
|
void deltaType;
|
|
93
93
|
void chatDeltaCtx;
|
|
94
94
|
});
|
|
95
|
+
session.onArtifact((artifact, ctx) => {
|
|
96
|
+
const publicArtifact = artifact;
|
|
97
|
+
const artifactContext = ctx;
|
|
98
|
+
const turnKind = ctx.turnKind;
|
|
99
|
+
const origin = ctx.source;
|
|
100
|
+
const file = session.readAsset(artifact.path, "file");
|
|
101
|
+
void publicArtifact;
|
|
102
|
+
void artifactContext;
|
|
103
|
+
void turnKind;
|
|
104
|
+
void origin;
|
|
105
|
+
void file;
|
|
106
|
+
});
|
|
95
107
|
session.onStatus((_status, ctx) => {
|
|
96
108
|
const statusCtx = ctx;
|
|
97
109
|
const previous = ctx.previousStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.4.
|
|
1
|
+
export declare const SDK_VERSION = "0.4.4";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from sdk/package.json. Do not edit manually.
|
|
2
|
-
export const SDK_VERSION = "0.4.
|
|
2
|
+
export const SDK_VERSION = "0.4.4";
|
package/dist/vite.js
CHANGED
|
@@ -12,6 +12,7 @@ const DECLARATION_LIKE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs
|
|
|
12
12
|
const LEGACY_NODE_BUILTIN_MODULES = new Set(builtinModules.filter((specifier) => !specifier.startsWith("node:")));
|
|
13
13
|
const NODE_BUILTIN_MODULES = new Set(builtinModules.map((specifier) => specifier.replace(/^node:/, "")));
|
|
14
14
|
const nodeRequire = createRequire(import.meta.url);
|
|
15
|
+
const ssrResolvers = new WeakMap();
|
|
15
16
|
/**
|
|
16
17
|
* Vite build-time support for the static Deno module authoring API.
|
|
17
18
|
*
|
|
@@ -85,7 +86,7 @@ export function pedelecVitePlugin() {
|
|
|
85
86
|
};
|
|
86
87
|
}
|
|
87
88
|
async function prepareDeclaration(declaration, importer, resolveModule, config) {
|
|
88
|
-
const entry = await resolveEntry(declaration, importer, resolveModule);
|
|
89
|
+
const entry = await resolveEntry(declaration, importer, resolveModule, config);
|
|
89
90
|
const diagnosticPrefix = `Deno module "${declaration.name}" entry "${declaration.entry}" imported by "${importer}"`;
|
|
90
91
|
let runtimeBundle;
|
|
91
92
|
try {
|
|
@@ -119,13 +120,13 @@ async function prepareDeclaration(declaration, importer, resolveModule, config)
|
|
|
119
120
|
dependencies: new Set([...dependencies].map(normalizeFile)),
|
|
120
121
|
};
|
|
121
122
|
}
|
|
122
|
-
async function resolveEntry(declaration, importer, resolveModule) {
|
|
123
|
+
async function resolveEntry(declaration, importer, resolveModule, config) {
|
|
123
124
|
if (isRemoteOrSchemeEntry(declaration.entry)) {
|
|
124
125
|
throw new Error(`Deno module "${declaration.name}" entry "${declaration.entry}" is not a local or package specifier; remote and scheme URLs are not supported`);
|
|
125
126
|
}
|
|
126
127
|
let result;
|
|
127
128
|
try {
|
|
128
|
-
result = await resolveHostModule(declaration.entry, importer, resolveModule);
|
|
129
|
+
result = await resolveHostModule(declaration.entry, importer, resolveModule, config);
|
|
129
130
|
}
|
|
130
131
|
catch (error) {
|
|
131
132
|
throw new Error(`could not resolve entry "${declaration.entry}" for Deno module "${declaration.name}" from "${importer}": ${formatError(error)}`);
|
|
@@ -145,7 +146,7 @@ async function bundleRuntime(entry, resolveModule, config) {
|
|
|
145
146
|
return { id: builtin, external: true };
|
|
146
147
|
if (!importer || source.startsWith("\0"))
|
|
147
148
|
return null;
|
|
148
|
-
const resolved = await resolveHostModule(source, importer, resolveModule);
|
|
149
|
+
const resolved = await resolveHostModule(source, importer, resolveModule, config);
|
|
149
150
|
if (!resolved) {
|
|
150
151
|
throw new Error(`unresolved runtime dependency "${source}" from "${importer}"`);
|
|
151
152
|
}
|
|
@@ -232,7 +233,7 @@ async function bundleRuntime(entry, resolveModule, config) {
|
|
|
232
233
|
}
|
|
233
234
|
return { source: entryChunk.code, files };
|
|
234
235
|
}
|
|
235
|
-
async function resolveHostModule(source, importer, resolveModule) {
|
|
236
|
+
async function resolveHostModule(source, importer, resolveModule, config) {
|
|
236
237
|
const resolved = await resolveModule(source, importer, { skipSelf: true });
|
|
237
238
|
const resolvedFile = resolved ? stripQueryAndHash(resolved.id) : null;
|
|
238
239
|
const needsPackageFallback = Boolean(isBareSpecifier(source) &&
|
|
@@ -240,6 +241,23 @@ async function resolveHostModule(source, importer, resolveModule) {
|
|
|
240
241
|
(isOptimizedDependencyPath(resolved.id) || resolved.external || !ts.sys.fileExists(resolvedFile)));
|
|
241
242
|
if (!needsPackageFallback)
|
|
242
243
|
return resolved;
|
|
244
|
+
if (config) {
|
|
245
|
+
try {
|
|
246
|
+
let resolver = ssrResolvers.get(config);
|
|
247
|
+
if (!resolver) {
|
|
248
|
+
resolver = config.createResolver();
|
|
249
|
+
ssrResolvers.set(config, resolver);
|
|
250
|
+
}
|
|
251
|
+
const serverResolved = await resolver(source, importer, false, true);
|
|
252
|
+
if (serverResolved)
|
|
253
|
+
return { id: serverResolved };
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
// Fall through to the legacy Node resolver. Custom Vite plugins can still
|
|
257
|
+
// return a usable outer resolution even when Vite's internal SSR resolver
|
|
258
|
+
// cannot resolve the specifier.
|
|
259
|
+
}
|
|
260
|
+
}
|
|
243
261
|
try {
|
|
244
262
|
return { id: nodeRequire.resolve(source, { paths: [dirname(importer)] }) };
|
|
245
263
|
}
|
|
@@ -298,7 +316,7 @@ async function bundleDeclarations(runtimeEntry, specifier, importer, diagnosticP
|
|
|
298
316
|
continue;
|
|
299
317
|
if (!canResolveDeclarationDependency(moduleSpecifier, packageBoundary))
|
|
300
318
|
continue;
|
|
301
|
-
const resolved = await resolveDeclarationDependency(moduleSpecifier, fileName, options, host, resolveModule);
|
|
319
|
+
const resolved = await resolveDeclarationDependency(moduleSpecifier, fileName, options, host, resolveModule, config);
|
|
302
320
|
if (!resolved) {
|
|
303
321
|
throw new Error(`${diagnosticPrefix}: public declaration still depends on unresolved module "${moduleSpecifier}"`);
|
|
304
322
|
}
|
|
@@ -481,12 +499,12 @@ function resolveExportTarget(target, packageDirectory) {
|
|
|
481
499
|
}
|
|
482
500
|
return null;
|
|
483
501
|
}
|
|
484
|
-
async function resolveDeclarationDependency(specifier, importer, options, host, resolveModule) {
|
|
502
|
+
async function resolveDeclarationDependency(specifier, importer, options, host, resolveModule, config) {
|
|
485
503
|
const fromTypeScript = ts.resolveModuleName(specifier, importer, options, host).resolvedModule?.resolvedFileName;
|
|
486
504
|
if (fromTypeScript && !isTypeScriptLib(fromTypeScript) && isDeclarationLikePath(fromTypeScript)) {
|
|
487
505
|
return normalizeFile(fromTypeScript);
|
|
488
506
|
}
|
|
489
|
-
const viteResolved = await resolveHostModule(specifier, importer, resolveModule);
|
|
507
|
+
const viteResolved = await resolveHostModule(specifier, importer, resolveModule, config);
|
|
490
508
|
if (!viteResolved || viteResolved.external)
|
|
491
509
|
return null;
|
|
492
510
|
const resolvedId = stripQueryAndHash(viteResolved.id);
|