@workbench-ai/workbench-core 0.0.46

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.
Files changed (72) hide show
  1. package/dist/adapter-auth.d.ts +63 -0
  2. package/dist/adapter-auth.d.ts.map +1 -0
  3. package/dist/adapter-auth.js +244 -0
  4. package/dist/execution-events.d.ts +53 -0
  5. package/dist/execution-events.d.ts.map +1 -0
  6. package/dist/execution-events.js +195 -0
  7. package/dist/execution-graph.d.ts +27 -0
  8. package/dist/execution-graph.d.ts.map +1 -0
  9. package/dist/execution-graph.js +126 -0
  10. package/dist/execution-jobs.d.ts +70 -0
  11. package/dist/execution-jobs.d.ts.map +1 -0
  12. package/dist/execution-jobs.js +229 -0
  13. package/dist/execution-outputs.d.ts +9 -0
  14. package/dist/execution-outputs.d.ts.map +1 -0
  15. package/dist/execution-outputs.js +393 -0
  16. package/dist/execution-phases.d.ts +21 -0
  17. package/dist/execution-phases.d.ts.map +1 -0
  18. package/dist/execution-phases.js +262 -0
  19. package/dist/execution-runtime-types.d.ts +35 -0
  20. package/dist/execution-runtime-types.d.ts.map +1 -0
  21. package/dist/execution-runtime-types.js +1 -0
  22. package/dist/execution-scheduler.d.ts +31 -0
  23. package/dist/execution-scheduler.d.ts.map +1 -0
  24. package/dist/execution-scheduler.js +241 -0
  25. package/dist/execution-traces.d.ts +16 -0
  26. package/dist/execution-traces.d.ts.map +1 -0
  27. package/dist/execution-traces.js +164 -0
  28. package/dist/execution-usage.d.ts +12 -0
  29. package/dist/execution-usage.d.ts.map +1 -0
  30. package/dist/execution-usage.js +433 -0
  31. package/dist/generic-spec.d.ts +113 -0
  32. package/dist/generic-spec.d.ts.map +1 -0
  33. package/dist/generic-spec.js +656 -0
  34. package/dist/index.d.ts +160 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +2858 -0
  37. package/dist/model-prices-litellm.d.ts +9674 -0
  38. package/dist/model-prices-litellm.d.ts.map +1 -0
  39. package/dist/model-prices-litellm.js +9668 -0
  40. package/dist/runtime-utils.d.ts +18 -0
  41. package/dist/runtime-utils.d.ts.map +1 -0
  42. package/dist/runtime-utils.js +108 -0
  43. package/dist/sandbox-backends/docker.d.ts +5 -0
  44. package/dist/sandbox-backends/docker.d.ts.map +1 -0
  45. package/dist/sandbox-backends/docker.js +568 -0
  46. package/dist/sandbox-backends/index.d.ts +37 -0
  47. package/dist/sandbox-backends/index.d.ts.map +1 -0
  48. package/dist/sandbox-backends/index.js +79 -0
  49. package/dist/sandbox-backends/names.d.ts +6 -0
  50. package/dist/sandbox-backends/names.d.ts.map +1 -0
  51. package/dist/sandbox-backends/names.js +14 -0
  52. package/dist/sandbox-backends/template-images.d.ts +4 -0
  53. package/dist/sandbox-backends/template-images.d.ts.map +1 -0
  54. package/dist/sandbox-backends/template-images.js +48 -0
  55. package/dist/sandbox-inputs.d.ts +27 -0
  56. package/dist/sandbox-inputs.d.ts.map +1 -0
  57. package/dist/sandbox-inputs.js +220 -0
  58. package/dist/sandbox-plane.d.ts +89 -0
  59. package/dist/sandbox-plane.d.ts.map +1 -0
  60. package/dist/sandbox-plane.js +327 -0
  61. package/dist/subject-patch.d.ts +8 -0
  62. package/dist/subject-patch.d.ts.map +1 -0
  63. package/dist/subject-patch.js +63 -0
  64. package/dist/trace-files.d.ts +18 -0
  65. package/dist/trace-files.d.ts.map +1 -0
  66. package/dist/trace-files.js +94 -0
  67. package/environments/libreoffice-agent/Dockerfile +13 -0
  68. package/environments/libreoffice-python/Dockerfile +11 -0
  69. package/environments/node-22/Dockerfile +3 -0
  70. package/environments/python-3.12/Dockerfile +8 -0
  71. package/package.json +42 -0
  72. package/worker/sandbox-adapter-runner.cjs +275 -0
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+ const fs = require("node:fs");
3
+
4
+ const requestPath = process.argv[2] || "/workbench-execution/request.json";
5
+ const responsePath = process.argv[3] || "/workbench-execution/response.json";
6
+ const stagePath = responsePath.replace(/response\.json$/u, "stage.log");
7
+
8
+ function markStage(stage) {
9
+ try {
10
+ fs.appendFileSync(stagePath, `${new Date().toISOString()} ${stage}\n`);
11
+ } catch {
12
+ // Stage logging is diagnostic only; response writing below remains authoritative.
13
+ }
14
+ }
15
+
16
+ async function main() {
17
+ try {
18
+ markStage("start");
19
+ const request = JSON.parse(fs.readFileSync(requestPath, "utf8"));
20
+ markStage("request-read");
21
+ const validated = await validateSandboxAdapterRequest(request);
22
+ removeRequestFile(requestPath);
23
+ markStage("request-removed");
24
+ const runtimeImport = process.env.WORKBENCH_RUNTIME_IMPORT || "../src/index.ts";
25
+ const {
26
+ executeAdapterInCurrentSandboxRuntime,
27
+ } = await import(runtimeImport);
28
+ markStage("runtime-imported");
29
+ const startedAt = typeof request.startedAt === "string" ? request.startedAt : new Date().toISOString();
30
+ const completedJob = await executeAdapterInCurrentSandboxRuntime(
31
+ {
32
+ ...validated.jobInput,
33
+ now: startedAt,
34
+ workspaceRoot: workspaceRootFromEnvironment(),
35
+ pullImages: false,
36
+ runtimeRegistry: "",
37
+ },
38
+ validated.execution,
39
+ startedAt,
40
+ validated.capability,
41
+ );
42
+ markStage("adapter-completed");
43
+ fs.writeFileSync(responsePath, `${JSON.stringify({ ok: true, job: completedJob }, null, 2)}\n`);
44
+ } catch (error) {
45
+ markStage("failed");
46
+ fs.writeFileSync(responsePath, `${JSON.stringify({
47
+ ok: false,
48
+ error: error instanceof Error ? error.stack ?? error.message : String(error),
49
+ }, null, 2)}\n`);
50
+ process.exitCode = 1;
51
+ }
52
+ }
53
+
54
+ function workspaceRootFromEnvironment() {
55
+ const value = typeof process.env.WORKBENCH_WORKSPACE_ROOT === "string"
56
+ ? process.env.WORKBENCH_WORKSPACE_ROOT.trim()
57
+ : "";
58
+ return isSafeWorkspaceRoot(value) ? value : "/workspace";
59
+ }
60
+
61
+ function isSafeWorkspaceRoot(value) {
62
+ return value.startsWith("/")
63
+ && value !== "/"
64
+ && !value.startsWith("/workbench-runtime")
65
+ && !value.startsWith("/workbench-execution")
66
+ && !/[\0\r\n:]/u.test(value);
67
+ }
68
+
69
+ async function validateSandboxAdapterRequest(request) {
70
+ const jobInput = request?.jobInput;
71
+ const jobExecution = jobInput?.job?.input?.execution;
72
+ const execution = request?.execution ?? jobExecution;
73
+ if (!jobInput || typeof jobInput !== "object" || !jobInput.job || typeof jobInput.job !== "object") {
74
+ throw new Error("Sandbox adapter request must include jobInput.job.");
75
+ }
76
+ if (!execution || typeof execution !== "object" || Array.isArray(execution)) {
77
+ throw new Error("Sandbox adapter request must include execution.");
78
+ }
79
+ if (!jobExecution || typeof jobExecution !== "object" || Array.isArray(jobExecution)) {
80
+ throw new Error("Sandbox adapter request must include jobInput.job.input.execution.");
81
+ }
82
+ const mismatch = collectExecutionMismatchIssues(jobExecution, execution);
83
+ if (mismatch.length > 0) {
84
+ throw new Error(`Sandbox adapter request execution mismatch:\n${mismatch.join("\n")}`);
85
+ }
86
+ if (!request.capability || typeof request.capability !== "object" || Array.isArray(request.capability)) {
87
+ throw new Error("Sandbox adapter request must include capability.");
88
+ }
89
+ const runtimeImport = process.env.WORKBENCH_RUNTIME_IMPORT || "../src/index.ts";
90
+ const {
91
+ collectExecutionCapabilityScopeIssues,
92
+ } = await import(runtimeImport);
93
+ const issues = collectExecutionCapabilityScopeIssues(request.capability, execution, {
94
+ now: new Date().toISOString(),
95
+ });
96
+ if (issues.length > 0) {
97
+ throw new Error(`Sandbox adapter request capability failed validation:\n${issues.join("\n")}`);
98
+ }
99
+ const inputBundle = validateInputBundle(request.inputBundle, request.capability, execution);
100
+ const runtimeInputs = runtimeInputsFromInputBundle(inputBundle);
101
+ const jobInputWithExecution = {
102
+ ...jobInput,
103
+ ...runtimeInputs,
104
+ job: {
105
+ ...jobInput.job,
106
+ input: {
107
+ ...(jobInput.job.input && typeof jobInput.job.input === "object" && !Array.isArray(jobInput.job.input)
108
+ ? jobInput.job.input
109
+ : {}),
110
+ execution,
111
+ },
112
+ },
113
+ };
114
+ return {
115
+ jobInput: jobInputWithExecution,
116
+ execution,
117
+ capability: request.capability,
118
+ };
119
+ }
120
+
121
+ function validateInputBundle(bundle, capability, execution) {
122
+ if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
123
+ throw new Error("Sandbox adapter request must include inputBundle.");
124
+ }
125
+ if (!Array.isArray(bundle.inputs)) {
126
+ throw new Error("Sandbox adapter inputBundle.inputs must be an array.");
127
+ }
128
+ const expected = new Map((capability.inputs || []).map((input) => [capabilityInputKey(input), input]));
129
+ const seen = new Set();
130
+ const inputs = [];
131
+ for (const entry of bundle.inputs) {
132
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
133
+ throw new Error("Sandbox adapter inputBundle inputs must be objects.");
134
+ }
135
+ const input = entry.input;
136
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
137
+ throw new Error("Sandbox adapter inputBundle input entry must include input.");
138
+ }
139
+ const key = capabilityInputKey(input);
140
+ if (!expected.has(key)) {
141
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} is outside the execution capability.`);
142
+ }
143
+ if (seen.has(key)) {
144
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} is duplicated.`);
145
+ }
146
+ seen.add(key);
147
+ if (entry.mountPath !== input.mountPath) {
148
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} mountPath does not match capability.`);
149
+ }
150
+ if (entry.kind === "files") {
151
+ if (!Array.isArray(entry.files) || !entry.files.every(isSurfaceSnapshotFile)) {
152
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} must include files.`);
153
+ }
154
+ inputs.push({
155
+ input,
156
+ mountPath: entry.mountPath,
157
+ kind: "files",
158
+ files: entry.files.map((file) => ({ ...file })),
159
+ });
160
+ } else if (entry.kind === "json") {
161
+ if (!isJson(entry.json)) {
162
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} must include JSON.`);
163
+ }
164
+ inputs.push({
165
+ input,
166
+ mountPath: entry.mountPath,
167
+ kind: "json",
168
+ json: entry.json,
169
+ });
170
+ } else {
171
+ throw new Error(`Sandbox adapter input bundle entry ${input.name || "<unknown>"} has unsupported kind ${entry.kind || "<missing>"}.`);
172
+ }
173
+ }
174
+ if (seen.size !== expected.size) {
175
+ const missing = [...expected.values()]
176
+ .filter((input) => !seen.has(capabilityInputKey(input)))
177
+ .map((input) => input.name)
178
+ .join(", ");
179
+ throw new Error(`Sandbox adapter input bundle is missing declared capability inputs${missing ? `: ${missing}` : ""}.`);
180
+ }
181
+ const executionInputKeys = new Set((execution.inputs || []).map(capabilityInputKey));
182
+ for (const input of expected.values()) {
183
+ if (!executionInputKeys.has(capabilityInputKey(input))) {
184
+ throw new Error(`Sandbox adapter capability input ${input.name || "<unknown>"} is not declared by the execution.`);
185
+ }
186
+ }
187
+ return { inputs };
188
+ }
189
+
190
+ function runtimeInputsFromInputBundle(bundle) {
191
+ const filesByName = new Map();
192
+ for (const entry of bundle.inputs) {
193
+ if (entry.kind === "files") {
194
+ filesByName.set(entry.input.name, entry.files);
195
+ }
196
+ }
197
+ return {
198
+ baseFiles: filesByName.get("subject") || [],
199
+ engineResolveFiles: filesByName.get("case") || [],
200
+ traceFiles: filesByName.get("traces") || [],
201
+ };
202
+ }
203
+
204
+ function removeRequestFile(filePath) {
205
+ fs.rmSync(filePath, { force: true });
206
+ }
207
+
208
+ function capabilityInputKey(input) {
209
+ return stableJson({
210
+ name: input?.name ?? null,
211
+ ref: input?.ref ?? null,
212
+ mountPath: input?.mountPath ?? null,
213
+ writable: input?.writable ?? null,
214
+ });
215
+ }
216
+
217
+ function isSurfaceSnapshotFile(value) {
218
+ return Boolean(value)
219
+ && typeof value === "object"
220
+ && !Array.isArray(value)
221
+ && typeof value.path === "string"
222
+ && (value.kind === "text" || value.kind === "binary")
223
+ && (value.encoding === "utf8" || value.encoding === "base64")
224
+ && typeof value.content === "string"
225
+ && typeof value.executable === "boolean";
226
+ }
227
+
228
+ function isJson(value) {
229
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
230
+ return true;
231
+ }
232
+ if (typeof value === "number") {
233
+ return Number.isFinite(value);
234
+ }
235
+ if (Array.isArray(value)) {
236
+ return value.every(isJson);
237
+ }
238
+ if (value && typeof value === "object") {
239
+ return Object.values(value).every(isJson);
240
+ }
241
+ return false;
242
+ }
243
+
244
+ function collectExecutionMismatchIssues(jobExecution, execution) {
245
+ const issues = [];
246
+ for (const key of ["id", "projectId", "runId", "subjectId", "purpose"]) {
247
+ if ((jobExecution[key] ?? null) !== (execution[key] ?? null)) {
248
+ issues.push(`job execution ${key} does not match request execution ${key}.`);
249
+ }
250
+ }
251
+ for (const key of ["adapter", "sandbox", "inputs", "outputs", "policy", "metadata"]) {
252
+ if (stableJson(jobExecution[key] ?? null) !== stableJson(execution[key] ?? null)) {
253
+ issues.push(`job execution ${key} does not match request execution ${key}.`);
254
+ }
255
+ }
256
+ return issues;
257
+ }
258
+
259
+ function stableJson(value) {
260
+ if (Array.isArray(value)) {
261
+ return `[${value.map(stableJson).join(",")}]`;
262
+ }
263
+ if (value && typeof value === "object") {
264
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
265
+ }
266
+ return JSON.stringify(value);
267
+ }
268
+
269
+ if (require.main === module) {
270
+ void main();
271
+ }
272
+
273
+ module.exports = {
274
+ validateSandboxAdapterRequest,
275
+ };