maka-agent 0.2.0-dev.3.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.
- package/dist/cli-core.js +1 -0
- package/dist/eval-bundle-path.js +1 -1
- package/dist/pi-tui-runner.js +3 -1
- package/dist/runtime-host-cli.js +37 -3
- package/dist/runtime-host-onboarding.js +10 -1
- package/dist/runtime-host-peer-mesh-management-command.js +17 -0
- package/dist/runtime-host-setup-command.js +33 -15
- package/dist/runtime-host-systemd-service.js +9 -3
- package/dist/runtime-host-tui-context.js +2 -6
- package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/node_modules/@maka/eval/dist/external-subject.js +1 -1
- package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -2
- package/node_modules/@maka/runtime/dist/sandbox/macos-seatbelt.js +68 -9
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +22 -3
- package/node_modules/@maka/runtime-host/dist/operator/peer-mesh-management-frame.js +14 -0
- package/{packages/eval/dist/index.js → node_modules/@maka/runtime-host/dist/peer-mesh/display-name.js} +12 -10
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +32 -21
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +207 -47
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +2 -0
- package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +18 -5
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +59 -2
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +11 -7
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +19 -0
- package/package.json +1 -2
- package/packages/eval/dist/attempt-store.js +0 -138
- package/packages/eval/dist/cli.js +0 -119
- package/packages/eval/dist/experiment-directory.js +0 -59
- package/packages/eval/dist/experiment.js +0 -49
- package/packages/eval/dist/external-subject.js +0 -488
- package/packages/eval/dist/harbor-external-subject.js +0 -929
- package/packages/eval/dist/harbor-maka-subject.js +0 -83
- package/packages/eval/dist/harness-environment.js +0 -80
- package/packages/eval/dist/harness-executor.js +0 -1013
- package/packages/eval/dist/install-preflight.js +0 -201
- package/packages/eval/dist/maka-artifacts.js +0 -126
- package/packages/eval/dist/maka-runtime-policy.js +0 -42
- package/packages/eval/dist/maka-subject.js +0 -268
- package/packages/eval/dist/metering-checkpoint.js +0 -80
- package/packages/eval/dist/provider-admission.js +0 -39
- package/packages/eval/dist/provider-metering.js +0 -67
- package/packages/eval/dist/provider-web-tool-surface.js +0 -74
- package/packages/eval/dist/relay-result-frame.js +0 -38
- package/packages/eval/dist/result.js +0 -94
- package/packages/eval/dist/runner.js +0 -290
- package/packages/eval/dist/spec.js +0 -135
- package/packages/eval/dist/toolchain-verification.js +0 -130
- package/packages/eval/harbor/deepseek-codex-models.json +0 -69
- package/packages/eval/harbor/deepseek-harness-profile/cordis.patch.yml +0 -140
- package/packages/eval/harbor/deepseek-harness-profile/cordis.yml +0 -18
- package/packages/eval/harbor/deepseek-harness-profile/package.json +0 -10
- package/packages/eval/harbor/docker-compose-egress-proxy.yaml +0 -57
- package/packages/eval/harbor/egress-proxy/Dockerfile +0 -25
- package/packages/eval/harbor/egress-proxy/entrypoint.sh +0 -62
- package/packages/eval/harbor/egress-proxy/network-policy +0 -148
- package/packages/eval/harbor/egress_filter.py +0 -435
- package/packages/eval/harbor/eval_framework.py +0 -40
- package/packages/eval/harbor/relay_agent.py +0 -686
- package/packages/eval/harbor/run_trial.py +0 -223
- package/packages/eval/package.json +0 -20
|
@@ -1,201 +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 { execFile } from 'node:child_process';
|
|
20
|
-
import { constants } from 'node:fs';
|
|
21
|
-
import { access, lstat, stat } from 'node:fs/promises';
|
|
22
|
-
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
23
|
-
import { BUNDLED_HARNESS_RELAY_ROOT, createHarnessPreparationEnvironment, resolvePathWithinRoot, resolveRealPathWithinRoot, } from './harness-environment.js';
|
|
24
|
-
const PREFLIGHT_TIMEOUT_MS = 10_000;
|
|
25
|
-
const PREFLIGHT_OUTPUT_LIMIT_BYTES = 16 * 1024;
|
|
26
|
-
const PYTHON_FRAMEWORK_PROBE = [
|
|
27
|
-
'from importlib import import_module',
|
|
28
|
-
'from importlib.metadata import version',
|
|
29
|
-
'import sys',
|
|
30
|
-
'actual = version(sys.argv[1])',
|
|
31
|
-
'if actual != sys.argv[2]:',
|
|
32
|
-
' raise SystemExit(f"installed {actual}, expected {sys.argv[2]}")',
|
|
33
|
-
'import_module(f"{sys.argv[3]}.models.trial.config")',
|
|
34
|
-
].join('\n');
|
|
35
|
-
export async function preflightHarnessInstallation(input, dependencies = {}) {
|
|
36
|
-
input.signal?.throwIfAborted();
|
|
37
|
-
const { framework, options, specPath } = input;
|
|
38
|
-
const pythonPath = pythonCommand(options.pythonPathEnv, specPath);
|
|
39
|
-
const trialsRoot = machinePath(options.trialsRootEnv);
|
|
40
|
-
if (isAbsolute(pythonPath)) {
|
|
41
|
-
await requirePath(pythonPath, `machine path ${options.pythonPathEnv}`, 'file');
|
|
42
|
-
await access(pythonPath, constants.X_OK).catch(() => {
|
|
43
|
-
throw new Error(`machine path ${options.pythonPathEnv} is not executable: ${pythonPath}`);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
await requireUsableDirectory(trialsRoot, `machine path ${options.trialsRootEnv}`);
|
|
47
|
-
if (options.tasksRootEnv) {
|
|
48
|
-
await requirePath(machinePath(options.tasksRootEnv), `machine path ${options.tasksRootEnv}`, 'directory');
|
|
49
|
-
}
|
|
50
|
-
for (const mount of options.mounts) {
|
|
51
|
-
await requirePath(machinePath(mount.sourceEnv), `machine path ${mount.sourceEnv}`, 'any');
|
|
52
|
-
}
|
|
53
|
-
let networkPolicyPath;
|
|
54
|
-
if (options.egressProxy) {
|
|
55
|
-
const source = machinePath(options.egressProxy.composeSourceEnv);
|
|
56
|
-
await requirePath(source, `machine path ${options.egressProxy.composeSourceEnv}`, 'directory');
|
|
57
|
-
const composeCandidate = resolvePathWithinRoot(source, options.egressProxy.composeRelativePath, 'egress proxy compose path');
|
|
58
|
-
const networkPolicyCandidate = resolvePathWithinRoot(source, options.egressProxy.networkPolicyRelativePath, 'egress network policy path');
|
|
59
|
-
await requirePath(composeCandidate, 'Eval egress Compose overlay', 'file');
|
|
60
|
-
await requirePath(networkPolicyCandidate, 'Eval egress network policy', 'file');
|
|
61
|
-
[, networkPolicyPath] = await Promise.all([
|
|
62
|
-
resolveRealPathWithinRoot(source, options.egressProxy.composeRelativePath, 'egress proxy compose path'),
|
|
63
|
-
resolveRealPathWithinRoot(source, options.egressProxy.networkPolicyRelativePath, 'egress network policy path'),
|
|
64
|
-
]);
|
|
65
|
-
}
|
|
66
|
-
for (const asset of ['eval_framework.py', 'relay_agent.py', 'run_trial.py']) {
|
|
67
|
-
await requirePath(resolve(BUNDLED_HARNESS_RELAY_ROOT, asset), `bundled Eval runtime ${asset}`, 'file');
|
|
68
|
-
}
|
|
69
|
-
input.signal?.throwIfAborted();
|
|
70
|
-
const runCommand = dependencies.runCommand ?? runCheckedCommand;
|
|
71
|
-
const environment = createHarnessPreparationEnvironment({
|
|
72
|
-
subjectCredentialNames: input.subjectCredentialNames,
|
|
73
|
-
declared: options.preparationEnvironment,
|
|
74
|
-
...(options.egressProxy && networkPolicyPath
|
|
75
|
-
? {
|
|
76
|
-
egress: {
|
|
77
|
-
allowedHost: options.egressProxy.allowedHost,
|
|
78
|
-
networkPolicyPath,
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
: {}),
|
|
82
|
-
});
|
|
83
|
-
const workingDirectory = dirname(specPath);
|
|
84
|
-
const distribution = framework === 'harbor' ? 'harbor' : 'datacurve-pier';
|
|
85
|
-
try {
|
|
86
|
-
await runCommand(pythonPath, ['-c', PYTHON_FRAMEWORK_PROBE, distribution, options.frameworkVersion, framework], environment, workingDirectory, input.signal);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (input.signal?.aborted)
|
|
90
|
-
input.signal.throwIfAborted();
|
|
91
|
-
throw new Error(`${framework} Python environment ${options.pythonPathEnv} is unavailable or does not provide ${distribution}@${options.frameworkVersion}: ${errorMessage(error)}`);
|
|
92
|
-
}
|
|
93
|
-
input.signal?.throwIfAborted();
|
|
94
|
-
if (options.environment.type === 'docker') {
|
|
95
|
-
try {
|
|
96
|
-
await runCommand('docker', ['version', '--format', '{{.Server.Version}}'], environment, workingDirectory, input.signal);
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
if (input.signal?.aborted)
|
|
100
|
-
input.signal.throwIfAborted();
|
|
101
|
-
throw new Error(`Docker CLI or daemon is unavailable: ${errorMessage(error)}`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
async function runCheckedCommand(command, args, environment, cwd, signal) {
|
|
106
|
-
signal?.throwIfAborted();
|
|
107
|
-
await new Promise((resolvePromise, rejectPromise) => {
|
|
108
|
-
execFile(command, [...args], {
|
|
109
|
-
env: environment,
|
|
110
|
-
cwd,
|
|
111
|
-
timeout: PREFLIGHT_TIMEOUT_MS,
|
|
112
|
-
killSignal: 'SIGKILL',
|
|
113
|
-
maxBuffer: PREFLIGHT_OUTPUT_LIMIT_BYTES,
|
|
114
|
-
encoding: 'utf8',
|
|
115
|
-
...(signal ? { signal } : {}),
|
|
116
|
-
}, (error, _stdout, stderr) => {
|
|
117
|
-
if (!error) {
|
|
118
|
-
resolvePromise();
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
rejectPromise(new Error(stderr.trim() || error.message));
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
async function requirePath(path, label, expected) {
|
|
126
|
-
let metadata;
|
|
127
|
-
try {
|
|
128
|
-
metadata = await stat(path);
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
if (error.code === 'ENOENT') {
|
|
132
|
-
throw new Error(`${label} does not exist: ${path}`);
|
|
133
|
-
}
|
|
134
|
-
throw new Error(`${label} is inaccessible: ${path}: ${errorMessage(error)}`);
|
|
135
|
-
}
|
|
136
|
-
if (expected === 'file' && !metadata.isFile())
|
|
137
|
-
throw new Error(`${label} is not a file: ${path}`);
|
|
138
|
-
if (expected === 'directory' && !metadata.isDirectory()) {
|
|
139
|
-
throw new Error(`${label} is not a directory: ${path}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
async function requireUsableDirectory(path, label) {
|
|
143
|
-
let candidate = path;
|
|
144
|
-
while (true) {
|
|
145
|
-
let metadata;
|
|
146
|
-
try {
|
|
147
|
-
metadata = await stat(candidate);
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
if (error.code !== 'ENOENT') {
|
|
151
|
-
throw new Error(`${label} is inaccessible: ${candidate}: ${errorMessage(error)}`);
|
|
152
|
-
}
|
|
153
|
-
let linkMetadata;
|
|
154
|
-
try {
|
|
155
|
-
linkMetadata = await lstat(candidate);
|
|
156
|
-
}
|
|
157
|
-
catch (linkError) {
|
|
158
|
-
if (linkError.code !== 'ENOENT') {
|
|
159
|
-
throw new Error(`${label} is inaccessible: ${candidate}: ${errorMessage(linkError)}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
if (linkMetadata?.isSymbolicLink()) {
|
|
163
|
-
throw new Error(`${label} is a dangling symbolic link: ${candidate}`);
|
|
164
|
-
}
|
|
165
|
-
if (linkMetadata)
|
|
166
|
-
continue;
|
|
167
|
-
const parent = dirname(candidate);
|
|
168
|
-
if (parent === candidate) {
|
|
169
|
-
throw new Error(`${label} has no accessible parent directory: ${path}`);
|
|
170
|
-
}
|
|
171
|
-
candidate = parent;
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
if (!metadata.isDirectory()) {
|
|
175
|
-
const subject = candidate === path ? label : `${label} parent`;
|
|
176
|
-
throw new Error(`${subject} is not a directory: ${candidate}`);
|
|
177
|
-
}
|
|
178
|
-
await access(candidate, constants.W_OK | constants.X_OK).catch(() => {
|
|
179
|
-
const subject = candidate === path ? label : `${label} nearest existing parent`;
|
|
180
|
-
throw new Error(`${subject} is not writable and searchable: ${candidate}`);
|
|
181
|
-
});
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function machinePath(name) {
|
|
186
|
-
const value = process.env[name];
|
|
187
|
-
if (!value)
|
|
188
|
-
throw new Error(`machine path ${name} is unavailable`);
|
|
189
|
-
return resolve(value);
|
|
190
|
-
}
|
|
191
|
-
function pythonCommand(name, specPath) {
|
|
192
|
-
const value = process.env[name];
|
|
193
|
-
if (!value)
|
|
194
|
-
throw new Error(`machine path ${name} is unavailable`);
|
|
195
|
-
if (isAbsolute(value))
|
|
196
|
-
return value;
|
|
197
|
-
return value.includes('/') || value.includes('\\') ? resolve(dirname(specPath), value) : value;
|
|
198
|
-
}
|
|
199
|
-
function errorMessage(error) {
|
|
200
|
-
return error instanceof Error ? error.message : String(error);
|
|
201
|
-
}
|
|
@@ -1,126 +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 { createReadStream } from 'node:fs';
|
|
21
|
-
import { chmod, copyFile, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
22
|
-
import { basename, dirname, join, resolve } from 'node:path';
|
|
23
|
-
import { backup, DatabaseSync } from 'node:sqlite';
|
|
24
|
-
export const MAKA_RUNTIME_ARTIFACT_PATH = '/logs/artifacts/maka-runtime-host';
|
|
25
|
-
export const MAKA_SUBJECT_STDOUT_PATH = '/logs/artifacts/maka-subject.stdout.txt';
|
|
26
|
-
export const MAKA_SUBJECT_STDERR_PATH = '/logs/artifacts/maka-subject.stderr.txt';
|
|
27
|
-
export async function captureMakaRuntimeArtifacts(input) {
|
|
28
|
-
const stateRoot = resolve(input.stateRoot);
|
|
29
|
-
const destinationRoot = resolve(input.destinationRoot);
|
|
30
|
-
const stagingRoot = `${destinationRoot}.${process.pid}.${randomUUID()}.tmp`;
|
|
31
|
-
await rm(stagingRoot, { recursive: true, force: true });
|
|
32
|
-
try {
|
|
33
|
-
await mkdir(stagingRoot, { recursive: true, mode: 0o700 });
|
|
34
|
-
const sourcePath = join(stateRoot, 'runtime.sqlite');
|
|
35
|
-
const destinationPath = join(stagingRoot, 'runtime.sqlite');
|
|
36
|
-
const source = new DatabaseSync(sourcePath, { readOnly: true });
|
|
37
|
-
try {
|
|
38
|
-
await backup(source, destinationPath);
|
|
39
|
-
}
|
|
40
|
-
finally {
|
|
41
|
-
source.close();
|
|
42
|
-
}
|
|
43
|
-
const snapshot = new DatabaseSync(destinationPath);
|
|
44
|
-
try {
|
|
45
|
-
snapshot.exec('PRAGMA wal_checkpoint(TRUNCATE)');
|
|
46
|
-
snapshot.exec('PRAGMA journal_mode=DELETE');
|
|
47
|
-
}
|
|
48
|
-
finally {
|
|
49
|
-
snapshot.close();
|
|
50
|
-
}
|
|
51
|
-
await rm(`${destinationPath}-wal`, { force: true });
|
|
52
|
-
await rm(`${destinationPath}-shm`, { force: true });
|
|
53
|
-
await chmod(destinationPath, 0o600);
|
|
54
|
-
for (const name of ['runtime-host-candidate.log', 'runtime-policy.json']) {
|
|
55
|
-
const source = join(stateRoot, name);
|
|
56
|
-
try {
|
|
57
|
-
const metadata = await stat(source);
|
|
58
|
-
if (!metadata.isFile())
|
|
59
|
-
continue;
|
|
60
|
-
const destination = join(stagingRoot, name);
|
|
61
|
-
await copyFile(source, destination);
|
|
62
|
-
await chmod(destination, 0o600);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
if (error.code !== 'ENOENT')
|
|
66
|
-
throw error;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const files = await Promise.all(['runtime.sqlite', 'runtime-host-candidate.log', 'runtime-policy.json'].map((name) => describeFile(join(stagingRoot, name), name)));
|
|
70
|
-
const manifest = {
|
|
71
|
-
schemaVersion: 'maka.eval.runtime_artifacts.v1',
|
|
72
|
-
reason: input.reason,
|
|
73
|
-
capturedAt: (input.now ?? Date.now)(),
|
|
74
|
-
files: files.filter((file) => file !== null),
|
|
75
|
-
};
|
|
76
|
-
await writeFile(join(stagingRoot, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, {
|
|
77
|
-
flag: 'wx',
|
|
78
|
-
mode: 0o600,
|
|
79
|
-
});
|
|
80
|
-
await mkdir(dirname(destinationRoot), { recursive: true, mode: 0o700 });
|
|
81
|
-
await rm(destinationRoot, { recursive: true, force: true });
|
|
82
|
-
await rename(stagingRoot, destinationRoot);
|
|
83
|
-
return manifest;
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
await rm(stagingRoot, { recursive: true, force: true }).catch(() => undefined);
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
export async function writeMakaArtifactCollectionError(destinationRoot, error) {
|
|
91
|
-
const root = resolve(destinationRoot);
|
|
92
|
-
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
93
|
-
await writeFile(join(root, 'collection-error.json'), `${JSON.stringify({
|
|
94
|
-
schemaVersion: 'maka.eval.runtime_artifact_error.v1',
|
|
95
|
-
errorCode: safeErrorCode(error),
|
|
96
|
-
message: safeErrorMessage(error),
|
|
97
|
-
})}\n`, { mode: 0o600 });
|
|
98
|
-
}
|
|
99
|
-
async function describeFile(path, name) {
|
|
100
|
-
try {
|
|
101
|
-
const metadata = await stat(path);
|
|
102
|
-
if (!metadata.isFile())
|
|
103
|
-
return null;
|
|
104
|
-
const hash = createHash('sha256');
|
|
105
|
-
for await (const chunk of createReadStream(path))
|
|
106
|
-
hash.update(chunk);
|
|
107
|
-
return {
|
|
108
|
-
path: basename(name),
|
|
109
|
-
bytes: metadata.size,
|
|
110
|
-
sha256: `sha256:${hash.digest('hex')}`,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
if (error.code === 'ENOENT')
|
|
115
|
-
return null;
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
function safeErrorCode(error) {
|
|
120
|
-
const code = error instanceof Error ? error.code : undefined;
|
|
121
|
-
return typeof code === 'string' && /^[A-Z0-9_]{1,64}$/u.test(code) ? code : null;
|
|
122
|
-
}
|
|
123
|
-
function safeErrorMessage(error) {
|
|
124
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
-
return Buffer.from(message).subarray(0, 1024).toString();
|
|
126
|
-
}
|
|
@@ -1,42 +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 { createDefaultRuntimePolicy } from '@maka/core/runtime-policy';
|
|
20
|
-
export function makaEvalRuntimePolicyDocument(proxyUrl) {
|
|
21
|
-
const policy = createDefaultRuntimePolicy();
|
|
22
|
-
const proxy = proxyUrl ? new URL(proxyUrl) : undefined;
|
|
23
|
-
return {
|
|
24
|
-
schemaVersion: 2,
|
|
25
|
-
revision: 0,
|
|
26
|
-
policy: {
|
|
27
|
-
...policy,
|
|
28
|
-
...(proxy
|
|
29
|
-
? {
|
|
30
|
-
networkProxy: {
|
|
31
|
-
...policy.networkProxy,
|
|
32
|
-
enabled: true,
|
|
33
|
-
protocol: 'http',
|
|
34
|
-
host: proxy.hostname,
|
|
35
|
-
port: Number(proxy.port || 80),
|
|
36
|
-
},
|
|
37
|
-
}
|
|
38
|
-
: {}),
|
|
39
|
-
privacy: { incognitoActive: true },
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
}
|
|
@@ -1,268 +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 { isSessionToolProfile } from '@maka/core/session';
|
|
21
|
-
import { decodeHostedExecutionProjection } from '@maka/runtime-host/protocol';
|
|
22
|
-
import { MAKA_RUNTIME_ARTIFACT_PATH, MAKA_SUBJECT_STDERR_PATH, MAKA_SUBJECT_STDOUT_PATH, } from './maka-artifacts.js';
|
|
23
|
-
import { deepSeekCostUsd } from './provider-metering.js';
|
|
24
|
-
export function createMakaSubjectAdapter() {
|
|
25
|
-
return {
|
|
26
|
-
kind: 'maka',
|
|
27
|
-
validate: (cell) => decodeConfig(cell.subject.config),
|
|
28
|
-
async execute({ cell, context }) {
|
|
29
|
-
const config = decodeConfig(cell.subject.config);
|
|
30
|
-
const executionId = randomUUID();
|
|
31
|
-
const input = {
|
|
32
|
-
executionId,
|
|
33
|
-
session: {
|
|
34
|
-
workspace: { kind: 'host_path', path: context.cwd },
|
|
35
|
-
modelTarget: {
|
|
36
|
-
kind: 'explicit',
|
|
37
|
-
connectionSlug: config.connectionSlug,
|
|
38
|
-
model: config.model,
|
|
39
|
-
},
|
|
40
|
-
thinkingLevel: config.thinkingLevel,
|
|
41
|
-
permissionMode: config.permissionMode,
|
|
42
|
-
collaborationMode: config.collaborationMode,
|
|
43
|
-
orchestrationMode: config.orchestrationMode,
|
|
44
|
-
toolProfile: config.toolProfile,
|
|
45
|
-
},
|
|
46
|
-
content: { text: context.taskInput },
|
|
47
|
-
maxSteps: positive(cell.budget.maxSteps, 'budget.maxSteps'),
|
|
48
|
-
};
|
|
49
|
-
const payload = Buffer.from(JSON.stringify({
|
|
50
|
-
rootPath: `${config.runtimeHostsPath}/${executionId}`,
|
|
51
|
-
artifactRoot: MAKA_RUNTIME_ARTIFACT_PATH,
|
|
52
|
-
baseUrl: config.baseUrl,
|
|
53
|
-
hostSettlementTimeoutMs: config.hostSettlementTimeoutMs,
|
|
54
|
-
execution: input,
|
|
55
|
-
})).toString('base64url');
|
|
56
|
-
const startedAt = Date.now();
|
|
57
|
-
let process;
|
|
58
|
-
try {
|
|
59
|
-
process = await context.execute({
|
|
60
|
-
command: config.nodePath,
|
|
61
|
-
args: [config.shimPath, payload],
|
|
62
|
-
credentialEnvironment: Object.fromEntries(cell.subject.credentials.map((name) => [name, name])),
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return subjectFailure('relay-execute', startedAt, context.signal);
|
|
67
|
-
}
|
|
68
|
-
if (process.termination !== 'exited') {
|
|
69
|
-
const projection = tryDecodeMatchingProjection(process.stdout, executionId);
|
|
70
|
-
const settled = projection?.kind === 'settled' ? projection : undefined;
|
|
71
|
-
return {
|
|
72
|
-
usage: settled?.usage ?? null,
|
|
73
|
-
costUsd: settled ? estimateDeepSeekCost(settled.usage, config.model) : null,
|
|
74
|
-
durationMs: Date.now() - startedAt,
|
|
75
|
-
status: 'failed',
|
|
76
|
-
failureReason: 'Maka subject exceeded the framework timeout',
|
|
77
|
-
artifacts: makaArtifacts(executionId, process, settled?.costUsd),
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
if (process.stdout.length === 0) {
|
|
81
|
-
return subjectFailure('empty-output', startedAt, context.signal, process);
|
|
82
|
-
}
|
|
83
|
-
let parsed;
|
|
84
|
-
try {
|
|
85
|
-
parsed = JSON.parse(process.stdout);
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
return subjectFailure('json-parse', startedAt, context.signal, process);
|
|
89
|
-
}
|
|
90
|
-
let projection;
|
|
91
|
-
try {
|
|
92
|
-
projection = decodeHostedExecutionProjection(parsed);
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return subjectFailure('result-decode', startedAt, context.signal, process);
|
|
96
|
-
}
|
|
97
|
-
if (projection.executionId !== executionId) {
|
|
98
|
-
return subjectFailure('identity-check', startedAt, context.signal, process);
|
|
99
|
-
}
|
|
100
|
-
if (projection.kind === 'indeterminate') {
|
|
101
|
-
return {
|
|
102
|
-
usage: null,
|
|
103
|
-
costUsd: null,
|
|
104
|
-
durationMs: Date.now() - startedAt,
|
|
105
|
-
status: 'indeterminate',
|
|
106
|
-
failureReason: safeFailureReason(projection.failureReason, 'Maka execution did not settle'),
|
|
107
|
-
artifacts: makaArtifacts(executionId, process),
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
const result = (status, failureReason) => ({
|
|
111
|
-
usage: projection.usage,
|
|
112
|
-
// Eval prices what Eval compares. The subject reports a cost of its
|
|
113
|
-
// own, from its own table, and taking it here would mean one arm
|
|
114
|
-
// billed at the runtime's rates and the others at this package's --
|
|
115
|
-
// a difference in the reported figure that no agent behaviour caused.
|
|
116
|
-
// It is kept as evidence below rather than used as the authority.
|
|
117
|
-
costUsd: estimateDeepSeekCost(projection.usage, config.model),
|
|
118
|
-
durationMs: Date.now() - startedAt,
|
|
119
|
-
status,
|
|
120
|
-
failureReason,
|
|
121
|
-
artifacts: makaArtifacts(executionId, process, projection.costUsd),
|
|
122
|
-
});
|
|
123
|
-
// The shim's exit code projects this same projection's status for the
|
|
124
|
-
// relay's benefit, so reading it here would only ask the same question
|
|
125
|
-
// twice and get a coarser answer. A shim that died without settling
|
|
126
|
-
// leaves no decodable projection, and the branches above catch that.
|
|
127
|
-
if (projection.status === 'cancelled') {
|
|
128
|
-
return result('indeterminate', 'Maka subject cancelled');
|
|
129
|
-
}
|
|
130
|
-
return result(projection.status, projection.status === 'completed' || projection.failureReason == null
|
|
131
|
-
? null
|
|
132
|
-
: safeFailureReason(projection.failureReason, 'Maka execution failed'));
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function tryDecodeMatchingProjection(stdout, executionId) {
|
|
137
|
-
if (stdout.length === 0)
|
|
138
|
-
return undefined;
|
|
139
|
-
try {
|
|
140
|
-
const projection = decodeHostedExecutionProjection(JSON.parse(stdout));
|
|
141
|
-
return projection.executionId === executionId ? projection : undefined;
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function safeFailureReason(value, fallback) {
|
|
148
|
-
if (SAFE_RUNTIME_FAILURE_REASONS.has(value))
|
|
149
|
-
return value;
|
|
150
|
-
if (/^Runtime Host did not start: (?:composition_mismatch|existing_host|host_unresponsive|incompatible|startup_timeout|upgrade_required)$/u.test(value) ||
|
|
151
|
-
/^Runtime Host usage did not settle: (?:missing_attempt_usage|partial_attempt_usage|pending_usage_repair|unreadable_usage_record)$/u.test(value))
|
|
152
|
-
return value;
|
|
153
|
-
return fallback;
|
|
154
|
-
}
|
|
155
|
-
const SAFE_RUNTIME_FAILURE_REASONS = new Set([
|
|
156
|
-
'Hosted execution is not active',
|
|
157
|
-
'Hosted execution was cancelled',
|
|
158
|
-
'Hosted execution was cancelled before admission',
|
|
159
|
-
'Runtime Host connection failed before execution settlement',
|
|
160
|
-
'Runtime Host could not settle execution',
|
|
161
|
-
'Runtime Host did not exit cleanly',
|
|
162
|
-
]);
|
|
163
|
-
function subjectFailure(stage, startedAt, signal, process) {
|
|
164
|
-
const cancelled = signal?.aborted === true;
|
|
165
|
-
return {
|
|
166
|
-
usage: null,
|
|
167
|
-
costUsd: null,
|
|
168
|
-
durationMs: Date.now() - startedAt,
|
|
169
|
-
status: cancelled ? 'indeterminate' : 'infra_failed',
|
|
170
|
-
failureReason: cancelled ? 'Maka subject cancelled' : `Maka subject failed during ${stage}`,
|
|
171
|
-
artifacts: [
|
|
172
|
-
...makaArtifacts(undefined, process),
|
|
173
|
-
{
|
|
174
|
-
kind: 'subject-failure',
|
|
175
|
-
stage,
|
|
176
|
-
...(process
|
|
177
|
-
? {
|
|
178
|
-
termination: process.termination,
|
|
179
|
-
exitCode: process.exitCode,
|
|
180
|
-
stdoutBytes: Buffer.byteLength(process.stdout),
|
|
181
|
-
...(process.diagnostic ? { diagnostic: process.diagnostic } : {}),
|
|
182
|
-
}
|
|
183
|
-
: {}),
|
|
184
|
-
},
|
|
185
|
-
],
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
function makaArtifacts(executionId, process,
|
|
189
|
-
// What the subject billed itself, when it said. Recording it is what makes a
|
|
190
|
-
// disagreement with Eval's own figure visible instead of silent -- the two
|
|
191
|
-
// are computed from the same usage, so they should differ only when a price
|
|
192
|
-
// table has drifted.
|
|
193
|
-
subjectReportedCostUsd) {
|
|
194
|
-
return [
|
|
195
|
-
...(subjectReportedCostUsd === undefined || subjectReportedCostUsd === null
|
|
196
|
-
? []
|
|
197
|
-
: [{ kind: 'subject-reported-cost', costUsd: subjectReportedCostUsd }]),
|
|
198
|
-
{
|
|
199
|
-
kind: 'maka-runtime-state',
|
|
200
|
-
path: MAKA_RUNTIME_ARTIFACT_PATH,
|
|
201
|
-
...(executionId ? { executionId } : {}),
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
kind: 'subject-stdout',
|
|
205
|
-
path: MAKA_SUBJECT_STDOUT_PATH,
|
|
206
|
-
...(process ? { bytes: Buffer.byteLength(process.stdout) } : {}),
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
kind: 'subject-stderr',
|
|
210
|
-
path: MAKA_SUBJECT_STDERR_PATH,
|
|
211
|
-
},
|
|
212
|
-
];
|
|
213
|
-
}
|
|
214
|
-
function decodeConfig(value) {
|
|
215
|
-
const fields = [
|
|
216
|
-
'nodePath',
|
|
217
|
-
'shimPath',
|
|
218
|
-
'runtimeHostsPath',
|
|
219
|
-
'baseUrl',
|
|
220
|
-
'connectionSlug',
|
|
221
|
-
'model',
|
|
222
|
-
'thinkingLevel',
|
|
223
|
-
'permissionMode',
|
|
224
|
-
'collaborationMode',
|
|
225
|
-
'orchestrationMode',
|
|
226
|
-
'hostSettlementTimeoutMs',
|
|
227
|
-
'toolProfile',
|
|
228
|
-
];
|
|
229
|
-
const config = exact(value, fields);
|
|
230
|
-
if (!URL.canParse(String(config.baseUrl)))
|
|
231
|
-
throw new Error('Maka baseUrl is invalid');
|
|
232
|
-
const hostSettlementTimeoutMs = positiveInteger(config.hostSettlementTimeoutMs, 'Maka config.hostSettlementTimeoutMs');
|
|
233
|
-
if (!isSessionToolProfile(config.toolProfile)) {
|
|
234
|
-
throw new Error('Maka config.toolProfile is invalid');
|
|
235
|
-
}
|
|
236
|
-
return { ...config, hostSettlementTimeoutMs };
|
|
237
|
-
}
|
|
238
|
-
function exact(value, fields) {
|
|
239
|
-
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
240
|
-
throw new Error('Maka config must be an object');
|
|
241
|
-
const record = value;
|
|
242
|
-
if (Object.keys(record).length !== fields.length ||
|
|
243
|
-
fields.some((field) => !Object.hasOwn(record, field)))
|
|
244
|
-
throw new Error('Maka config fields are invalid');
|
|
245
|
-
for (const field of fields) {
|
|
246
|
-
if (field === 'hostSettlementTimeoutMs')
|
|
247
|
-
continue;
|
|
248
|
-
if (typeof record[field] !== 'string' || record[field] === '')
|
|
249
|
-
throw new Error(`Maka config.${field} is invalid`);
|
|
250
|
-
}
|
|
251
|
-
return record;
|
|
252
|
-
}
|
|
253
|
-
function positiveInteger(value, where) {
|
|
254
|
-
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
|
|
255
|
-
throw new Error(`${where} is invalid`);
|
|
256
|
-
}
|
|
257
|
-
return value;
|
|
258
|
-
}
|
|
259
|
-
function positive(value, where) {
|
|
260
|
-
if (!Number.isSafeInteger(value) || value < 1)
|
|
261
|
-
throw new Error(`${where} is invalid`);
|
|
262
|
-
return value;
|
|
263
|
-
}
|
|
264
|
-
function estimateDeepSeekCost(usage, model) {
|
|
265
|
-
if (model !== 'deepseek-v4-flash')
|
|
266
|
-
return null;
|
|
267
|
-
return deepSeekCostUsd(usage);
|
|
268
|
-
}
|