maka-agent 0.2.0-dev.4.20260830 → 0.2.0-dev.5.20260830

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 (44) hide show
  1. package/dist/eval-bundle-path.js +1 -1
  2. package/dist/pi-tui-runner.js +3 -1
  3. package/dist/runtime-host-onboarding.js +10 -1
  4. package/dist/runtime-host-tui-context.js +2 -6
  5. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  6. package/node_modules/@maka/eval/dist/external-subject.js +1 -1
  7. package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -2
  8. package/package.json +1 -2
  9. package/packages/eval/dist/attempt-store.js +0 -138
  10. package/packages/eval/dist/cli.js +0 -119
  11. package/packages/eval/dist/experiment-directory.js +0 -59
  12. package/packages/eval/dist/experiment.js +0 -49
  13. package/packages/eval/dist/external-subject.js +0 -488
  14. package/packages/eval/dist/harbor-external-subject.js +0 -929
  15. package/packages/eval/dist/harbor-maka-subject.js +0 -83
  16. package/packages/eval/dist/harness-environment.js +0 -80
  17. package/packages/eval/dist/harness-executor.js +0 -1013
  18. package/packages/eval/dist/index.js +0 -28
  19. package/packages/eval/dist/install-preflight.js +0 -201
  20. package/packages/eval/dist/maka-artifacts.js +0 -126
  21. package/packages/eval/dist/maka-runtime-policy.js +0 -42
  22. package/packages/eval/dist/maka-subject.js +0 -268
  23. package/packages/eval/dist/metering-checkpoint.js +0 -80
  24. package/packages/eval/dist/provider-admission.js +0 -39
  25. package/packages/eval/dist/provider-metering.js +0 -67
  26. package/packages/eval/dist/provider-web-tool-surface.js +0 -74
  27. package/packages/eval/dist/relay-result-frame.js +0 -38
  28. package/packages/eval/dist/result.js +0 -94
  29. package/packages/eval/dist/runner.js +0 -290
  30. package/packages/eval/dist/spec.js +0 -135
  31. package/packages/eval/dist/toolchain-verification.js +0 -130
  32. package/packages/eval/harbor/deepseek-codex-models.json +0 -69
  33. package/packages/eval/harbor/deepseek-harness-profile/cordis.patch.yml +0 -140
  34. package/packages/eval/harbor/deepseek-harness-profile/cordis.yml +0 -18
  35. package/packages/eval/harbor/deepseek-harness-profile/package.json +0 -10
  36. package/packages/eval/harbor/docker-compose-egress-proxy.yaml +0 -57
  37. package/packages/eval/harbor/egress-proxy/Dockerfile +0 -25
  38. package/packages/eval/harbor/egress-proxy/entrypoint.sh +0 -62
  39. package/packages/eval/harbor/egress-proxy/network-policy +0 -148
  40. package/packages/eval/harbor/egress_filter.py +0 -435
  41. package/packages/eval/harbor/eval_framework.py +0 -40
  42. package/packages/eval/harbor/relay_agent.py +0 -686
  43. package/packages/eval/harbor/run_trial.py +0 -223
  44. package/packages/eval/package.json +0 -20
