@workbench-ai/workbench-protocol 0.0.40
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/adapter-manifest.d.ts +50 -0
- package/dist/adapter-manifest.d.ts.map +1 -0
- package/dist/adapter-manifest.js +448 -0
- package/dist/adapter-protocol.d.ts +59 -0
- package/dist/adapter-protocol.d.ts.map +1 -0
- package/dist/adapter-protocol.js +186 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/package.json +34 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface WorkbenchAdapterManifest {
|
|
2
|
+
id: string;
|
|
3
|
+
protocol: "workbench.adapter.v1";
|
|
4
|
+
setup: string[];
|
|
5
|
+
command: string;
|
|
6
|
+
auth?: WorkbenchAdapterAuthManifest;
|
|
7
|
+
refs?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface WorkbenchAdapterAuthManifest {
|
|
10
|
+
methods?: Record<string, WorkbenchAdapterAuthMethodManifest>;
|
|
11
|
+
slots?: Record<string, {
|
|
12
|
+
methods?: Record<string, WorkbenchAdapterAuthMethodManifest>;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
export interface WorkbenchAdapterAuthFileManifest {
|
|
16
|
+
path: string;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface WorkbenchAdapterAuthEnvManifest {
|
|
20
|
+
name: string;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface WorkbenchAdapterAuthMethodManifest {
|
|
24
|
+
env?: WorkbenchAdapterAuthEnvManifest[];
|
|
25
|
+
files?: WorkbenchAdapterAuthFileManifest[];
|
|
26
|
+
command?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface WorkbenchAdapterInvocationLike {
|
|
29
|
+
use: string;
|
|
30
|
+
auth?: unknown;
|
|
31
|
+
with?: unknown;
|
|
32
|
+
}
|
|
33
|
+
export interface WorkbenchAdapterAuthRequirement {
|
|
34
|
+
adapterId: string;
|
|
35
|
+
slot?: string;
|
|
36
|
+
profile: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function adapterCommandName(adapterId: string): string;
|
|
39
|
+
export declare function cloneWorkbenchAdapterManifest(manifest: WorkbenchAdapterManifest): WorkbenchAdapterManifest;
|
|
40
|
+
export declare function parseWorkbenchAdapterManifest(source: string, label?: string): WorkbenchAdapterManifest;
|
|
41
|
+
export declare function workbenchAdapterManifestRequiresAuth(manifest: WorkbenchAdapterManifest): boolean;
|
|
42
|
+
export declare function collectWorkbenchAdapterInvocations(roots: readonly WorkbenchAdapterInvocationLike[], manifests: readonly WorkbenchAdapterManifest[] | Map<string, WorkbenchAdapterManifest>): WorkbenchAdapterInvocationLike[];
|
|
43
|
+
export declare function collectWorkbenchAdapterAuthRequirements(roots: readonly WorkbenchAdapterInvocationLike[], manifests: readonly WorkbenchAdapterManifest[] | Map<string, WorkbenchAdapterManifest>): WorkbenchAdapterAuthRequirement[];
|
|
44
|
+
export declare function withDefaultWorkbenchAdapterAuthProfiles<T extends {
|
|
45
|
+
improve?: WorkbenchAdapterInvocationLike;
|
|
46
|
+
run: WorkbenchAdapterInvocationLike;
|
|
47
|
+
grade: WorkbenchAdapterInvocationLike;
|
|
48
|
+
}>(spec: T, manifests: readonly WorkbenchAdapterManifest[] | Map<string, WorkbenchAdapterManifest>): T;
|
|
49
|
+
export declare function withDefaultWorkbenchAdapterAuth<T extends WorkbenchAdapterInvocationLike>(invocation: T, manifests: readonly WorkbenchAdapterManifest[] | Map<string, WorkbenchAdapterManifest>): T;
|
|
50
|
+
//# sourceMappingURL=adapter-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-manifest.d.ts","sourceRoot":"","sources":["../src/adapter-manifest.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,sBAAsB,CAAC;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,4BAA4B,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kCAAkC,CAAC,CAAC;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kCAAkC,CAAC,CAAC;KAC9D,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kCAAkC;IACjD,GAAG,CAAC,EAAE,+BAA+B,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE,gCAAgC,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,8BAA8B;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,wBAAwB,GACjC,wBAAwB,CAO1B;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,EACd,KAAK,SAA2B,GAC/B,wBAAwB,CA6B1B;AAED,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,wBAAwB,GACjC,OAAO,CAET;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,SAAS,8BAA8B,EAAE,EAChD,SAAS,EAAE,SAAS,wBAAwB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,GACrF,8BAA8B,EAAE,CAUlC;AAED,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,SAAS,8BAA8B,EAAE,EAChD,SAAS,EAAE,SAAS,wBAAwB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,GACrF,+BAA+B,EAAE,CAcnC;AAED,wBAAgB,uCAAuC,CAAC,CAAC,SAAS;IAChE,OAAO,CAAC,EAAE,8BAA8B,CAAC;IACzC,GAAG,EAAE,8BAA8B,CAAC;IACpC,KAAK,EAAE,8BAA8B,CAAC;CACvC,EACC,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,SAAS,wBAAwB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,GACrF,CAAC,CASH;AAED,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,8BAA8B,EACtF,UAAU,EAAE,CAAC,EACb,SAAS,EAAE,SAAS,wBAAwB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,GACrF,CAAC,CAKH"}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import YAML from "yaml";
|
|
2
|
+
export function adapterCommandName(adapterId) {
|
|
3
|
+
return `workbench-adapter-${adapterId}`;
|
|
4
|
+
}
|
|
5
|
+
export function cloneWorkbenchAdapterManifest(manifest) {
|
|
6
|
+
return {
|
|
7
|
+
...manifest,
|
|
8
|
+
setup: [...manifest.setup],
|
|
9
|
+
...(manifest.auth ? { auth: cloneJson(manifest.auth) } : {}),
|
|
10
|
+
...(manifest.refs ? { refs: [...manifest.refs] } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function parseWorkbenchAdapterManifest(source, label = "workbench.adapter.yaml") {
|
|
14
|
+
const parsed = YAML.parse(source);
|
|
15
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16
|
+
throw new Error(`${label} must be a YAML object.`);
|
|
17
|
+
}
|
|
18
|
+
const record = parsed;
|
|
19
|
+
rejectUnknownManifestKeys(record, label, ["id", "protocol", "setup", "command", "auth", "refs"]);
|
|
20
|
+
const id = readAdapterId(record.id, `${label}.id`);
|
|
21
|
+
if (record.protocol !== "workbench.adapter.v1") {
|
|
22
|
+
throw new Error(`${label}.protocol must be workbench.adapter.v1.`);
|
|
23
|
+
}
|
|
24
|
+
const command = typeof record.command === "string" && record.command.trim()
|
|
25
|
+
? record.command.trim()
|
|
26
|
+
: adapterCommandName(id);
|
|
27
|
+
const setup = record.setup === undefined
|
|
28
|
+
? []
|
|
29
|
+
: readStringArray(record.setup, `${label}.setup`);
|
|
30
|
+
const refs = record.refs === undefined
|
|
31
|
+
? undefined
|
|
32
|
+
: readAdapterRefs(record.refs, `${label}.refs`);
|
|
33
|
+
const auth = readAuth(record.auth, `${label}.auth`);
|
|
34
|
+
return {
|
|
35
|
+
id,
|
|
36
|
+
protocol: "workbench.adapter.v1",
|
|
37
|
+
setup,
|
|
38
|
+
command,
|
|
39
|
+
...(auth ? { auth } : {}),
|
|
40
|
+
...(refs ? { refs } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function workbenchAdapterManifestRequiresAuth(manifest) {
|
|
44
|
+
return defaultWorkbenchAdapterAuthForManifest(manifest) !== undefined;
|
|
45
|
+
}
|
|
46
|
+
export function collectWorkbenchAdapterInvocations(roots, manifests) {
|
|
47
|
+
const manifestById = manifestMap(manifests);
|
|
48
|
+
const collected = [];
|
|
49
|
+
const queue = roots.map((root) => normalizeInvocationLike(root)).filter(isInvocationLike);
|
|
50
|
+
while (queue.length > 0) {
|
|
51
|
+
const invocation = queue.shift();
|
|
52
|
+
collected.push(invocation);
|
|
53
|
+
queue.push(...nestedWorkbenchAdapterInvocations(invocation, manifestById));
|
|
54
|
+
}
|
|
55
|
+
return collected;
|
|
56
|
+
}
|
|
57
|
+
export function collectWorkbenchAdapterAuthRequirements(roots, manifests) {
|
|
58
|
+
const manifestById = manifestMap(manifests);
|
|
59
|
+
const targets = new Map();
|
|
60
|
+
for (const invocation of collectWorkbenchAdapterInvocations(roots, manifestById)) {
|
|
61
|
+
const manifest = manifestById.get(invocation.use);
|
|
62
|
+
const requirements = adapterAuthRequirementsForInvocation(invocation, manifest);
|
|
63
|
+
if (requirements.length === 0) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (const target of requirements) {
|
|
67
|
+
targets.set(adapterAuthRequirementKey(target), target);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...targets.values()];
|
|
71
|
+
}
|
|
72
|
+
export function withDefaultWorkbenchAdapterAuthProfiles(spec, manifests) {
|
|
73
|
+
const manifestById = manifestMap(manifests);
|
|
74
|
+
const clone = cloneJson(spec);
|
|
75
|
+
if (clone.improve) {
|
|
76
|
+
clone.improve = withDefaultWorkbenchAdapterAuth(clone.improve, manifestById);
|
|
77
|
+
}
|
|
78
|
+
clone.run = withDefaultWorkbenchAdapterAuth(clone.run, manifestById);
|
|
79
|
+
clone.grade = withDefaultWorkbenchAdapterAuth(clone.grade, manifestById);
|
|
80
|
+
return clone;
|
|
81
|
+
}
|
|
82
|
+
export function withDefaultWorkbenchAdapterAuth(invocation, manifests) {
|
|
83
|
+
return applyDefaultWorkbenchAdapterAuth(cloneJson(invocation), manifestMap(manifests));
|
|
84
|
+
}
|
|
85
|
+
function applyDefaultWorkbenchAdapterAuth(invocation, manifestById) {
|
|
86
|
+
const manifest = manifestById.get(invocation.use);
|
|
87
|
+
if (manifest && invocation.auth === undefined) {
|
|
88
|
+
const defaultAuth = defaultWorkbenchAdapterAuthForManifest(manifest);
|
|
89
|
+
if (defaultAuth !== undefined) {
|
|
90
|
+
invocation.auth = defaultAuth;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (!manifest?.refs?.length) {
|
|
94
|
+
return invocation;
|
|
95
|
+
}
|
|
96
|
+
const config = invocationConfig(invocation);
|
|
97
|
+
for (const pointer of manifest.refs) {
|
|
98
|
+
const value = readJsonPointer(config, pointer);
|
|
99
|
+
if (Array.isArray(value)) {
|
|
100
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
101
|
+
const nested = normalizeInvocationLike(value[index]);
|
|
102
|
+
if (nested) {
|
|
103
|
+
value[index] = applyDefaultWorkbenchAdapterAuth(nested, manifestById);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const nested = normalizeInvocationLike(value);
|
|
109
|
+
if (nested) {
|
|
110
|
+
const parent = readJsonPointerParent(config, pointer);
|
|
111
|
+
if (parent) {
|
|
112
|
+
const withDefaults = applyDefaultWorkbenchAdapterAuth(nested, manifestById);
|
|
113
|
+
if (Array.isArray(parent.container) && typeof parent.key === "number") {
|
|
114
|
+
parent.container[parent.key] = withDefaults;
|
|
115
|
+
}
|
|
116
|
+
else if (!Array.isArray(parent.container) && typeof parent.key === "string") {
|
|
117
|
+
parent.container[parent.key] = withDefaults;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return invocation;
|
|
123
|
+
}
|
|
124
|
+
function nestedWorkbenchAdapterInvocations(invocation, manifestById) {
|
|
125
|
+
const manifest = manifestById.get(invocation.use);
|
|
126
|
+
if (!manifest?.refs?.length) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
const config = invocationConfig(invocation);
|
|
130
|
+
return manifest.refs.flatMap((pointer) => {
|
|
131
|
+
const value = readJsonPointer(config, pointer);
|
|
132
|
+
if (Array.isArray(value)) {
|
|
133
|
+
return value.map((entry) => normalizeInvocationLike(entry)).filter(isInvocationLike);
|
|
134
|
+
}
|
|
135
|
+
const nested = normalizeInvocationLike(value);
|
|
136
|
+
return nested ? [nested] : [];
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function manifestMap(manifests) {
|
|
140
|
+
return manifests instanceof Map
|
|
141
|
+
? manifests
|
|
142
|
+
: new Map(manifests.map((manifest) => [manifest.id, manifest]));
|
|
143
|
+
}
|
|
144
|
+
function invocationConfig(invocation) {
|
|
145
|
+
return invocation.with;
|
|
146
|
+
}
|
|
147
|
+
function defaultWorkbenchAdapterAuthForManifest(manifest) {
|
|
148
|
+
const auth = manifest.auth;
|
|
149
|
+
if (!auth) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
if (auth.methods && Object.keys(auth.methods).length > 0) {
|
|
153
|
+
return "default";
|
|
154
|
+
}
|
|
155
|
+
const slotNames = adapterAuthSlotNames(auth);
|
|
156
|
+
if (slotNames.length === 0) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return Object.fromEntries(slotNames.map((slot) => [slot, "default"]));
|
|
160
|
+
}
|
|
161
|
+
function adapterAuthRequirementsForInvocation(invocation, manifest) {
|
|
162
|
+
const auth = invocation.auth;
|
|
163
|
+
if (typeof auth === "string") {
|
|
164
|
+
const slotTargets = adapterAuthSlotNames(manifest?.auth).map((slot) => ({
|
|
165
|
+
adapterId: invocation.use,
|
|
166
|
+
slot,
|
|
167
|
+
profile: auth,
|
|
168
|
+
}));
|
|
169
|
+
return manifest?.auth?.methods && Object.keys(manifest.auth.methods).length > 0
|
|
170
|
+
? [{ adapterId: invocation.use, profile: auth }, ...slotTargets]
|
|
171
|
+
: slotTargets.length > 0
|
|
172
|
+
? slotTargets
|
|
173
|
+
: [{ adapterId: invocation.use, profile: auth }];
|
|
174
|
+
}
|
|
175
|
+
if (auth && typeof auth === "object" && !Array.isArray(auth)) {
|
|
176
|
+
return Object.entries(auth)
|
|
177
|
+
.filter((entry) => typeof entry[1] === "string")
|
|
178
|
+
.map(([slot, profile]) => ({
|
|
179
|
+
adapterId: invocation.use,
|
|
180
|
+
slot,
|
|
181
|
+
profile,
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
if (!manifest || !workbenchAdapterManifestRequiresAuth(manifest)) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
const defaultAuth = defaultWorkbenchAdapterAuthForManifest(manifest);
|
|
188
|
+
if (typeof defaultAuth === "string") {
|
|
189
|
+
return [{ adapterId: invocation.use, profile: defaultAuth }];
|
|
190
|
+
}
|
|
191
|
+
if (defaultAuth && typeof defaultAuth === "object") {
|
|
192
|
+
return Object.entries(defaultAuth).map(([slot, profile]) => ({
|
|
193
|
+
adapterId: invocation.use,
|
|
194
|
+
slot,
|
|
195
|
+
profile,
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
function adapterAuthSlotNames(auth) {
|
|
201
|
+
return auth?.slots ? Object.keys(auth.slots).sort() : [];
|
|
202
|
+
}
|
|
203
|
+
function adapterAuthRequirementKey(target) {
|
|
204
|
+
return `${target.adapterId}/${target.slot ?? "_"}/${target.profile}`;
|
|
205
|
+
}
|
|
206
|
+
function normalizeInvocationLike(value) {
|
|
207
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const record = value;
|
|
211
|
+
if (typeof record.use !== "string" || record.use.length === 0) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return record;
|
|
215
|
+
}
|
|
216
|
+
function isInvocationLike(value) {
|
|
217
|
+
return value !== null;
|
|
218
|
+
}
|
|
219
|
+
function readJsonPointer(root, pointer) {
|
|
220
|
+
if (pointer === "") {
|
|
221
|
+
return root;
|
|
222
|
+
}
|
|
223
|
+
if (!pointer.startsWith("/")) {
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
let current = root;
|
|
227
|
+
for (const rawSegment of pointer.slice(1).split("/")) {
|
|
228
|
+
const segment = decodeJsonPointerSegment(rawSegment);
|
|
229
|
+
if (Array.isArray(current)) {
|
|
230
|
+
const index = Number(segment);
|
|
231
|
+
if (!Number.isInteger(index) || index < 0 || index >= current.length) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
current = current[index];
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (!current || typeof current !== "object") {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
current = current[segment];
|
|
241
|
+
}
|
|
242
|
+
return current;
|
|
243
|
+
}
|
|
244
|
+
function readJsonPointerParent(root, pointer) {
|
|
245
|
+
if (!pointer.startsWith("/") || pointer === "") {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const rawSegments = pointer.slice(1).split("/");
|
|
249
|
+
const last = decodeJsonPointerSegment(rawSegments.pop());
|
|
250
|
+
const parent = readJsonPointer(root, rawSegments.length === 0 ? "" : `/${rawSegments.join("/")}`);
|
|
251
|
+
if (Array.isArray(parent)) {
|
|
252
|
+
const index = Number(last);
|
|
253
|
+
return Number.isInteger(index) && index >= 0 && index < parent.length
|
|
254
|
+
? { container: parent, key: index }
|
|
255
|
+
: null;
|
|
256
|
+
}
|
|
257
|
+
if (parent && typeof parent === "object") {
|
|
258
|
+
return { container: parent, key: last };
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
function decodeJsonPointerSegment(segment) {
|
|
263
|
+
return segment.replace(/~1/gu, "/").replace(/~0/gu, "~");
|
|
264
|
+
}
|
|
265
|
+
function cloneJson(value) {
|
|
266
|
+
return JSON.parse(JSON.stringify(value));
|
|
267
|
+
}
|
|
268
|
+
function readAdapterId(value, label) {
|
|
269
|
+
if (typeof value !== "string" || !/^[a-z][a-z0-9-]*$/u.test(value)) {
|
|
270
|
+
throw new Error(`${label} must be a lowercase adapter id.`);
|
|
271
|
+
}
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
function rejectUnknownManifestKeys(record, label, allowed) {
|
|
275
|
+
const extras = Object.keys(record).filter((key) => !allowed.includes(key));
|
|
276
|
+
if (extras.length > 0) {
|
|
277
|
+
throw new Error(`${label} includes unsupported ${extras.length === 1 ? "field" : "fields"}: ${extras.join(", ")}.`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function readStringArray(value, label) {
|
|
281
|
+
if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string" && entry.trim().length > 0)) {
|
|
282
|
+
throw new Error(`${label} must be a list of non-empty strings.`);
|
|
283
|
+
}
|
|
284
|
+
return value.map((entry) => entry.trim());
|
|
285
|
+
}
|
|
286
|
+
function readAdapterRefs(value, label) {
|
|
287
|
+
const refs = readStringArray(value, label);
|
|
288
|
+
for (const ref of refs) {
|
|
289
|
+
if (ref !== "" && !ref.startsWith("/")) {
|
|
290
|
+
throw new Error(`${label} entries must be JSON pointers.`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return refs;
|
|
294
|
+
}
|
|
295
|
+
function readAuth(value, label) {
|
|
296
|
+
if (value === undefined) {
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
300
|
+
throw new Error(`${label} must be an object.`);
|
|
301
|
+
}
|
|
302
|
+
const record = value;
|
|
303
|
+
rejectUnknownManifestKeys(record, label, ["methods", "slots"]);
|
|
304
|
+
const methods = record.methods === undefined
|
|
305
|
+
? undefined
|
|
306
|
+
: readAuthMethods(record.methods, `${label}.methods`);
|
|
307
|
+
const slots = record.slots === undefined
|
|
308
|
+
? undefined
|
|
309
|
+
: readAuthSlots(record.slots, `${label}.slots`);
|
|
310
|
+
if (methods && slots) {
|
|
311
|
+
throw new Error(`${label} must use either methods or slots, not both.`);
|
|
312
|
+
}
|
|
313
|
+
if (!methods && !slots) {
|
|
314
|
+
throw new Error(`${label} must declare methods or slots.`);
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
...(methods ? { methods } : {}),
|
|
318
|
+
...(slots ? { slots } : {}),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function readAuthSlots(value, label) {
|
|
322
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
323
|
+
throw new Error(`${label} must be an object.`);
|
|
324
|
+
}
|
|
325
|
+
const slots = {};
|
|
326
|
+
for (const [slot, config] of Object.entries(value).sort()) {
|
|
327
|
+
if (!/^[a-z][a-z0-9-]*$/u.test(slot)) {
|
|
328
|
+
throw new Error(`${label} keys must be lowercase auth slot names.`);
|
|
329
|
+
}
|
|
330
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
331
|
+
throw new Error(`${label}.${slot} must be an object.`);
|
|
332
|
+
}
|
|
333
|
+
const record = config;
|
|
334
|
+
rejectUnknownManifestKeys(record, `${label}.${slot}`, ["methods"]);
|
|
335
|
+
const methods = readAuthMethods(record.methods, `${label}.${slot}.methods`);
|
|
336
|
+
slots[slot] = { methods };
|
|
337
|
+
}
|
|
338
|
+
if (Object.keys(slots).length === 0) {
|
|
339
|
+
throw new Error(`${label} must include at least one slot.`);
|
|
340
|
+
}
|
|
341
|
+
return slots;
|
|
342
|
+
}
|
|
343
|
+
function readAuthMethods(value, label) {
|
|
344
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
345
|
+
throw new Error(`${label} must be an object.`);
|
|
346
|
+
}
|
|
347
|
+
const methods = {};
|
|
348
|
+
for (const [method, config] of Object.entries(value).sort()) {
|
|
349
|
+
if (!/^[a-z][a-z0-9-]*$/u.test(method)) {
|
|
350
|
+
throw new Error(`${label} keys must be lowercase auth method names.`);
|
|
351
|
+
}
|
|
352
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
353
|
+
throw new Error(`${label}.${method} must be an object.`);
|
|
354
|
+
}
|
|
355
|
+
methods[method] = readAuthMethod(config, `${label}.${method}`);
|
|
356
|
+
}
|
|
357
|
+
if (Object.keys(methods).length === 0) {
|
|
358
|
+
throw new Error(`${label} must include at least one method.`);
|
|
359
|
+
}
|
|
360
|
+
return methods;
|
|
361
|
+
}
|
|
362
|
+
function readAuthMethod(record, label) {
|
|
363
|
+
rejectUnknownManifestKeys(record, label, ["env", "files", "command"]);
|
|
364
|
+
const env = record.env === undefined
|
|
365
|
+
? undefined
|
|
366
|
+
: readAuthEnv(record.env, `${label}.env`);
|
|
367
|
+
const files = record.files === undefined
|
|
368
|
+
? undefined
|
|
369
|
+
: readAuthFiles(record.files, `${label}.files`);
|
|
370
|
+
const command = record.command === undefined
|
|
371
|
+
? undefined
|
|
372
|
+
: readNonEmptyString(record.command, `${label}.command`);
|
|
373
|
+
if (!env && !files && !command) {
|
|
374
|
+
throw new Error(`${label} must declare env, files, or command.`);
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
...(env ? { env } : {}),
|
|
378
|
+
...(files ? { files } : {}),
|
|
379
|
+
...(command ? { command } : {}),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function readAuthFiles(value, label) {
|
|
383
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
384
|
+
throw new Error(`${label} must be a non-empty list.`);
|
|
385
|
+
}
|
|
386
|
+
return value.map((entry, index) => {
|
|
387
|
+
if (typeof entry === "string") {
|
|
388
|
+
return { path: readAuthFilePath(entry, `${label}[${index}]`) };
|
|
389
|
+
}
|
|
390
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
391
|
+
throw new Error(`${label}[${index}] must be a file path or object.`);
|
|
392
|
+
}
|
|
393
|
+
const record = entry;
|
|
394
|
+
rejectUnknownManifestKeys(record, `${label}[${index}]`, ["path", "required"]);
|
|
395
|
+
return {
|
|
396
|
+
path: readAuthFilePath(record.path, `${label}[${index}].path`),
|
|
397
|
+
...readRequiredFlag(record.required, `${label}[${index}].required`),
|
|
398
|
+
};
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function readAuthEnv(value, label) {
|
|
402
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
403
|
+
throw new Error(`${label} must be a non-empty list.`);
|
|
404
|
+
}
|
|
405
|
+
return value.map((entry, index) => {
|
|
406
|
+
if (typeof entry === "string") {
|
|
407
|
+
return { name: readAuthEnvName(entry, `${label}[${index}]`) };
|
|
408
|
+
}
|
|
409
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
410
|
+
throw new Error(`${label}[${index}] must be an env name or object.`);
|
|
411
|
+
}
|
|
412
|
+
const record = entry;
|
|
413
|
+
rejectUnknownManifestKeys(record, `${label}[${index}]`, ["name", "required"]);
|
|
414
|
+
return {
|
|
415
|
+
name: readAuthEnvName(record.name, `${label}[${index}].name`),
|
|
416
|
+
...readRequiredFlag(record.required, `${label}[${index}].required`),
|
|
417
|
+
};
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function readRequiredFlag(value, label) {
|
|
421
|
+
if (value === undefined || value === true) {
|
|
422
|
+
return {};
|
|
423
|
+
}
|
|
424
|
+
if (value === false) {
|
|
425
|
+
return { required: false };
|
|
426
|
+
}
|
|
427
|
+
throw new Error(`${label} must be a boolean.`);
|
|
428
|
+
}
|
|
429
|
+
function readAuthEnvName(value, label) {
|
|
430
|
+
const name = readNonEmptyString(value, label);
|
|
431
|
+
if (!/^[A-Z_][A-Z0-9_]*$/u.test(name)) {
|
|
432
|
+
throw new Error(`${label} must be an environment variable name.`);
|
|
433
|
+
}
|
|
434
|
+
return name;
|
|
435
|
+
}
|
|
436
|
+
function readAuthFilePath(value, label) {
|
|
437
|
+
const filePath = readNonEmptyString(value, label).replace(/\\/gu, "/").replace(/^\/+/u, "");
|
|
438
|
+
if (!filePath || filePath.split("/").some((part) => part === "." || part === ".." || part === "")) {
|
|
439
|
+
throw new Error(`${label} must be a safe relative file path.`);
|
|
440
|
+
}
|
|
441
|
+
return filePath;
|
|
442
|
+
}
|
|
443
|
+
function readNonEmptyString(value, label) {
|
|
444
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
445
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
446
|
+
}
|
|
447
|
+
return value.trim();
|
|
448
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Json, UsageSummary, WorkbenchExecutionSpec } from "@workbench-ai/workbench-contract";
|
|
2
|
+
export interface WorkbenchAdapterCommandRequest {
|
|
3
|
+
protocol: "workbench.adapter.v1";
|
|
4
|
+
execution: {
|
|
5
|
+
id: string;
|
|
6
|
+
jobId?: string;
|
|
7
|
+
purpose: WorkbenchExecutionSpec["purpose"];
|
|
8
|
+
role: "optimizer" | "runner" | "grader";
|
|
9
|
+
candidateId?: string;
|
|
10
|
+
trialIndex?: number;
|
|
11
|
+
sampleIndex?: number;
|
|
12
|
+
caseId?: string;
|
|
13
|
+
};
|
|
14
|
+
adapter: {
|
|
15
|
+
use: string;
|
|
16
|
+
with?: Json;
|
|
17
|
+
auth?: Json;
|
|
18
|
+
};
|
|
19
|
+
auth?: Json;
|
|
20
|
+
benchmark?: {
|
|
21
|
+
name?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
};
|
|
24
|
+
candidate?: {
|
|
25
|
+
path?: string;
|
|
26
|
+
};
|
|
27
|
+
optimizer?: {
|
|
28
|
+
edits?: string[];
|
|
29
|
+
};
|
|
30
|
+
task?: {
|
|
31
|
+
text?: string;
|
|
32
|
+
};
|
|
33
|
+
expectedOutputs?: Array<{
|
|
34
|
+
name?: string;
|
|
35
|
+
path?: string;
|
|
36
|
+
}>;
|
|
37
|
+
paths: {
|
|
38
|
+
workspace: string;
|
|
39
|
+
input?: string;
|
|
40
|
+
output: string;
|
|
41
|
+
candidate?: string;
|
|
42
|
+
task?: string;
|
|
43
|
+
runnerOutput?: string;
|
|
44
|
+
traces?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface WorkbenchAdapterResultMetadata {
|
|
48
|
+
ok?: boolean;
|
|
49
|
+
summary?: string;
|
|
50
|
+
feedback?: Json;
|
|
51
|
+
usage?: UsageSummary;
|
|
52
|
+
}
|
|
53
|
+
export declare function readWorkbenchAdapterCommandRequest(configuredPath?: string): Promise<WorkbenchAdapterCommandRequest>;
|
|
54
|
+
export declare function normalizeWorkbenchAdapterCommandRequest(value: unknown): WorkbenchAdapterCommandRequest;
|
|
55
|
+
export declare function ensureWorkbenchAdapterOutputDir(request: WorkbenchAdapterCommandRequest): Promise<void>;
|
|
56
|
+
export declare function workbenchAdapterResultPath(outputRoot: string): string;
|
|
57
|
+
export declare function writeWorkbenchAdapterResultMetadata(outputRoot: string, result: WorkbenchAdapterResultMetadata): Promise<void>;
|
|
58
|
+
export declare function readWorkbenchAdapterResultMetadata(outputRoot: string): Promise<WorkbenchAdapterResultMetadata>;
|
|
59
|
+
//# sourceMappingURL=adapter-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-protocol.d.ts","sourceRoot":"","sources":["../src/adapter-protocol.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,IAAI,EACJ,YAAY,EACZ,sBAAsB,EACvB,MAAM,kCAAkC,CAAC;AAE1C,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,sBAAsB,CAAC;IACjC,SAAS,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;QACxC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,IAAI,CAAC,EAAE,IAAI,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,SAAS,CAAC,EAAE;QACV,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,8BAA8B;IAC7C,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,wBAAsB,kCAAkC,CACtD,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,8BAA8B,CAAC,CAOzC;AAED,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,OAAO,GACb,8BAA8B,CA8ChC;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAsB,mCAAmC,CACvD,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,kCAAkC,CACtD,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,8BAA8B,CAAC,CAkBzC"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export async function readWorkbenchAdapterCommandRequest(configuredPath) {
|
|
4
|
+
const requestPath = configuredPath ?? process.env.WORKBENCH_ADAPTER_REQUEST;
|
|
5
|
+
if (!requestPath) {
|
|
6
|
+
throw new Error("WORKBENCH_ADAPTER_REQUEST is required.");
|
|
7
|
+
}
|
|
8
|
+
const parsed = JSON.parse(await fs.readFile(requestPath, "utf8"));
|
|
9
|
+
return normalizeWorkbenchAdapterCommandRequest(parsed);
|
|
10
|
+
}
|
|
11
|
+
export function normalizeWorkbenchAdapterCommandRequest(value) {
|
|
12
|
+
const record = requiredJsonRecord(value, "adapter request");
|
|
13
|
+
if (record.protocol !== "workbench.adapter.v1") {
|
|
14
|
+
throw new Error("Adapter request protocol must be workbench.adapter.v1.");
|
|
15
|
+
}
|
|
16
|
+
const execution = requiredJsonRecord(record.execution, "adapter request execution");
|
|
17
|
+
const adapter = requiredJsonRecord(record.adapter, "adapter request adapter");
|
|
18
|
+
const paths = requiredJsonRecord(record.paths, "adapter request paths");
|
|
19
|
+
const purpose = requiredPurpose(execution.purpose, "adapter request execution.purpose");
|
|
20
|
+
const role = executionPurposeRole(purpose);
|
|
21
|
+
const use = requiredString(adapter.use, "adapter request adapter.use");
|
|
22
|
+
return {
|
|
23
|
+
protocol: "workbench.adapter.v1",
|
|
24
|
+
execution: {
|
|
25
|
+
id: requiredString(execution.id, "adapter request execution.id"),
|
|
26
|
+
...(typeof execution.jobId === "string" ? { jobId: execution.jobId } : {}),
|
|
27
|
+
purpose,
|
|
28
|
+
role,
|
|
29
|
+
...(typeof execution.candidateId === "string" ? { candidateId: execution.candidateId } : {}),
|
|
30
|
+
...(typeof execution.trialIndex === "number" ? { trialIndex: execution.trialIndex } : {}),
|
|
31
|
+
...(typeof execution.sampleIndex === "number" ? { sampleIndex: execution.sampleIndex } : {}),
|
|
32
|
+
...(typeof execution.caseId === "string" ? { caseId: execution.caseId } : {}),
|
|
33
|
+
},
|
|
34
|
+
adapter: {
|
|
35
|
+
use,
|
|
36
|
+
with: adapter.with !== undefined ? adapter.with : {},
|
|
37
|
+
...(adapter.auth !== undefined ? { auth: adapter.auth } : {}),
|
|
38
|
+
},
|
|
39
|
+
...(record.auth !== undefined ? { auth: record.auth } : {}),
|
|
40
|
+
...(record.benchmark !== undefined ? { benchmark: normalizeAdapterCommandBenchmark(record.benchmark) } : {}),
|
|
41
|
+
...(record.candidate !== undefined ? { candidate: normalizeAdapterCommandCandidate(record.candidate) } : {}),
|
|
42
|
+
...(record.optimizer !== undefined ? { optimizer: normalizeAdapterCommandOptimizer(record.optimizer) } : {}),
|
|
43
|
+
...(record.task !== undefined ? { task: normalizeAdapterCommandTask(record.task) } : {}),
|
|
44
|
+
...(Array.isArray(record.expectedOutputs)
|
|
45
|
+
? { expectedOutputs: normalizeAdapterCommandExpectedOutputs(record.expectedOutputs) }
|
|
46
|
+
: {}),
|
|
47
|
+
paths: {
|
|
48
|
+
workspace: requiredString(paths.workspace, "adapter request paths.workspace"),
|
|
49
|
+
output: requiredString(paths.output, "adapter request paths.output"),
|
|
50
|
+
...(typeof paths.input === "string" ? { input: paths.input } : {}),
|
|
51
|
+
...(typeof paths.candidate === "string" ? { candidate: paths.candidate } : {}),
|
|
52
|
+
...(typeof paths.task === "string" ? { task: paths.task } : {}),
|
|
53
|
+
...(typeof paths.runnerOutput === "string" ? { runnerOutput: paths.runnerOutput } : {}),
|
|
54
|
+
...(typeof paths.traces === "string" ? { traces: paths.traces } : {}),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function ensureWorkbenchAdapterOutputDir(request) {
|
|
59
|
+
await fs.mkdir(request.paths.output, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
export function workbenchAdapterResultPath(outputRoot) {
|
|
62
|
+
return path.join(outputRoot, ".workbench", "result.json");
|
|
63
|
+
}
|
|
64
|
+
export async function writeWorkbenchAdapterResultMetadata(outputRoot, result) {
|
|
65
|
+
const resultPath = workbenchAdapterResultPath(outputRoot);
|
|
66
|
+
await fs.mkdir(path.dirname(resultPath), { recursive: true });
|
|
67
|
+
await fs.writeFile(resultPath, `${JSON.stringify(result, null, 2)}\n`);
|
|
68
|
+
}
|
|
69
|
+
export async function readWorkbenchAdapterResultMetadata(outputRoot) {
|
|
70
|
+
const source = await fs.readFile(workbenchAdapterResultPath(outputRoot), "utf8").catch((error) => {
|
|
71
|
+
if (error.code === "ENOENT") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
});
|
|
76
|
+
if (source === null) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
const parsed = JSON.parse(source);
|
|
80
|
+
const record = jsonRecord(parsed);
|
|
81
|
+
return {
|
|
82
|
+
...(record.ok === true || record.ok === false ? { ok: record.ok } : {}),
|
|
83
|
+
...(typeof record.summary === "string" ? { summary: record.summary } : {}),
|
|
84
|
+
...(record.feedback !== undefined ? { feedback: record.feedback } : {}),
|
|
85
|
+
...(record.usage !== undefined ? { usage: normalizeUsageSummary(record.usage) } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function normalizeAdapterCommandExpectedOutputs(value) {
|
|
89
|
+
return value.flatMap((entry) => {
|
|
90
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
return [{
|
|
94
|
+
...(typeof entry.name === "string" ? { name: entry.name } : {}),
|
|
95
|
+
...(typeof entry.path === "string" ? { path: entry.path } : {}),
|
|
96
|
+
}];
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function normalizeAdapterCommandBenchmark(value) {
|
|
100
|
+
const record = requiredJsonRecord(value, "adapter request benchmark");
|
|
101
|
+
return {
|
|
102
|
+
...(typeof record.name === "string" ? { name: record.name } : {}),
|
|
103
|
+
...(typeof record.description === "string" ? { description: record.description } : {}),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function normalizeAdapterCommandCandidate(value) {
|
|
107
|
+
const record = requiredJsonRecord(value, "adapter request candidate");
|
|
108
|
+
return {
|
|
109
|
+
...(typeof record.path === "string" ? { path: record.path } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function normalizeAdapterCommandOptimizer(value) {
|
|
113
|
+
const record = requiredJsonRecord(value, "adapter request optimizer");
|
|
114
|
+
return {
|
|
115
|
+
edits: Array.isArray(record.edits)
|
|
116
|
+
? record.edits.filter((entry) => typeof entry === "string")
|
|
117
|
+
: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function normalizeAdapterCommandTask(value) {
|
|
121
|
+
const record = requiredJsonRecord(value, "adapter request task");
|
|
122
|
+
return {
|
|
123
|
+
...(typeof record.text === "string" ? { text: record.text } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function requiredJsonRecord(value, label) {
|
|
127
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
128
|
+
throw new Error(`${label} must be an object.`);
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
function requiredPurpose(value, label) {
|
|
133
|
+
if (value === "improve" || value === "run-task" || value === "grade-task") {
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`${label} must be improve, run-task, or grade-task.`);
|
|
137
|
+
}
|
|
138
|
+
function requiredString(value, label) {
|
|
139
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
140
|
+
throw new Error(`${label} is required.`);
|
|
141
|
+
}
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
function executionPurposeRole(purpose) {
|
|
145
|
+
if (purpose === "improve") {
|
|
146
|
+
return "optimizer";
|
|
147
|
+
}
|
|
148
|
+
if (purpose === "run-task") {
|
|
149
|
+
return "runner";
|
|
150
|
+
}
|
|
151
|
+
return "grader";
|
|
152
|
+
}
|
|
153
|
+
function jsonRecord(value) {
|
|
154
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
155
|
+
? value
|
|
156
|
+
: {};
|
|
157
|
+
}
|
|
158
|
+
function normalizeUsageSummary(value) {
|
|
159
|
+
const record = jsonRecord(value);
|
|
160
|
+
return {
|
|
161
|
+
...(record.total !== undefined ? { total: normalizeExecutionUsage(record.total) } : {}),
|
|
162
|
+
...(record.optimizer !== undefined ? { optimizer: normalizeExecutionUsage(record.optimizer) } : {}),
|
|
163
|
+
...(record.runner !== undefined ? { runner: normalizeExecutionUsage(record.runner) } : {}),
|
|
164
|
+
...(record.grader !== undefined ? { grader: normalizeExecutionUsage(record.grader) } : {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function normalizeExecutionUsage(value) {
|
|
168
|
+
const record = jsonRecord(value);
|
|
169
|
+
return {
|
|
170
|
+
...(typeof record.provider === "string" ? { provider: record.provider } : {}),
|
|
171
|
+
...(typeof record.model === "string" ? { model: record.model } : {}),
|
|
172
|
+
...(typeof record.inputTokens === "number" ? { inputTokens: record.inputTokens } : {}),
|
|
173
|
+
...(typeof record.uncachedInputTokens === "number" ? { uncachedInputTokens: record.uncachedInputTokens } : {}),
|
|
174
|
+
...(typeof record.cachedInputTokens === "number" ? { cachedInputTokens: record.cachedInputTokens } : {}),
|
|
175
|
+
...(typeof record.cacheCreationInputTokens === "number" ? { cacheCreationInputTokens: record.cacheCreationInputTokens } : {}),
|
|
176
|
+
...(typeof record.cacheReadInputTokens === "number" ? { cacheReadInputTokens: record.cacheReadInputTokens } : {}),
|
|
177
|
+
...(typeof record.outputTokens === "number" ? { outputTokens: record.outputTokens } : {}),
|
|
178
|
+
...(typeof record.reasoningOutputTokens === "number" ? { reasoningOutputTokens: record.reasoningOutputTokens } : {}),
|
|
179
|
+
...(typeof record.totalTokens === "number" ? { totalTokens: record.totalTokens } : {}),
|
|
180
|
+
...(typeof record.costUsd === "number" ? { costUsd: record.costUsd } : {}),
|
|
181
|
+
...(record.costSource === "provider" || record.costSource === "estimated" || record.costSource === "mixed"
|
|
182
|
+
? { costSource: record.costSource }
|
|
183
|
+
: {}),
|
|
184
|
+
...(typeof record.pricingSource === "string" ? { pricingSource: record.pricingSource } : {}),
|
|
185
|
+
};
|
|
186
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { adapterCommandName, cloneWorkbenchAdapterManifest, collectWorkbenchAdapterAuthRequirements, collectWorkbenchAdapterInvocations, parseWorkbenchAdapterManifest, workbenchAdapterManifestRequiresAuth, withDefaultWorkbenchAdapterAuth, withDefaultWorkbenchAdapterAuthProfiles, type WorkbenchAdapterAuthEnvManifest, type WorkbenchAdapterAuthFileManifest, type WorkbenchAdapterAuthManifest, type WorkbenchAdapterAuthMethodManifest, type WorkbenchAdapterAuthRequirement, type WorkbenchAdapterInvocationLike, type WorkbenchAdapterManifest, } from "./adapter-manifest.ts";
|
|
2
|
+
export { ensureWorkbenchAdapterOutputDir, normalizeWorkbenchAdapterCommandRequest, readWorkbenchAdapterCommandRequest, readWorkbenchAdapterResultMetadata, workbenchAdapterResultPath, writeWorkbenchAdapterResultMetadata, type WorkbenchAdapterCommandRequest, type WorkbenchAdapterResultMetadata, } from "./adapter-protocol.ts";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,uCAAuC,EACvC,kCAAkC,EAClC,6BAA6B,EAC7B,oCAAoC,EACpC,+BAA+B,EAC/B,uCAAuC,EACvC,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,4BAA4B,EACjC,KAAK,kCAAkC,EACvC,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,+BAA+B,EAC/B,uCAAuC,EACvC,kCAAkC,EAClC,kCAAkC,EAClC,0BAA0B,EAC1B,mCAAmC,EACnC,KAAK,8BAA8B,EACnC,KAAK,8BAA8B,GACpC,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { adapterCommandName, cloneWorkbenchAdapterManifest, collectWorkbenchAdapterAuthRequirements, collectWorkbenchAdapterInvocations, parseWorkbenchAdapterManifest, workbenchAdapterManifestRequiresAuth, withDefaultWorkbenchAdapterAuth, withDefaultWorkbenchAdapterAuthProfiles, } from "./adapter-manifest.js";
|
|
2
|
+
export { ensureWorkbenchAdapterOutputDir, normalizeWorkbenchAdapterCommandRequest, readWorkbenchAdapterCommandRequest, readWorkbenchAdapterResultMetadata, workbenchAdapterResultPath, writeWorkbenchAdapterResultMetadata, } from "./adapter-protocol.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workbench-ai/workbench-protocol",
|
|
3
|
+
"version": "0.0.40",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"yaml": "^2.8.2",
|
|
18
|
+
"@workbench-ai/workbench-contract": "0.0.40"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^24.3.1",
|
|
22
|
+
"typescript": "^5.9.2",
|
|
23
|
+
"vitest": "^3.2.4"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"registry": "https://registry.npmjs.org/",
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
31
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
32
|
+
"test": "vitest run --config vitest.config.ts"
|
|
33
|
+
}
|
|
34
|
+
}
|