@workbench-ai/workbench 0.0.50 → 0.0.51
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/dist/command-model.d.ts.map +1 -1
- package/dist/command-model.js +37 -420
- package/dist/dev-open/client.css +21 -50
- package/dist/dev-open/client.js +140 -140
- package/dist/dev-open-server.d.ts +3 -0
- package/dist/dev-open-server.d.ts.map +1 -1
- package/dist/dev-open-server.js +40 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +383 -837
- package/dist/local-archive.d.ts +5 -1
- package/dist/local-archive.d.ts.map +1 -1
- package/dist/local-archive.js +239 -10
- package/package.json +4 -4
package/dist/local-archive.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CandidateRecord, type EvaluationScorecard, type HostedWorkbenchJob, type RunSummary, type RuntimeEvent, type SurfaceSnapshotFile, type WorkbenchExecutionTrace, type WorkbenchTraceSession } from "@workbench-ai/workbench-core";
|
|
1
|
+
import { type CandidateRecord, type EvaluationScorecard, type HostedWorkbenchJob, type RunSummary, type RuntimeEvent, type SurfaceSnapshotFile, type WorkbenchRuntimeBundle, type WorkbenchRuntimeBundleStats, type WorkbenchRuntimeImportResult, type WorkbenchExecutionTrace, type WorkbenchTraceSession } from "@workbench-ai/workbench-core";
|
|
2
2
|
export interface LocalArchiveSnapshot {
|
|
3
3
|
activeId: string | null;
|
|
4
4
|
candidates: CandidateRecord[];
|
|
@@ -23,6 +23,10 @@ export declare function loadLocalArchive(workspace: string): Promise<LocalArchiv
|
|
|
23
23
|
export declare function loadLocalArchiveIndex(workspace: string): Promise<LocalArchiveIndex>;
|
|
24
24
|
export declare function saveLocalArchive(workspace: string, snapshot: LocalArchiveSnapshot): Promise<void>;
|
|
25
25
|
export declare function saveLocalJobs(workspace: string, jobs: readonly HostedWorkbenchJob[]): Promise<void>;
|
|
26
|
+
export declare function exportLocalRuntimeBundle(workspace: string): Promise<WorkbenchRuntimeBundle>;
|
|
27
|
+
export declare function importLocalRuntimeBundle(workspace: string, bundle: WorkbenchRuntimeBundle): Promise<WorkbenchRuntimeImportResult>;
|
|
28
|
+
export declare function runtimeBundleStats(bundle: WorkbenchRuntimeBundle): WorkbenchRuntimeBundleStats;
|
|
29
|
+
export declare function sanitizeRuntimeJobForExchange(job: HostedWorkbenchJob): HostedWorkbenchJob;
|
|
26
30
|
export declare function readLocalExecutionFiles(workspace: string, jobId: string): Promise<SurfaceSnapshotFile[]>;
|
|
27
31
|
export declare function readLocalCandidateRecord(workspace: string, candidateId: string): Promise<CandidateRecord>;
|
|
28
32
|
export declare function readLocalCandidateFilesForId(workspace: string, candidateId: string): Promise<SurfaceSnapshotFile[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-archive.d.ts","sourceRoot":"","sources":["../src/local-archive.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"local-archive.d.ts","sourceRoot":"","sources":["../src/local-archive.ts"],"names":[],"mappings":"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"}
|
package/dist/local-archive.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { buildWorkbenchTraceSessionsFromFiles, candidateRecordWithoutDerivedFields, selectExecutionOutputFilesForInspection, } from "@workbench-ai/workbench-core";
|
|
3
|
+
import { buildWorkbenchTraceSessionsFromFiles, candidateRecordWithoutDerivedFields, sanitizeWorkbenchRuntimeCandidateForExchange, sanitizeWorkbenchRuntimeJobForExchange, selectExecutionOutputFilesForInspection, workbenchRuntimeBundleStats, workbenchSurfaceFilesEqualForExchange, } from "@workbench-ai/workbench-core";
|
|
4
4
|
const RUNTIME_DIR = ".workbench/runtime";
|
|
5
5
|
const CANDIDATE_RECORDS_DIR = "candidates";
|
|
6
6
|
export function localRuntimeDir(workspace) {
|
|
@@ -66,6 +66,142 @@ export async function saveLocalArchive(workspace, snapshot) {
|
|
|
66
66
|
await writeJson(path.join(root, "events.json"), snapshot.events);
|
|
67
67
|
}
|
|
68
68
|
export async function saveLocalJobs(workspace, jobs) {
|
|
69
|
+
if (jobs.length === 0) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await writeArchivedLocalJobs(workspace, jobs, new Map());
|
|
73
|
+
}
|
|
74
|
+
export async function exportLocalRuntimeBundle(workspace) {
|
|
75
|
+
const snapshot = await loadLocalArchive(workspace);
|
|
76
|
+
const jobs = (await readLocalJobs(workspace)).map(sanitizeRuntimeJobForExchange);
|
|
77
|
+
const executionFiles = await Promise.all(jobs.map(async (job) => ({
|
|
78
|
+
jobId: job.id,
|
|
79
|
+
files: await readLocalExecutionFiles(workspace, job.id),
|
|
80
|
+
})));
|
|
81
|
+
return {
|
|
82
|
+
schema: "workbench.runtime.bundle.v1",
|
|
83
|
+
activeId: snapshot.activeId,
|
|
84
|
+
candidates: snapshot.candidates.map(sanitizeWorkbenchRuntimeCandidateForExchange),
|
|
85
|
+
candidateFiles: Object.entries(snapshot.candidateFiles).map(([candidateId, files]) => ({
|
|
86
|
+
candidateId,
|
|
87
|
+
files: copySurfaceFiles(files),
|
|
88
|
+
})),
|
|
89
|
+
evaluations: snapshot.evaluations.map((evaluation) => ({ ...evaluation })),
|
|
90
|
+
runs: snapshot.runs.map((run) => ({ ...run })),
|
|
91
|
+
jobs,
|
|
92
|
+
executionFiles,
|
|
93
|
+
events: snapshot.events.map((event) => ({ ...event })),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export async function importLocalRuntimeBundle(workspace, bundle) {
|
|
97
|
+
validateRuntimeBundleSchema(bundle);
|
|
98
|
+
const snapshot = await loadLocalArchive(workspace);
|
|
99
|
+
const existingJobs = (await readLocalJobs(workspace)).map(sanitizeRuntimeJobForExchange);
|
|
100
|
+
let changed = false;
|
|
101
|
+
const existingCandidates = snapshot.candidates.map(sanitizeWorkbenchRuntimeCandidateForExchange);
|
|
102
|
+
if (JSON.stringify(existingCandidates) !== JSON.stringify(snapshot.candidates)) {
|
|
103
|
+
changed = true;
|
|
104
|
+
}
|
|
105
|
+
const incomingCandidates = bundle.candidates.map(sanitizeWorkbenchRuntimeCandidateForExchange);
|
|
106
|
+
const candidates = mergeRecordsById(existingCandidates, incomingCandidates, (candidate) => candidate.id, (didChange) => {
|
|
107
|
+
changed ||= didChange;
|
|
108
|
+
}).sort(compareLocalCandidateRecords);
|
|
109
|
+
const candidateFiles = { ...snapshot.candidateFiles };
|
|
110
|
+
for (const group of bundle.candidateFiles) {
|
|
111
|
+
const candidateId = localRecordName(group.candidateId);
|
|
112
|
+
const files = copySurfaceFiles(group.files);
|
|
113
|
+
const existing = candidateFiles[candidateId];
|
|
114
|
+
if (existing) {
|
|
115
|
+
if (!workbenchSurfaceFilesEqualForExchange(existing, files)) {
|
|
116
|
+
throw new Error(`Runtime history conflict for candidate files ${candidateId}.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
changed = true;
|
|
121
|
+
}
|
|
122
|
+
candidateFiles[candidateId] = files;
|
|
123
|
+
}
|
|
124
|
+
const candidateIds = new Set(candidates.map((candidate) => candidate.id));
|
|
125
|
+
const activeId = bundle.activeId && candidateIds.has(bundle.activeId)
|
|
126
|
+
? bundle.activeId
|
|
127
|
+
: snapshot.activeId && candidateIds.has(snapshot.activeId)
|
|
128
|
+
? snapshot.activeId
|
|
129
|
+
: null;
|
|
130
|
+
if (activeId !== snapshot.activeId) {
|
|
131
|
+
changed = true;
|
|
132
|
+
}
|
|
133
|
+
const evaluations = mergeRecordsById(snapshot.evaluations, bundle.evaluations, (evaluation) => evaluation.id, (didChange) => {
|
|
134
|
+
changed ||= didChange;
|
|
135
|
+
}).sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
|
|
136
|
+
const runs = mergeRecordsById(snapshot.runs, bundle.runs, (run) => run.id, (didChange) => {
|
|
137
|
+
changed ||= didChange;
|
|
138
|
+
}).sort((left, right) => left.startedAt.localeCompare(right.startedAt) || left.id.localeCompare(right.id));
|
|
139
|
+
const events = mergeRecordsById(snapshot.events, bundle.events, runtimeEventKey, (didChange) => {
|
|
140
|
+
changed ||= didChange;
|
|
141
|
+
}).sort((left, right) => left.at.localeCompare(right.at) || left.id.localeCompare(right.id));
|
|
142
|
+
const executionFilesByJobId = new Map();
|
|
143
|
+
await Promise.all(existingJobs.map(async (job) => {
|
|
144
|
+
executionFilesByJobId.set(job.id, await readLocalExecutionFiles(workspace, job.id));
|
|
145
|
+
}));
|
|
146
|
+
for (const group of bundle.executionFiles) {
|
|
147
|
+
const jobId = localRecordName(group.jobId);
|
|
148
|
+
const files = copySurfaceFiles(group.files);
|
|
149
|
+
const existing = executionFilesByJobId.get(jobId);
|
|
150
|
+
if (existing) {
|
|
151
|
+
if (!workbenchSurfaceFilesEqualForExchange(existing, files)) {
|
|
152
|
+
throw new Error(`Runtime history conflict for execution files ${jobId}.`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
changed = true;
|
|
157
|
+
}
|
|
158
|
+
executionFilesByJobId.set(jobId, files);
|
|
159
|
+
}
|
|
160
|
+
const jobs = mergeRecordsById(existingJobs, bundle.jobs.map(sanitizeRuntimeJobForExchange), (job) => job.id, (didChange) => {
|
|
161
|
+
changed ||= didChange;
|
|
162
|
+
}, runtimeJobsEqualForExchange).sort((left, right) => (left.startedAt ?? left.createdAt).localeCompare(right.startedAt ?? right.createdAt) ||
|
|
163
|
+
left.id.localeCompare(right.id));
|
|
164
|
+
await saveLocalArchive(workspace, {
|
|
165
|
+
activeId,
|
|
166
|
+
candidates,
|
|
167
|
+
candidateFiles,
|
|
168
|
+
evaluations,
|
|
169
|
+
runs,
|
|
170
|
+
events,
|
|
171
|
+
});
|
|
172
|
+
await writeArchivedLocalJobs(workspace, jobs, executionFilesByJobId);
|
|
173
|
+
return {
|
|
174
|
+
changed,
|
|
175
|
+
stats: runtimeBundleStats({
|
|
176
|
+
schema: "workbench.runtime.bundle.v1",
|
|
177
|
+
activeId,
|
|
178
|
+
candidates,
|
|
179
|
+
candidateFiles: Object.entries(candidateFiles).map(([candidateId, files]) => ({
|
|
180
|
+
candidateId,
|
|
181
|
+
files,
|
|
182
|
+
})),
|
|
183
|
+
evaluations,
|
|
184
|
+
runs,
|
|
185
|
+
jobs,
|
|
186
|
+
executionFiles: [...executionFilesByJobId.entries()].map(([jobId, files]) => ({
|
|
187
|
+
jobId,
|
|
188
|
+
files,
|
|
189
|
+
})),
|
|
190
|
+
events,
|
|
191
|
+
}),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export function runtimeBundleStats(bundle) {
|
|
195
|
+
return workbenchRuntimeBundleStats(bundle);
|
|
196
|
+
}
|
|
197
|
+
export function sanitizeRuntimeJobForExchange(job) {
|
|
198
|
+
return sanitizeWorkbenchRuntimeJobForExchange(job);
|
|
199
|
+
}
|
|
200
|
+
function sanitizeRuntimeJobForArchive(job) {
|
|
201
|
+
const { leaseUntil: _leaseUntil, wakeupLeaseUntil: _wakeupLeaseUntil, hostId: _hostId, workerId: _workerId, claimTokenHash: _claimTokenHash, ...portable } = job;
|
|
202
|
+
return { ...portable };
|
|
203
|
+
}
|
|
204
|
+
async function writeArchivedLocalJobs(workspace, jobs, executionFilesByJobId) {
|
|
69
205
|
if (jobs.length === 0) {
|
|
70
206
|
return;
|
|
71
207
|
}
|
|
@@ -77,14 +213,18 @@ export async function saveLocalJobs(workspace, jobs) {
|
|
|
77
213
|
fs.mkdir(executionFilesDir, { recursive: true }),
|
|
78
214
|
]);
|
|
79
215
|
for (const job of jobs) {
|
|
216
|
+
const sanitizedJob = sanitizeRuntimeJobForArchive(job);
|
|
80
217
|
const safeJobId = localRecordName(job.id);
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
218
|
+
const explicitOutputFiles = executionFilesByJobId.get(job.id);
|
|
219
|
+
const traceSourceFiles = filterArchivedExecutionFiles(completedJobOutputFiles(sanitizedJob));
|
|
220
|
+
const outputFiles = explicitOutputFiles
|
|
221
|
+
? copySurfaceFiles(explicitOutputFiles)
|
|
222
|
+
: selectExecutionOutputFilesForInspection({
|
|
223
|
+
purpose: readExecutionPurpose(sanitizedJob),
|
|
224
|
+
files: traceSourceFiles,
|
|
225
|
+
output: jsonRecord(sanitizedJob.output),
|
|
226
|
+
});
|
|
227
|
+
await writeJson(path.join(jobsDir, `${safeJobId}.json`), archivedLocalJob(sanitizedJob, outputFiles, traceSourceFiles.length > 0 ? traceSourceFiles : outputFiles));
|
|
88
228
|
const filesRoot = path.join(executionFilesDir, safeJobId);
|
|
89
229
|
await fs.rm(filesRoot, { force: true, recursive: true });
|
|
90
230
|
await writeSurfaceFiles(filesRoot, outputFiles);
|
|
@@ -187,6 +327,70 @@ export function readLocalCandidateFiles(snapshot, candidateId) {
|
|
|
187
327
|
function validateLocalArchiveSnapshot(snapshot) {
|
|
188
328
|
validateLocalArchiveIndex(snapshot);
|
|
189
329
|
}
|
|
330
|
+
function validateRuntimeBundleSchema(bundle) {
|
|
331
|
+
if (!bundle || bundle.schema !== "workbench.runtime.bundle.v1") {
|
|
332
|
+
throw new Error("Unsupported Workbench runtime bundle.");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function mergeRecordsById(existing, incoming, idFor, markChanged, equal = runtimeRecordsEqual) {
|
|
336
|
+
const records = new Map();
|
|
337
|
+
for (const record of existing) {
|
|
338
|
+
records.set(localRecordName(idFor(record)), record);
|
|
339
|
+
}
|
|
340
|
+
for (const record of incoming) {
|
|
341
|
+
const id = localRecordName(idFor(record));
|
|
342
|
+
const previous = records.get(id);
|
|
343
|
+
if (!previous || !equal(previous, record)) {
|
|
344
|
+
if (previous) {
|
|
345
|
+
throw new Error(`Runtime history conflict for id ${id}.`);
|
|
346
|
+
}
|
|
347
|
+
markChanged(true);
|
|
348
|
+
}
|
|
349
|
+
records.set(id, record);
|
|
350
|
+
}
|
|
351
|
+
return [...records.values()];
|
|
352
|
+
}
|
|
353
|
+
function runtimeRecordsEqual(left, right) {
|
|
354
|
+
return JSON.stringify(canonicalRuntimeJson(left)) ===
|
|
355
|
+
JSON.stringify(canonicalRuntimeJson(right));
|
|
356
|
+
}
|
|
357
|
+
function runtimeJobsEqualForExchange(left, right) {
|
|
358
|
+
return runtimeRecordsEqual(runtimeComparableJob(left), runtimeComparableJob(right));
|
|
359
|
+
}
|
|
360
|
+
function runtimeComparableJob(job) {
|
|
361
|
+
const comparable = sanitizeRuntimeJobForExchange(job);
|
|
362
|
+
const output = comparable.output;
|
|
363
|
+
if (!output || typeof output !== "object" || Array.isArray(output)) {
|
|
364
|
+
return comparable;
|
|
365
|
+
}
|
|
366
|
+
const { files: _files, fileSet: _fileSet, ...portableOutput } = output;
|
|
367
|
+
return {
|
|
368
|
+
...comparable,
|
|
369
|
+
output: portableOutput,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function canonicalRuntimeJson(value) {
|
|
373
|
+
if (Array.isArray(value)) {
|
|
374
|
+
return value.map(canonicalRuntimeJson);
|
|
375
|
+
}
|
|
376
|
+
if (value && typeof value === "object") {
|
|
377
|
+
return Object.fromEntries(Object.keys(value)
|
|
378
|
+
.sort()
|
|
379
|
+
.map((key) => [key, canonicalRuntimeJson(value[key])]));
|
|
380
|
+
}
|
|
381
|
+
return value;
|
|
382
|
+
}
|
|
383
|
+
function runtimeEventKey(event) {
|
|
384
|
+
return [
|
|
385
|
+
event.runId ?? "_",
|
|
386
|
+
event.jobId ?? "_",
|
|
387
|
+
event.at,
|
|
388
|
+
event.id,
|
|
389
|
+
].join("#");
|
|
390
|
+
}
|
|
391
|
+
function copySurfaceFiles(files) {
|
|
392
|
+
return files.map((file) => ({ ...file }));
|
|
393
|
+
}
|
|
190
394
|
function validateLocalArchiveIndex(snapshot) {
|
|
191
395
|
const candidateIds = new Set(snapshot.candidates.map((candidate) => candidate.id));
|
|
192
396
|
if (snapshot.activeId && !candidateIds.has(snapshot.activeId)) {
|
|
@@ -260,16 +464,41 @@ function compareLocalCandidateRecords(left, right) {
|
|
|
260
464
|
}
|
|
261
465
|
function archivedLocalJob(job, outputFiles, traceSourceFiles) {
|
|
262
466
|
const output = jsonRecord(job.output);
|
|
263
|
-
const
|
|
467
|
+
const existingTrace = readExistingTrace(job);
|
|
468
|
+
const existingTraceSessions = readExistingTraceSessions(job);
|
|
469
|
+
const traceSessions = existingTraceSessions.length > 0
|
|
470
|
+
? existingTraceSessions
|
|
471
|
+
: buildLocalJobTraceSessions(job, traceSourceFiles);
|
|
264
472
|
return {
|
|
265
473
|
...job,
|
|
266
474
|
...(Object.keys(output).length > 0
|
|
267
475
|
? { output: { ...output, files: traceSourceFiles } }
|
|
268
476
|
: {}),
|
|
269
|
-
trace: buildLocalJobTrace(job),
|
|
477
|
+
trace: existingTrace ?? buildLocalJobTrace(job),
|
|
270
478
|
traceSessions,
|
|
271
479
|
};
|
|
272
480
|
}
|
|
481
|
+
function readExistingTrace(job) {
|
|
482
|
+
const trace = job.trace;
|
|
483
|
+
if (!trace || typeof trace !== "object" || Array.isArray(trace)) {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
trace_id: typeof trace.trace_id === "string" && trace.trace_id.length > 0
|
|
488
|
+
? trace.trace_id
|
|
489
|
+
: job.id,
|
|
490
|
+
spans: Array.isArray(trace.spans) ? trace.spans : [],
|
|
491
|
+
events: Array.isArray(trace.events) ? trace.events : [],
|
|
492
|
+
summaries: Array.isArray(trace.summaries) ? trace.summaries : [],
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function readExistingTraceSessions(job) {
|
|
496
|
+
const sessions = job.traceSessions;
|
|
497
|
+
if (!Array.isArray(sessions)) {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
return sessions.map((session) => ({ ...session }));
|
|
501
|
+
}
|
|
273
502
|
function filterArchivedExecutionFiles(files) {
|
|
274
503
|
return files.filter((file) => file.path.startsWith(".workbench/traces/") ||
|
|
275
504
|
!isWorkbenchReservedArchivePath(file.path));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-ai/workbench",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"yaml": "^2.8.2",
|
|
24
|
-
"@workbench-ai/workbench-
|
|
25
|
-
"@workbench-ai/workbench-protocol": "0.0.
|
|
26
|
-
"@workbench-ai/workbench-
|
|
24
|
+
"@workbench-ai/workbench-core": "0.0.51",
|
|
25
|
+
"@workbench-ai/workbench-protocol": "0.0.51",
|
|
26
|
+
"@workbench-ai/workbench-built-in-adapters": "0.0.51"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@tailwindcss/postcss": "^4.2.2",
|