@@ -23,7 +23,7 @@ export function configureInstalledEvalBundle(environment = process.env, packageR
23
23
  if (Object.hasOwn(environment, MAKA_EVAL_BUNDLE_ENV))
24
24
  return;
25
25
  try {
26
- if (!statSync(resolve(packageRoot, 'packages/eval')).isDirectory())
26
+ if (!statSync(resolve(packageRoot, 'node_modules/@maka/eval')).isDirectory())
27
27
  return;
28
28
  }
29
29
  catch {
@@ -870,6 +870,7 @@ export async function runMakaPiTui(input) {
870
870
  // in place after `/setup` saves so newly configured models are immediately
871
871
  // available — the single source the picker and connection/model lookups read.
872
872
  let modelChoices = input.modelChoices;
873
+ let connectionIdentities = input.connectionIdentities;
873
874
  // Monotonic attempt id: each setup submit captures one, and any transition
874
875
  // that abandons the in-flight attempt (back, re-pick, close) increments it so
875
876
  // a late verify/save settlement cannot clobber a newer attempt.
@@ -1142,7 +1143,7 @@ export async function runMakaPiTui(input) {
1142
1143
  model = summary.model;
1143
1144
  connectionId = summary.llmConnectionId;
1144
1145
  connectionSlug = summary.llmConnectionSlug;
1145
- const identityNotice = sessionConnectionIdentityNotice(summary, input.connectionIdentities, input.locale ?? 'en');
1146
+ const identityNotice = sessionConnectionIdentityNotice(summary, connectionIdentities, input.locale ?? 'en');
1146
1147
  if (announceIdentity && identityNotice && identityNotice !== connectionIdentityNotice) {
1147
1148
  state.entries.push({ kind: 'notice', level: 'error', text: identityNotice });
1148
1149
  }
@@ -1832,6 +1833,7 @@ export async function runMakaPiTui(input) {
1832
1833
  // attempt must not overwrite choices refreshed by a newer save.
1833
1834
  if (result.refresh.kind === 'ok') {
1834
1835
  modelChoices = result.refresh.modelChoices;
1836
+ connectionIdentities = result.refresh.connectionIdentities;
1835
1837
  }
1836
1838
  if (input.firstRun) {
1837
1839
  beginClose();
@@ -50,12 +50,14 @@ export function createRuntimeHostOnboardingSurface(connection) {
50
50
  return result;
51
51
  }
52
52
  try {
53
+ const catalog = await readRuntimeHostConnectionCatalog(connection);
53
54
  return {
54
55
  kind: 'ok',
55
56
  connection: result.connection,
56
57
  refresh: {
57
58
  kind: 'ok',
58
- modelChoices: projectRuntimeHostModelChoices(await readRuntimeHostConnectionCatalog(connection)),
59
+ modelChoices: projectRuntimeHostModelChoices(catalog),
60
+ connectionIdentities: projectRuntimeHostConnectionIdentities(catalog),
59
61
  },
60
62
  };
61
63
  }
@@ -108,6 +110,13 @@ export function projectRuntimeHostModelChoices(catalog) {
108
110
  }
109
111
  return choices;
110
112
  }
113
+ export function projectRuntimeHostConnectionIdentities(catalog) {
114
+ return catalog.connections.map((connection) => ({
115
+ connectionId: connection.connectionId,
116
+ connectionSlug: connection.slug,
117
+ enabled: connection.enabled,
118
+ }));
119
+ }
111
120
  export function projectProviders(catalog) {
112
121
  const entries = [];
113
122
  for (const provider of listApiKeyOnboardableProviders()) {
@@ -26,7 +26,7 @@ import { readRuntimeHostAgentGraphEpochs, readRuntimeHostInvocableSkills, readRu
26
26
  import { runtimeHostProfileUsesHostWorkspace } from '@maka/runtime-host/profile-kind';
27
27
  import { connectRuntimeHostCli, readHostChatDefaultPermissionMode, resolveRuntimeHostCliTarget, } from './runtime-host-cli-context.js';
28
28
  import { createRuntimeHostMakaSessionDriver, } from './runtime-host-session-driver.js';
29
- import { createRuntimeHostOnboardingSurface, projectRuntimeHostModelChoices, } from './runtime-host-onboarding.js';
29
+ import { createRuntimeHostOnboardingSurface, projectRuntimeHostConnectionIdentities, projectRuntimeHostModelChoices, } from './runtime-host-onboarding.js';
30
30
  import { createTuiMcpController, } from './tui-mcp-control.js';
31
31
  export async function createRuntimeHostTuiContext(input) {
32
32
  const connected = await connectRuntimeHostCli({
@@ -88,11 +88,7 @@ export async function createRuntimeHostTuiContext(input) {
88
88
  ...(selectedTarget.connectionId === undefined
89
89
  ? {}
90
90
  : { connectionId: selectedTarget.connectionId }),
91
- connectionIdentities: catalog.connections.map((entry) => ({
92
- connectionId: entry.connectionId,
93
- connectionSlug: entry.slug,
94
- enabled: entry.enabled,
95
- })),
91
+ connectionIdentities: projectRuntimeHostConnectionIdentities(catalog),
96
92
  connectionName: selectedTarget.connection?.name ?? selectedTarget.connectionSlug,
97
93
  ...(selectedTarget.connection
98
94
  ? { providerType: selectedTarget.connection.providerType }
@@ -21,7 +21,7 @@ import { join } from 'node:path';
21
21
  import { meteringCheckpointMacMatches, readBoundedRegularFile } from './metering-checkpoint.js';
22
22
  import { deriveMetering } from './provider-metering.js';
23
23
  import { TOOLCHAIN_IDENTITIES, TOOLCHAIN_IDENTITY_ENV, isExternalProfile, verifyToolchainDirectory, } from './toolchain-verification.js';
24
- const BUNDLED_EXTERNAL_WRAPPER = '/opt/maka-agent/packages/eval/dist/harbor-external-subject.js';
24
+ const BUNDLED_EXTERNAL_WRAPPER = '/opt/maka-agent/node_modules/@maka/eval/dist/harbor-external-subject.js';
25
25
  export function createExternalSubjectAdapter() {
26
26
  const verifiedToolchains = new Map();
27
27
  return {
@@ -44,7 +44,7 @@ const PROFILE_PREPARERS = {
44
44
  codex: async ({ env, home, root, proxyBaseUrl }) => {
45
45
  env.OPENAI_API_KEY = 'maka-eval-local';
46
46
  env.CODEX_HOME = home;
47
- const catalog = rooted(root, '/opt/maka-agent/packages/eval/harbor/deepseek-codex-models.json');
47
+ const catalog = rooted(root, '/opt/maka-agent/node_modules/@maka/eval/harbor/deepseek-codex-models.json');
48
48
  await writeFile(join(home, 'config.toml'), [
49
49
  'model_provider = "maka-http"',
50
50
  `model_catalog_json = ${JSON.stringify(catalog)}`,
@@ -198,7 +198,7 @@ const PROFILE_PREPARERS = {
198
198
  env.DSH_HOME = join(home, 'dsh');
199
199
  const profile = join(env.DSH_HOME, 'profiles', DEEPSEEK_HARNESS_PROFILE);
200
200
  await mkdir(profile, { recursive: true, mode: 0o700 });
201
- const source = rooted(root, '/opt/maka-agent/packages/eval/harbor/deepseek-harness-profile');
201
+ const source = rooted(root, '/opt/maka-agent/node_modules/@maka/eval/harbor/deepseek-harness-profile');
202
202
  for (const file of ['package.json', 'cordis.yml', 'cordis.patch.yml']) {
203
203
  await copyFile(join(source, file), join(profile, file));
204
204
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maka-agent",
3
- "version": "0.2.0-dev.4.20260830",
3
+ "version": "0.2.0-dev.5.20260830",
4
4
  "description": "Apache Maka (Incubating) developer snapshot; not an Apache release.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -39,7 +39,6 @@
39
39
  "files": [
40
40
  "dist",
41
41
  "native",
42
- "packages/eval",
43
42
  "README.md",
44
43
  "README.zh-CN.md",
45
44
  "LICENSE",
@@ -1,138 +0,0 @@
1
- /*
2
- * Licensed to the Apache Software Foundation (ASF) under one
3
- * or more contributor license agreements. See the NOTICE file
4
- * distributed with this work for additional information
5
- * regarding copyright ownership. The ASF licenses this file
6
- * to you under the Apache License, Version 2.0 (the
7
- * "License"); you may not use this file except in compliance
8
- * with the License. You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing,
13
- * software distributed under the License is distributed on an
14
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- * KIND, either express or implied. See the License for the
16
- * specific language governing permissions and limitations
17
- * under the License.
18
- */
19
- import { createHash, randomUUID } from 'node:crypto';
20
- import { link, mkdir, open, readFile, readdir, unlink } from 'node:fs/promises';
21
- import { join } from 'node:path';
22
- import { decodeEvalResult } from './result.js';
23
- export class FileAttemptStore {
24
- path;
25
- constructor(path) {
26
- this.path = path;
27
- }
28
- async runExclusive(operation) {
29
- await mkdir(this.path, { recursive: true });
30
- const path = join(this.path, '.writer.lock');
31
- let lock;
32
- try {
33
- lock = await open(path, 'wx', 0o600);
34
- }
35
- catch (error) {
36
- if (error.code === 'EEXIST') {
37
- throw new Error(`${path}: experiment already has an active writer`);
38
- }
39
- throw error;
40
- }
41
- try {
42
- return await operation();
43
- }
44
- finally {
45
- await lock.close();
46
- await unlink(path);
47
- }
48
- }
49
- async list(cellId) {
50
- const directory = this.#cellDirectory(cellId);
51
- let names;
52
- try {
53
- names = await readdir(directory);
54
- }
55
- catch (error) {
56
- if (error.code === 'ENOENT')
57
- return [];
58
- throw error;
59
- }
60
- const attempts = await Promise.all(names
61
- .filter((name) => /^\d{6}\.json$/u.test(name))
62
- .sort()
63
- .map(async (name) => {
64
- const attempt = decodeAttempt(JSON.parse(await readFile(join(directory, name), 'utf8')));
65
- const sequence = Number(name.slice(0, 6));
66
- if (attempt.cellId !== cellId || attempt.sequence !== sequence) {
67
- throw new Error('attempt file does not match its immutable identity');
68
- }
69
- return attempt;
70
- }));
71
- return attempts;
72
- }
73
- async append(attempt) {
74
- const record = decodeAttempt(attempt);
75
- const expected = ((await this.list(record.cellId)).at(-1)?.sequence ?? 0) + 1;
76
- if (record.sequence !== expected)
77
- throw new Error(`attempt sequence must be ${expected}`);
78
- const directory = this.#cellDirectory(record.cellId);
79
- await mkdir(directory, { recursive: true });
80
- const finalPath = join(directory, `${String(record.sequence).padStart(6, '0')}.json`);
81
- const temporaryPath = `${finalPath}.${randomUUID()}.tmp`;
82
- const temporary = await open(temporaryPath, 'wx', 0o600);
83
- try {
84
- await temporary.writeFile(`${JSON.stringify(record)}\n`);
85
- await temporary.sync();
86
- await temporary.close();
87
- await link(temporaryPath, finalPath);
88
- }
89
- finally {
90
- await temporary.close().catch(() => undefined);
91
- await unlink(temporaryPath).catch(() => undefined);
92
- }
93
- }
94
- #cellDirectory(cellId) {
95
- return join(this.path, createHash('sha256').update(cellId).digest('hex'));
96
- }
97
- }
98
- function decodeAttempt(value) {
99
- const attempt = exact(value, 'attempt', [
100
- 'cellId',
101
- 'sequence',
102
- 'startedAt',
103
- 'completedAt',
104
- 'result',
105
- ]);
106
- return {
107
- cellId: nonempty(attempt.cellId, 'attempt.cellId'),
108
- sequence: positiveInteger(attempt.sequence, 'attempt.sequence'),
109
- startedAt: nonnegative(attempt.startedAt, 'attempt.startedAt'),
110
- completedAt: nonnegative(attempt.completedAt, 'attempt.completedAt'),
111
- result: decodeEvalResult(attempt.result, 'attempt.result'),
112
- };
113
- }
114
- function exact(value, where, fields) {
115
- if (!value || typeof value !== 'object' || Array.isArray(value))
116
- throw new Error(`${where} must be an object`);
117
- const record = value;
118
- if (Object.keys(record).length !== fields.length ||
119
- fields.some((field) => !Object.hasOwn(record, field))) {
120
- throw new Error(`${where} fields are invalid`);
121
- }
122
- return record;
123
- }
124
- function nonempty(value, where) {
125
- if (typeof value !== 'string' || value.length === 0)
126
- throw new Error(`${where} is invalid`);
127
- return value;
128
- }
129
- function positiveInteger(value, where) {
130
- if (!Number.isSafeInteger(value) || value < 1)
131
- throw new Error(`${where} is invalid`);
132
- return value;
133
- }
134
- function nonnegative(value, where) {
135
- if (typeof value !== 'number' || !Number.isFinite(value) || value < 0)
136
- throw new Error(`${where} is invalid`);
137
- return value;
138
- }
@@ -1,119 +0,0 @@
1
- /*
2
- * Licensed to the Apache Software Foundation (ASF) under one
3
- * or more contributor license agreements. See the NOTICE file
4
- * distributed with this work for additional information
5
- * regarding copyright ownership. The ASF licenses this file
6
- * to you under the Apache License, Version 2.0 (the
7
- * "License"); you may not use this file except in compliance
8
- * with the License. You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing,
13
- * software distributed under the License is distributed on an
14
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- * KIND, either express or implied. See the License for the
16
- * specific language governing permissions and limitations
17
- * under the License.
18
- */
19
- import { readFile } from 'node:fs/promises';
20
- import { resolve } from 'node:path';
21
- import { createExternalSubjectAdapter } from './external-subject.js';
22
- import { createHarborExecutor, createPierExecutor, } from './harness-executor.js';
23
- import { openExperimentDirectory } from './experiment-directory.js';
24
- import { createMakaSubjectAdapter } from './maka-subject.js';
25
- import { runExperiment } from './runner.js';
26
- import { parseExperimentSpec } from './spec.js';
27
- const USAGE = 'usage: maka eval run <spec.json> --out <directory> [--cell <cell-id>]';
28
- export async function runMakaEvalCli(argv, overrides = {}) {
29
- const controller = overrides.signal ? undefined : new AbortController();
30
- const signal = overrides.signal ?? controller?.signal;
31
- let interrupted;
32
- const interrupt = () => {
33
- interrupted = 130;
34
- controller?.abort();
35
- };
36
- const terminate = () => {
37
- interrupted = 143;
38
- controller?.abort();
39
- };
40
- if (controller) {
41
- process.once('SIGINT', interrupt);
42
- process.once('SIGTERM', terminate);
43
- }
44
- try {
45
- const command = parseArgs(argv);
46
- if (command.kind === 'help') {
47
- (overrides.stdout ?? process.stdout.write.bind(process.stdout))(`${USAGE}\n`);
48
- return 0;
49
- }
50
- const specPath = resolve(command.specPath);
51
- const spec = parseExperimentSpec(JSON.parse(await readFile(specPath, 'utf8')));
52
- const directory = await openExperimentDirectory(resolve(command.outDir), spec);
53
- let executor;
54
- if (overrides.loadExecutor) {
55
- executor = overrides.loadExecutor(spec, specPath);
56
- }
57
- else {
58
- const builtin = builtinExecutor(spec, specPath);
59
- await builtin.preflight({
60
- subjectCredentialNames: [
61
- ...new Set(spec.subjects.flatMap((subject) => subject.credentials)),
62
- ],
63
- ...(signal ? { signal } : {}),
64
- });
65
- executor = builtin;
66
- }
67
- const results = await runExperiment({
68
- spec,
69
- store: directory.attempts,
70
- executor,
71
- subjects: overrides.subjects ?? [createMakaSubjectAdapter(), createExternalSubjectAdapter()],
72
- ...(command.cellIds.length > 0 ? { cellIds: command.cellIds } : {}),
73
- ...(signal ? { signal } : {}),
74
- });
75
- const incomplete = spec.tasks.length * spec.repetitions * spec.subjects.length - results.size;
76
- (overrides.stdout ?? process.stdout.write.bind(process.stdout))(`${JSON.stringify({ experimentId: spec.id, cells: results.size, incomplete })}\n`);
77
- return interrupted ?? (incomplete === 0 ? 0 : 1);
78
- }
79
- catch (error) {
80
- (overrides.stderr ?? process.stderr.write.bind(process.stderr))(`maka eval: ${error instanceof Error ? error.message : String(error)}\n${USAGE}\n`);
81
- return interrupted ?? 2;
82
- }
83
- finally {
84
- if (controller) {
85
- process.removeListener('SIGINT', interrupt);
86
- process.removeListener('SIGTERM', terminate);
87
- }
88
- }
89
- }
90
- function builtinExecutor(spec, specPath) {
91
- if (spec.executor.kind === 'harbor')
92
- return createHarborExecutor(spec.executor.config, specPath);
93
- if (spec.executor.kind === 'pier')
94
- return createPierExecutor(spec.executor.config, specPath);
95
- throw new Error(`unsupported executor: ${spec.executor.kind}`);
96
- }
97
- function parseArgs(argv) {
98
- if (argv.length === 1 && (argv[0] === '--help' || argv[0] === '-h'))
99
- return { kind: 'help' };
100
- if (argv[0] !== 'run' || !argv[1] || argv[1].startsWith('-'))
101
- throw new Error(USAGE);
102
- let outDir;
103
- const cellIds = [];
104
- for (let index = 2; index < argv.length; index += 2) {
105
- const flag = argv[index];
106
- const value = argv[index + 1];
107
- if (!value || value.startsWith('-'))
108
- throw new Error(`${flag} requires a value`);
109
- if (flag === '--out')
110
- outDir = value;
111
- else if (flag === '--cell')
112
- cellIds.push(value);
113
- else
114
- throw new Error(`unexpected argument: ${flag}`);
115
- }
116
- if (!outDir)
117
- throw new Error('--out is required');
118
- return { kind: 'run', specPath: argv[1], outDir, cellIds };
119
- }
@@ -1,59 +0,0 @@
1
- /*
2
- * Licensed to the Apache Software Foundation (ASF) under one
3
- * or more contributor license agreements. See the NOTICE file
4
- * distributed with this work for additional information
5
- * regarding copyright ownership. The ASF licenses this file
6
- * to you under the Apache License, Version 2.0 (the
7
- * "License"); you may not use this file except in compliance
8
- * with the License. You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing,
13
- * software distributed under the License is distributed on an
14
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- * KIND, either express or implied. See the License for the
16
- * specific language governing permissions and limitations
17
- * under the License.
18
- */
19
- import { randomUUID } from 'node:crypto';
20
- import { link, mkdir, open, readFile, unlink } from 'node:fs/promises';
21
- import { join } from 'node:path';
22
- import { FileAttemptStore } from './attempt-store.js';
23
- import { parseExperimentSpec } from './spec.js';
24
- export async function openExperimentDirectory(root, spec) {
25
- await mkdir(root, { recursive: true });
26
- const specPath = join(root, 'experiment.json');
27
- const temporaryPath = join(root, `.experiment-${randomUUID()}.tmp`);
28
- const canonical = `${canonicalJson(spec)}\n`;
29
- const temporary = await open(temporaryPath, 'wx', 0o600);
30
- try {
31
- await temporary.writeFile(canonical);
32
- await temporary.sync();
33
- await temporary.close();
34
- await link(temporaryPath, specPath);
35
- }
36
- catch (error) {
37
- if (error.code !== 'EEXIST')
38
- throw error;
39
- const existing = parseExperimentSpec(JSON.parse(await readFile(specPath, 'utf8')));
40
- if (canonicalJson(existing) !== canonicalJson(spec))
41
- throw new Error('experiment spec differs');
42
- }
43
- finally {
44
- await temporary.close().catch(() => undefined);
45
- await unlink(temporaryPath).catch(() => undefined);
46
- }
47
- return { root, specPath, attempts: new FileAttemptStore(join(root, 'attempts')) };
48
- }
49
- function canonicalJson(value) {
50
- if (Array.isArray(value))
51
- return `[${value.map(canonicalJson).join(',')}]`;
52
- if (value && typeof value === 'object') {
53
- return `{${Object.entries(value)
54
- .sort(([left], [right]) => left.localeCompare(right))
55
- .map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)
56
- .join(',')}}`;
57
- }
58
- return JSON.stringify(value);
59
- }
@@ -1,49 +0,0 @@
1
- /*
2
- * Licensed to the Apache Software Foundation (ASF) under one
3
- * or more contributor license agreements. See the NOTICE file
4
- * distributed with this work for additional information
5
- * regarding copyright ownership. The ASF licenses this file
6
- * to you under the Apache License, Version 2.0 (the
7
- * "License"); you may not use this file except in compliance
8
- * with the License. You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing,
13
- * software distributed under the License is distributed on an
14
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- * KIND, either express or implied. See the License for the
16
- * specific language governing permissions and limitations
17
- * under the License.
18
- */
19
- export function decodeJsonObject(value, where) {
20
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
21
- throw new Error(`${where} must be an object`);
22
- }
23
- return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, decodeJsonValue(child, `${where}.${key}`)]));
24
- }
25
- function decodeJsonValue(value, where) {
26
- if (value === null || typeof value === 'string' || typeof value === 'boolean')
27
- return value;
28
- if (typeof value === 'number' && Number.isFinite(value))
29
- return value;
30
- if (Array.isArray(value)) {
31
- return value.map((child, index) => decodeJsonValue(child, `${where}[${index}]`));
32
- }
33
- if (value && typeof value === 'object')
34
- return decodeJsonObject(value, where);
35
- throw new Error(`${where} must be JSON`);
36
- }
37
- export function expandExperiment(spec) {
38
- return spec.tasks.flatMap((task) => Array.from({ length: spec.repetitions }, (_, repetition) => repetition + 1).flatMap((repetition) => spec.subjects.map((subject) => ({
39
- id: `${task.id}::${repetition}::${subject.id}`,
40
- experimentId: spec.id,
41
- benchmark: spec.benchmark,
42
- executor: spec.executor,
43
- subject,
44
- task,
45
- repetition,
46
- budget: spec.budget,
47
- verifier: spec.verifier,
48
- }))));
49
- }