@addai/node 0.30.12 → 0.30.14
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/auto-update.d.ts +3 -0
- package/dist/auto-update.js +15 -0
- package/dist/capabilities.d.ts +31 -6
- package/dist/capabilities.js +48 -26
- package/dist/claude-models.d.ts +71 -0
- package/dist/claude-models.js +330 -0
- package/dist/claude-print.d.ts +15 -0
- package/dist/claude-print.js +16 -0
- package/dist/codex-models.d.ts +81 -0
- package/dist/codex-models.js +385 -0
- package/dist/codex-spawn.d.ts +14 -8
- package/dist/codex-spawn.js +30 -10
- package/dist/command-runner.js +31 -9
- package/dist/desktop/docker.js +2 -0
- package/dist/desktop/manager.d.ts +2 -1
- package/dist/desktop/manager.js +51 -1
- package/dist/desktop/provider.d.ts +1 -1
- package/dist/desktop/provider.js +2 -0
- package/dist/desktop/relay-client.js +7 -0
- package/dist/desktop/spec.d.ts +2 -0
- package/dist/direct/aios-bridge.d.ts +13 -0
- package/dist/direct/aios-bridge.js +177 -0
- package/dist/direct/aios-mcp.d.ts +2 -0
- package/dist/direct/aios-mcp.js +132 -0
- package/dist/direct/aios-tools.d.ts +351 -0
- package/dist/direct/aios-tools.js +120 -0
- package/dist/direct/board-chat-provider.d.ts +64 -0
- package/dist/direct/board-chat-provider.js +151 -0
- package/dist/direct/board-chat.d.ts +40 -0
- package/dist/direct/board-chat.js +414 -0
- package/dist/direct/config.d.ts +2 -0
- package/dist/direct/config.js +60 -0
- package/dist/direct/launch.d.ts +14 -0
- package/dist/direct/launch.js +121 -0
- package/dist/direct/protocol.d.ts +46 -0
- package/dist/direct/protocol.js +84 -0
- package/dist/direct/relay-main.d.ts +1 -0
- package/dist/direct/relay-main.js +21 -0
- package/dist/direct/relay.d.ts +26 -0
- package/dist/direct/relay.js +334 -0
- package/dist/direct/sessions.d.ts +61 -0
- package/dist/direct/sessions.js +368 -0
- package/dist/direct/supervisor.d.ts +9 -0
- package/dist/direct/supervisor.js +137 -0
- package/dist/direct/terminal.d.ts +1 -0
- package/dist/direct/terminal.js +106 -0
- package/dist/direct/worker.d.ts +1 -0
- package/dist/direct/worker.js +278 -0
- package/dist/entitybox/container-action.cjs +85 -0
- package/dist/entitybox/container-watchdog.cjs +70 -0
- package/dist/entitybox/model-entry.d.ts +3 -0
- package/dist/entitybox/model-entry.js +233 -0
- package/dist/entitybox/model-mcp-proxy.d.ts +3 -0
- package/dist/entitybox/model-mcp-proxy.js +85 -0
- package/dist/entitybox-application-boundary.d.ts +59 -0
- package/dist/entitybox-application-boundary.js +161 -0
- package/dist/entitybox-application-guard-core.d.ts +44 -0
- package/dist/entitybox-application-guard-core.js +164 -0
- package/dist/entitybox-application-guard-process.d.ts +1 -0
- package/dist/entitybox-application-guard-process.js +83 -0
- package/dist/entitybox-application-guard.d.ts +46 -0
- package/dist/entitybox-application-guard.js +239 -0
- package/dist/entitybox-capacity-health-host.d.ts +12 -0
- package/dist/entitybox-capacity-health-host.js +80 -0
- package/dist/entitybox-capacity-health-worker.d.ts +22 -0
- package/dist/entitybox-capacity-health-worker.js +168 -0
- package/dist/entitybox-capacity-host.d.ts +17 -0
- package/dist/entitybox-capacity-host.js +155 -0
- package/dist/entitybox-capacity-owner-process.d.ts +1 -0
- package/dist/entitybox-capacity-owner-process.js +32 -0
- package/dist/entitybox-capacity-owner.d.ts +16 -0
- package/dist/entitybox-capacity-owner.js +90 -0
- package/dist/entitybox-capacity-programs.d.ts +7 -0
- package/dist/entitybox-capacity-programs.js +49 -0
- package/dist/entitybox-capacity-provisioner.d.ts +82 -0
- package/dist/entitybox-capacity-provisioner.js +404 -0
- package/dist/entitybox-capacity-publication.d.ts +29 -0
- package/dist/entitybox-capacity-publication.js +199 -0
- package/dist/entitybox-capacity-registration.d.ts +36 -0
- package/dist/entitybox-capacity-registration.js +75 -0
- package/dist/entitybox-capacity-worker.d.ts +29 -0
- package/dist/entitybox-capacity-worker.js +113 -0
- package/dist/entitybox-computer-task.d.ts +69 -0
- package/dist/entitybox-computer-task.js +176 -0
- package/dist/entitybox-controller-recovery.d.ts +40 -0
- package/dist/entitybox-controller-recovery.js +156 -0
- package/dist/entitybox-desktop-action-server.d.ts +34 -0
- package/dist/entitybox-desktop-action-server.js +176 -0
- package/dist/entitybox-desktop-admission.d.ts +32 -0
- package/dist/entitybox-desktop-admission.js +79 -0
- package/dist/entitybox-display-binding.d.ts +13 -0
- package/dist/entitybox-display-binding.js +31 -0
- package/dist/entitybox-execution-container.d.ts +82 -0
- package/dist/entitybox-execution-container.js +450 -0
- package/dist/entitybox-execution-host.d.ts +40 -0
- package/dist/entitybox-execution-host.js +168 -0
- package/dist/entitybox-execution-lease.d.ts +81 -0
- package/dist/entitybox-execution-lease.js +332 -0
- package/dist/entitybox-file-inputs.d.ts +51 -0
- package/dist/entitybox-file-inputs.js +182 -0
- package/dist/entitybox-file-session.d.ts +38 -0
- package/dist/entitybox-file-session.js +82 -0
- package/dist/entitybox-host-process.d.ts +12 -0
- package/dist/entitybox-host-process.js +120 -0
- package/dist/entitybox-install.d.ts +10 -0
- package/dist/entitybox-install.js +40 -0
- package/dist/entitybox-mcp-broker.d.ts +77 -0
- package/dist/entitybox-mcp-broker.js +420 -0
- package/dist/entitybox-mcp-contract.d.ts +10 -0
- package/dist/entitybox-mcp-contract.js +24 -0
- package/dist/entitybox-mcp-guard.d.ts +3 -0
- package/dist/entitybox-mcp-guard.js +167 -0
- package/dist/entitybox-model-artifact.d.ts +9 -0
- package/dist/entitybox-model-artifact.js +83 -0
- package/dist/entitybox-native-services.d.ts +33 -0
- package/dist/entitybox-native-services.js +172 -0
- package/dist/entitybox-operation.d.ts +4 -0
- package/dist/entitybox-operation.js +34 -0
- package/dist/entitybox-provider-broker.d.ts +41 -0
- package/dist/entitybox-provider-broker.js +149 -0
- package/dist/entitybox-queue-request.d.ts +32 -0
- package/dist/entitybox-queue-request.js +141 -0
- package/dist/entitybox-recovery-host.d.ts +12 -0
- package/dist/entitybox-recovery-host.js +80 -0
- package/dist/entitybox-recovery-store.d.ts +33 -0
- package/dist/entitybox-recovery-store.js +150 -0
- package/dist/entitybox-recovery-worker.d.ts +30 -0
- package/dist/entitybox-recovery-worker.js +134 -0
- package/dist/entitybox-vault-provider.d.ts +27 -0
- package/dist/entitybox-vault-provider.js +127 -0
- package/dist/harness-registry.js +3 -1
- package/dist/index.js +72 -38
- package/dist/install.d.ts +14 -2
- package/dist/install.js +115 -10
- package/dist/model-cache.d.ts +38 -0
- package/dist/model-cache.js +137 -0
- package/dist/request-pump.d.ts +3 -0
- package/dist/request-pump.js +21 -7
- package/dist/session-runner.d.ts +8 -1
- package/dist/session-runner.js +48 -3
- package/dist/supabase-client.js +4 -1
- package/package.json +5 -1
- package/scripts/copy-assets.js +4 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runEntityboxQueueRequest = runEntityboxQueueRequest;
|
|
4
|
+
const entitybox_install_1 = require("./entitybox-install");
|
|
5
|
+
const entitybox_mcp_contract_1 = require("./entitybox-mcp-contract");
|
|
6
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
7
|
+
const entitybox_computer_task_1 = require("./entitybox-computer-task");
|
|
8
|
+
const entitybox_operation_1 = require("./entitybox-operation");
|
|
9
|
+
/** Called before native host auth, cwd/project preparation or installation.
|
|
10
|
+
* No adapter means disabled, never ordinary-host fallback. An MCP scope is
|
|
11
|
+
* only a route marker: the runtime-authenticated SQL claim is authorization. */
|
|
12
|
+
async function runEntityboxQueueRequest(req, io, services) {
|
|
13
|
+
const env = req.mcp_env_overrides?.['entity-desktop-mcp'];
|
|
14
|
+
if (req.entitybox_computer_request !== true && (!env || !Object.prototype.hasOwnProperty.call(env, 'ENTITYBOX_DESKTOP_SCOPE')))
|
|
15
|
+
return false;
|
|
16
|
+
let lease, owner;
|
|
17
|
+
let prepared;
|
|
18
|
+
let preparing, preparationSettled = true;
|
|
19
|
+
let completion, reason = 'failed';
|
|
20
|
+
let poll, timeout, polling, watching = true;
|
|
21
|
+
const stop = new AbortController();
|
|
22
|
+
const cancel = (why) => { if (!stop.signal.aborted) {
|
|
23
|
+
reason = why;
|
|
24
|
+
stop.abort();
|
|
25
|
+
lease?.fence();
|
|
26
|
+
} };
|
|
27
|
+
const shutdown = () => cancel('lease_lost');
|
|
28
|
+
services?.signal?.addEventListener('abort', shutdown, { once: true });
|
|
29
|
+
if (services?.signal?.aborted)
|
|
30
|
+
shutdown();
|
|
31
|
+
const token = () => { const p = io.pairing(); if (!p || p.runtimeId !== req.runtime_id)
|
|
32
|
+
throw new Error(); return p.daemonToken; };
|
|
33
|
+
const status = () => (0, entitybox_operation_1.entityboxOperation)([], 4500, () => io.rpc('runtime_get_request_status', { p_token: token(), p_request_id: req.id }));
|
|
34
|
+
const inspectStatus = async () => {
|
|
35
|
+
try {
|
|
36
|
+
const value = await status();
|
|
37
|
+
if (value === 'canceled')
|
|
38
|
+
cancel('canceled');
|
|
39
|
+
else if (!['starting', 'running'].includes(value))
|
|
40
|
+
cancel('lease_lost');
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
cancel('lease_lost');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const tick = () => { polling = inspectStatus().finally(() => { if (watching && !stop.signal.aborted)
|
|
47
|
+
poll = setTimeout(tick, 750); }); };
|
|
48
|
+
try {
|
|
49
|
+
const scope = (0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(JSON.parse((0, entitybox_install_1.entityboxInstallScope)(req.mcp_env_overrides ?? undefined, req.id)));
|
|
50
|
+
if (scope.runtimeId !== req.runtime_id || scope.desktopId !== req.desktop_id || req.agent !== 'claude' || req.mode !== 'print'
|
|
51
|
+
|| typeof req.prompt !== 'string' || !req.prompt.trim() || req.prompt.length > 12000
|
|
52
|
+
|| (req.timeout_seconds != null && (!Number.isInteger(req.timeout_seconds) || req.timeout_seconds < 0 || req.timeout_seconds > 2147483)))
|
|
53
|
+
throw new Error();
|
|
54
|
+
if (!services)
|
|
55
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Isolated computer execution is not configured on this runtime.');
|
|
56
|
+
await inspectStatus();
|
|
57
|
+
if (stop.signal.aborted)
|
|
58
|
+
return true;
|
|
59
|
+
if (req.timeout_seconds)
|
|
60
|
+
timeout = setTimeout(() => cancel('failed'), req.timeout_seconds * 1000);
|
|
61
|
+
tick();
|
|
62
|
+
lease = await entitybox_execution_lease_1.EntityboxExecutionLease.claim(req.id, scope, token, io.rpc);
|
|
63
|
+
if (stop.signal.aborted)
|
|
64
|
+
lease.fence();
|
|
65
|
+
lease.assertActive();
|
|
66
|
+
prepared = await (0, entitybox_operation_1.entityboxOperation)([lease.signal, stop.signal], 10000, signal => {
|
|
67
|
+
preparationSettled = false;
|
|
68
|
+
preparing = Promise.resolve().then(() => services.prepare(structuredClone(req), lease, signal))
|
|
69
|
+
.then(value => { prepared = value; return value; }).finally(() => { preparationSettled = true; });
|
|
70
|
+
return preparing;
|
|
71
|
+
});
|
|
72
|
+
lease.assertActive();
|
|
73
|
+
if (stop.signal.aborted)
|
|
74
|
+
throw new Error();
|
|
75
|
+
const task = await entitybox_computer_task_1.EntityboxComputerTask.start(lease, { ...prepared.options,
|
|
76
|
+
onTask: value => { owner = value; prepared?.onTask?.(value); },
|
|
77
|
+
onContainer: container => prepared.register(container),
|
|
78
|
+
onEvent: async (event) => {
|
|
79
|
+
if (event.type === 'turn_complete') {
|
|
80
|
+
completion = event;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Fresh server authority for each event; no best-effort write or
|
|
84
|
+
// raw provider/RPC diagnostic can masquerade as durable progress.
|
|
85
|
+
if (!await lease.appendEvent(event))
|
|
86
|
+
throw new Error();
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const result = await task.done;
|
|
90
|
+
await inspectStatus();
|
|
91
|
+
if (!stop.signal.aborted && result.code === 0 && completion?.type === 'turn_complete' && completion.stopReason === 'success')
|
|
92
|
+
reason = 'completed';
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
lease?.fence();
|
|
96
|
+
if (!stop.signal.aborted)
|
|
97
|
+
reason = 'failed';
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
services?.signal?.removeEventListener('abort', shutdown);
|
|
101
|
+
watching = false;
|
|
102
|
+
clearTimeout(poll);
|
|
103
|
+
clearTimeout(timeout);
|
|
104
|
+
await polling;
|
|
105
|
+
if (lease) {
|
|
106
|
+
// Stop discovery waits for coordinator startup, including failures.
|
|
107
|
+
// No reservation release or successful event without complete proof.
|
|
108
|
+
try {
|
|
109
|
+
// Cooperative preparation gets a bounded chance to finish aborting.
|
|
110
|
+
// An unresponsive adapter must not strand the queue worker forever,
|
|
111
|
+
// but its unknown state also must not release the SQL reservation.
|
|
112
|
+
if (preparing && !preparationSettled) {
|
|
113
|
+
try {
|
|
114
|
+
await (0, entitybox_operation_1.entityboxOperation)([], 1500, () => preparing);
|
|
115
|
+
}
|
|
116
|
+
catch { }
|
|
117
|
+
}
|
|
118
|
+
if (!preparationSettled)
|
|
119
|
+
throw new Error();
|
|
120
|
+
await lease.acknowledgeStopped(reason, async () => {
|
|
121
|
+
await owner?.stopAndVerify();
|
|
122
|
+
if (prepared)
|
|
123
|
+
await prepared.verifyAllStopped();
|
|
124
|
+
});
|
|
125
|
+
await lease.finishRequest(reason, reason === 'completed' ? completion : undefined);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
lease.fence();
|
|
129
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Computer task cleanup or final status remains unverified.');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (!stop.signal.aborted) {
|
|
133
|
+
// Before a lease exists, retain the native failure reporting contract.
|
|
134
|
+
// Do not retry, resolve host credentials, install or start a harness.
|
|
135
|
+
const message = 'The isolated computer task could not start. Check runtime configuration and task access.';
|
|
136
|
+
await io.rpc('runtime_request_update', { p_token: token(), p_request_id: req.id, p_status: 'failed', p_error_code: 'entitybox_computer_setup_failed', p_error_message: message });
|
|
137
|
+
await io.rpc('runtime_event_emit', { p_token: token(), p_request_id: req.id, p_type: 'error', p_payload: { code: 'entitybox_computer_setup_failed', message } });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type EntityboxRecoveryWorkerIO } from './entitybox-recovery-worker';
|
|
2
|
+
/** Recovery can stay enabled after execution/provisioning are disabled. It
|
|
3
|
+
* grants no new task or computer startup authority. */
|
|
4
|
+
export declare function entityboxRecoveryEnvironment(env?: NodeJS.ProcessEnv): {
|
|
5
|
+
enabled: true;
|
|
6
|
+
dockerContext: string;
|
|
7
|
+
directory: string;
|
|
8
|
+
} | undefined;
|
|
9
|
+
export declare function startEntityboxRecoveryHost(io: Omit<EntityboxRecoveryWorkerIO, 'report'>, env?: NodeJS.ProcessEnv): {
|
|
10
|
+
stop(): void;
|
|
11
|
+
drain(_timeout?: number): Promise<boolean>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.entityboxRecoveryEnvironment = entityboxRecoveryEnvironment;
|
|
37
|
+
exports.startEntityboxRecoveryHost = startEntityboxRecoveryHost;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const paths_1 = require("./paths");
|
|
40
|
+
const entitybox_recovery_worker_1 = require("./entitybox-recovery-worker");
|
|
41
|
+
/** Recovery can stay enabled after execution/provisioning are disabled. It
|
|
42
|
+
* grants no new task or computer startup authority. */
|
|
43
|
+
function entityboxRecoveryEnvironment(env = process.env) {
|
|
44
|
+
if (env.AINODE_ENTITYBOX_RECOVERY_ENABLED !== '1')
|
|
45
|
+
return undefined;
|
|
46
|
+
const dockerContext = env.AINODE_ENTITYBOX_DOCKER_CONTEXT ?? '';
|
|
47
|
+
const directory = env.AINODE_ENTITYBOX_RECOVERY_DIRECTORY ?? path.join(paths_1.RUNTIME_HOME, 'entitybox', 'recovery');
|
|
48
|
+
if (env.DOCKER_HOST || !/^[-a-zA-Z0-9_.]{1,80}$/.test(dockerContext) || !path.isAbsolute(directory) || directory.startsWith('\\\\'))
|
|
49
|
+
throw new Error('Invalid recovery configuration');
|
|
50
|
+
return { enabled: true, dockerContext, directory };
|
|
51
|
+
}
|
|
52
|
+
function startEntityboxRecoveryHost(io, env = process.env) {
|
|
53
|
+
const idle = { stop() { }, async drain(_timeout) { return true; } };
|
|
54
|
+
try {
|
|
55
|
+
const config = entityboxRecoveryEnvironment(env);
|
|
56
|
+
if (!config)
|
|
57
|
+
return idle;
|
|
58
|
+
const pairing = io.pairing();
|
|
59
|
+
if (!pairing)
|
|
60
|
+
throw new Error();
|
|
61
|
+
const reported = new Map();
|
|
62
|
+
const worker = (0, entitybox_recovery_worker_1.createEntityboxRecoveryWorker)({ ...config, runtimeId: pairing.runtimeId }, { ...io, report: (state, id) => {
|
|
63
|
+
const key = id ?? 'worker', at = Date.now(), last = reported.get(key);
|
|
64
|
+
if (last?.state === state && at - last.at < 60000)
|
|
65
|
+
return;
|
|
66
|
+
if (reported.size > 1000)
|
|
67
|
+
reported.clear();
|
|
68
|
+
reported.set(key, { state, at });
|
|
69
|
+
console.log('[entitybox] Computer recovery ' + state + (id ? ' (' + id + ')' : ''));
|
|
70
|
+
} });
|
|
71
|
+
if (!worker)
|
|
72
|
+
return idle;
|
|
73
|
+
worker.start();
|
|
74
|
+
return worker;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
console.warn('[entitybox] Computer recovery is disabled: host configuration unavailable.');
|
|
78
|
+
return idle;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type EntityboxExecutionIdentity } from './entitybox-execution-lease';
|
|
2
|
+
import type { EntityboxApplicationBinding, EntityboxApplicationQuiescence } from './entitybox-application-boundary';
|
|
3
|
+
import { type EntityboxHostProcess } from './entitybox-host-process';
|
|
4
|
+
export declare function entityboxCanonical(value: unknown): string;
|
|
5
|
+
export interface EntityboxRecoveryHost {
|
|
6
|
+
hostId: string;
|
|
7
|
+
dockerContext: string;
|
|
8
|
+
controller: EntityboxHostProcess;
|
|
9
|
+
guard: EntityboxHostProcess;
|
|
10
|
+
}
|
|
11
|
+
export interface EntityboxGuardEvidence {
|
|
12
|
+
version: 1;
|
|
13
|
+
host: EntityboxRecoveryHost;
|
|
14
|
+
identity: EntityboxExecutionIdentity;
|
|
15
|
+
application: EntityboxApplicationBinding;
|
|
16
|
+
proof: EntityboxApplicationQuiescence;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseEntityboxRecoveryHost(value: unknown): Readonly<EntityboxRecoveryHost>;
|
|
19
|
+
/** Private host-local evidence only. Nothing is stored in browser/profile/work
|
|
20
|
+
* volumes, and no execution/pairing/provider nonce is written here. */
|
|
21
|
+
export declare class EntityboxRecoveryStore {
|
|
22
|
+
readonly directory: string;
|
|
23
|
+
readonly hostId: string;
|
|
24
|
+
constructor(directory: string);
|
|
25
|
+
private read;
|
|
26
|
+
private immutable;
|
|
27
|
+
writeProof(value: EntityboxGuardEvidence): void;
|
|
28
|
+
readProof(attemptId: string): {
|
|
29
|
+
value: EntityboxGuardEvidence;
|
|
30
|
+
sha256: string;
|
|
31
|
+
};
|
|
32
|
+
private proofFile;
|
|
33
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EntityboxRecoveryStore = void 0;
|
|
37
|
+
exports.entityboxCanonical = entityboxCanonical;
|
|
38
|
+
exports.parseEntityboxRecoveryHost = parseEntityboxRecoveryHost;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const crypto_1 = require("crypto");
|
|
42
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
43
|
+
const entitybox_host_process_1 = require("./entitybox-host-process");
|
|
44
|
+
const entitybox_mcp_contract_1 = require("./entitybox-mcp-contract");
|
|
45
|
+
const uuid = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
|
|
46
|
+
const fail = () => new entitybox_execution_lease_1.EntityboxExecutionError('Native recovery evidence could not be verified');
|
|
47
|
+
function entityboxCanonical(value) { if (Array.isArray(value))
|
|
48
|
+
return '[' + value.map(entityboxCanonical).join(',') + ']'; if (value && typeof value === 'object')
|
|
49
|
+
return '{' + Object.keys(value).sort().map(k => JSON.stringify(k) + ':' + entityboxCanonical(value[k])).join(',') + '}'; const result = JSON.stringify(value); if (result === undefined)
|
|
50
|
+
throw fail(); return result; }
|
|
51
|
+
function parseEntityboxRecoveryHost(value) {
|
|
52
|
+
const h = value;
|
|
53
|
+
if (!h || Object.keys(h).sort().join(',') !== 'controller,dockerContext,guard,hostId' || !uuid.test(h.hostId) || typeof h.dockerContext !== 'string' || !/^[-a-zA-Z0-9_.]{1,80}$/.test(h.dockerContext))
|
|
54
|
+
throw fail();
|
|
55
|
+
const controller = (0, entitybox_host_process_1.parseEntityboxHostProcess)(h.controller), guard = (0, entitybox_host_process_1.parseEntityboxHostProcess)(h.guard);
|
|
56
|
+
if (controller.platform !== guard.platform || controller.domain !== guard.domain || controller.pid === guard.pid)
|
|
57
|
+
throw fail();
|
|
58
|
+
return Object.freeze({ ...h, controller, guard });
|
|
59
|
+
}
|
|
60
|
+
/** Private host-local evidence only. Nothing is stored in browser/profile/work
|
|
61
|
+
* volumes, and no execution/pairing/provider nonce is written here. */
|
|
62
|
+
class EntityboxRecoveryStore {
|
|
63
|
+
directory;
|
|
64
|
+
hostId;
|
|
65
|
+
constructor(directory) {
|
|
66
|
+
if (!path.isAbsolute(directory) || directory.startsWith('\\\\'))
|
|
67
|
+
throw fail();
|
|
68
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
69
|
+
this.directory = fs.realpathSync(directory);
|
|
70
|
+
const file = path.join(this.directory, 'host.json');
|
|
71
|
+
this.immutable(file, entityboxCanonical({ version: 1, id: (0, crypto_1.randomUUID)() }), true);
|
|
72
|
+
const value = JSON.parse(this.read(file));
|
|
73
|
+
if (value?.version !== 1 || !uuid.test(value.id) || Object.keys(value).sort().join(',') !== 'id,version')
|
|
74
|
+
throw fail();
|
|
75
|
+
this.hostId = value.id;
|
|
76
|
+
}
|
|
77
|
+
read(file) { try {
|
|
78
|
+
const stat = fs.lstatSync(file);
|
|
79
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 16384)
|
|
80
|
+
throw fail();
|
|
81
|
+
return fs.readFileSync(file, 'utf8');
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw fail();
|
|
85
|
+
} }
|
|
86
|
+
immutable(file, text, existing = false) {
|
|
87
|
+
const temp = path.join(this.directory, 'pending-' + (0, crypto_1.randomUUID)() + '.json');
|
|
88
|
+
let fd, created = false;
|
|
89
|
+
try {
|
|
90
|
+
fd = fs.openSync(temp, 'wx', 0o600);
|
|
91
|
+
created = true;
|
|
92
|
+
fs.writeFileSync(fd, text);
|
|
93
|
+
fs.fsyncSync(fd);
|
|
94
|
+
fs.closeSync(fd);
|
|
95
|
+
fd = undefined;
|
|
96
|
+
try {
|
|
97
|
+
fs.linkSync(temp, file);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
if (e.code !== 'EEXIST' || !existing && this.read(file) !== text)
|
|
101
|
+
throw fail();
|
|
102
|
+
}
|
|
103
|
+
if (process.platform !== 'win32') {
|
|
104
|
+
const dir = fs.openSync(this.directory, 'r');
|
|
105
|
+
try {
|
|
106
|
+
fs.fsyncSync(dir);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
fs.closeSync(dir);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
throw fail();
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
if (fd !== undefined)
|
|
118
|
+
try {
|
|
119
|
+
fs.closeSync(fd);
|
|
120
|
+
}
|
|
121
|
+
catch { }
|
|
122
|
+
if (created)
|
|
123
|
+
try {
|
|
124
|
+
fs.unlinkSync(temp);
|
|
125
|
+
}
|
|
126
|
+
catch { }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
writeProof(value) {
|
|
130
|
+
const h = parseEntityboxRecoveryHost(value.host), identity = value.identity, scope = (0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(identity?.scope), a = value.application, p = value.proof;
|
|
131
|
+
if (value.version !== 1 || h.hostId !== this.hostId || !uuid.test(identity?.requestId) || !uuid.test(identity?.attemptId) || !a || !uuid.test(a.capacityId) || a.desktopId !== scope.desktopId || a.runtimeId !== scope.runtimeId || !/^[a-f0-9]{64}$/.test(a.containerId) || !/^sha256:[a-f0-9]{64}$/.test(a.imageId) || !Number.isFinite(Date.parse(a.startedAt)) || p?.attemptId !== identity.attemptId || p.capacityId !== a.capacityId || p.containerId !== a.containerId || !['paused', 'stopped'].includes(p.state) || !Number.isFinite(Date.parse(p.observedAt)))
|
|
132
|
+
throw fail();
|
|
133
|
+
const text = entityboxCanonical({ version: 1, host: h, identity: { requestId: identity.requestId, attemptId: identity.attemptId, scope }, application: { capacityId: a.capacityId, desktopId: a.desktopId, runtimeId: a.runtimeId, containerId: a.containerId, imageId: a.imageId, startedAt: a.startedAt }, proof: { capacityId: p.capacityId, containerId: p.containerId, attemptId: p.attemptId, state: p.state, observedAt: p.observedAt } });
|
|
134
|
+
if (Buffer.byteLength(text) > 16384)
|
|
135
|
+
throw fail();
|
|
136
|
+
this.immutable(this.proofFile(identity.attemptId), text);
|
|
137
|
+
}
|
|
138
|
+
readProof(attemptId) { const text = this.read(this.proofFile(attemptId)); let value; try {
|
|
139
|
+
value = JSON.parse(text);
|
|
140
|
+
if (value?.version !== 1 || value.identity?.attemptId !== attemptId || value.host?.hostId !== this.hostId)
|
|
141
|
+
throw fail();
|
|
142
|
+
parseEntityboxRecoveryHost(value.host);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
throw fail();
|
|
146
|
+
} return { value, sha256: (0, crypto_1.createHash)('sha256').update(text).digest('hex') }; }
|
|
147
|
+
proofFile(id) { if (!uuid.test(id))
|
|
148
|
+
throw fail(); return path.join(this.directory, 'guard-' + id + '.json'); }
|
|
149
|
+
}
|
|
150
|
+
exports.EntityboxRecoveryStore = EntityboxRecoveryStore;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type EntityboxControllerRecoveryOptions } from './entitybox-controller-recovery';
|
|
2
|
+
export interface EntityboxRecoveryWorkerConfiguration {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
runtimeId: string;
|
|
5
|
+
dockerContext: string;
|
|
6
|
+
directory: string;
|
|
7
|
+
}
|
|
8
|
+
export interface EntityboxRecoveryWorkerIO {
|
|
9
|
+
rpc: EntityboxControllerRecoveryOptions['rpc'];
|
|
10
|
+
pairing: () => {
|
|
11
|
+
runtimeId: string;
|
|
12
|
+
daemonToken: string;
|
|
13
|
+
} | null;
|
|
14
|
+
activeRequests: () => readonly string[];
|
|
15
|
+
report?: (state: 'recovered' | 'waiting' | 'attention' | 'unavailable', attemptId?: string) => void;
|
|
16
|
+
/** Fixture-only factory/clock, never model or queue input. */
|
|
17
|
+
recover?: (options: EntityboxControllerRecoveryOptions) => {
|
|
18
|
+
run: () => Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
clock?: () => number;
|
|
21
|
+
}
|
|
22
|
+
/** Discover interrupted native attempts. Inventory is a hint, never proof of
|
|
23
|
+
* process death or permission to release resources. The retained recovery
|
|
24
|
+
* driver rechecks SQL, exact guard evidence and OS process birth identities. */
|
|
25
|
+
export declare function createEntityboxRecoveryWorker(config: EntityboxRecoveryWorkerConfiguration, io: EntityboxRecoveryWorkerIO): {
|
|
26
|
+
tick: () => Promise<void>;
|
|
27
|
+
start(): void;
|
|
28
|
+
stop(): void;
|
|
29
|
+
drain(timeoutMs?: number): Promise<boolean>;
|
|
30
|
+
} | undefined;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEntityboxRecoveryWorker = createEntityboxRecoveryWorker;
|
|
4
|
+
const entitybox_controller_recovery_1 = require("./entitybox-controller-recovery");
|
|
5
|
+
const entitybox_recovery_store_1 = require("./entitybox-recovery-store");
|
|
6
|
+
const entitybox_mcp_contract_1 = require("./entitybox-mcp-contract");
|
|
7
|
+
const entitybox_operation_1 = require("./entitybox-operation");
|
|
8
|
+
const uuid = /^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$/;
|
|
9
|
+
/** Discover interrupted native attempts. Inventory is a hint, never proof of
|
|
10
|
+
* process death or permission to release resources. The retained recovery
|
|
11
|
+
* driver rechecks SQL, exact guard evidence and OS process birth identities. */
|
|
12
|
+
function createEntityboxRecoveryWorker(config, io) {
|
|
13
|
+
if (config.enabled !== true)
|
|
14
|
+
return undefined;
|
|
15
|
+
if (!uuid.test(config.runtimeId) || !/^[-a-zA-Z0-9_.]{1,80}$/.test(config.dockerContext))
|
|
16
|
+
throw new Error('Invalid native recovery configuration');
|
|
17
|
+
const settings = Object.freeze({ ...config }), store = new entitybox_recovery_store_1.EntityboxRecoveryStore(settings.directory), now = io.clock ?? Date.now;
|
|
18
|
+
const owners = new Map();
|
|
19
|
+
let stopped = false, started = false, flight, timer;
|
|
20
|
+
const token = () => {
|
|
21
|
+
const p = io.pairing();
|
|
22
|
+
if (stopped || !p || p.runtimeId !== settings.runtimeId || !p.daemonToken)
|
|
23
|
+
throw new Error('Recovery unavailable');
|
|
24
|
+
return p.daemonToken;
|
|
25
|
+
};
|
|
26
|
+
const report = (state, id) => { try {
|
|
27
|
+
io.report?.(state, id);
|
|
28
|
+
}
|
|
29
|
+
catch { } };
|
|
30
|
+
async function inventory() {
|
|
31
|
+
const rows = [], seen = new Set();
|
|
32
|
+
let after = null;
|
|
33
|
+
for (let page = 0; page < 10; page++) {
|
|
34
|
+
const values = await (0, entitybox_operation_1.entityboxOperation)([], 4500, () => io.rpc('entitybox_native_execution_inventory', { p_token: token(), p_after: after, p_limit: 50 }));
|
|
35
|
+
token();
|
|
36
|
+
if (!Array.isArray(values) || values.length > 50)
|
|
37
|
+
throw new Error();
|
|
38
|
+
for (const value of values) {
|
|
39
|
+
if (!value || ![value.attemptId, value.requestId].every(v => typeof v === 'string' && uuid.test(v))
|
|
40
|
+
|| !['running', 'stop_requested'].includes(value.phase) || seen.has(value.attemptId)
|
|
41
|
+
|| after !== null && value.attemptId <= after)
|
|
42
|
+
throw new Error();
|
|
43
|
+
const scope = (0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(value.scope);
|
|
44
|
+
if (scope.runtimeId !== settings.runtimeId || value.runId !== scope.runId)
|
|
45
|
+
throw new Error();
|
|
46
|
+
seen.add(value.attemptId);
|
|
47
|
+
after = value.attemptId;
|
|
48
|
+
rows.push({ attemptId: value.attemptId, requestId: value.requestId, scope });
|
|
49
|
+
}
|
|
50
|
+
if (values.length < 50)
|
|
51
|
+
return rows;
|
|
52
|
+
}
|
|
53
|
+
throw new Error();
|
|
54
|
+
}
|
|
55
|
+
async function run() {
|
|
56
|
+
try {
|
|
57
|
+
const rows = await inventory();
|
|
58
|
+
const present = new Set(rows.map(r => r.attemptId));
|
|
59
|
+
// SQL no longer lists a completed attempt. Drop only local retry state;
|
|
60
|
+
// never touch its old physical bindings after replacement has begun.
|
|
61
|
+
for (const id of owners.keys())
|
|
62
|
+
if (!present.has(id))
|
|
63
|
+
owners.delete(id);
|
|
64
|
+
for (const identity of rows) {
|
|
65
|
+
if (stopped)
|
|
66
|
+
return;
|
|
67
|
+
const active = io.activeRequests();
|
|
68
|
+
if (!Array.isArray(active) || !active.every(id => typeof id === 'string' && uuid.test(id)))
|
|
69
|
+
throw new Error();
|
|
70
|
+
if (active.includes(identity.requestId))
|
|
71
|
+
continue;
|
|
72
|
+
let retained = owners.get(identity.attemptId);
|
|
73
|
+
if (retained && (0, entitybox_recovery_store_1.entityboxCanonical)(retained.identity) !== (0, entitybox_recovery_store_1.entityboxCanonical)(identity))
|
|
74
|
+
throw new Error();
|
|
75
|
+
if (retained && now() < retained.retryAt)
|
|
76
|
+
continue;
|
|
77
|
+
try {
|
|
78
|
+
token();
|
|
79
|
+
if (!retained) {
|
|
80
|
+
// Live guards have not written a stop receipt. Reading a receipt
|
|
81
|
+
// does not assert its owner died; the driver must still prove it.
|
|
82
|
+
const evidence = store.readProof(identity.attemptId).value;
|
|
83
|
+
if ((0, entitybox_recovery_store_1.entityboxCanonical)(evidence.identity) !== (0, entitybox_recovery_store_1.entityboxCanonical)(identity)
|
|
84
|
+
|| evidence.host.hostId !== store.hostId || evidence.host.dockerContext !== settings.dockerContext)
|
|
85
|
+
throw new Error();
|
|
86
|
+
if (owners.size >= 500)
|
|
87
|
+
throw new Error();
|
|
88
|
+
const options = { identity, store, dockerContext: settings.dockerContext, token, rpc: io.rpc };
|
|
89
|
+
const owner = io.recover ? io.recover(options) : new entitybox_controller_recovery_1.EntityboxControllerRecovery(options);
|
|
90
|
+
retained = { identity, owner, failures: 0, retryAt: 0 };
|
|
91
|
+
owners.set(identity.attemptId, retained);
|
|
92
|
+
}
|
|
93
|
+
await retained.owner.run();
|
|
94
|
+
token();
|
|
95
|
+
owners.delete(identity.attemptId);
|
|
96
|
+
report('recovered', identity.attemptId);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
if (retained) {
|
|
100
|
+
retained.failures++;
|
|
101
|
+
retained.retryAt = now() + Math.min(300000, 5000 * 2 ** Math.min(retained.failures - 1, 6));
|
|
102
|
+
}
|
|
103
|
+
report(retained ? 'attention' : 'waiting', identity.attemptId);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
if (!stopped)
|
|
109
|
+
report('unavailable');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function tick() { if (stopped)
|
|
113
|
+
return Promise.resolve(); if (!flight)
|
|
114
|
+
flight = run().finally(() => { flight = undefined; }); return flight; }
|
|
115
|
+
function schedule() { if (stopped)
|
|
116
|
+
return; timer = setTimeout(() => { void tick().finally(schedule); }, 15000); timer.unref?.(); }
|
|
117
|
+
return {
|
|
118
|
+
tick,
|
|
119
|
+
start() { if (started || stopped)
|
|
120
|
+
return; started = true; void tick().finally(schedule); },
|
|
121
|
+
stop() { stopped = true; clearTimeout(timer); },
|
|
122
|
+
async drain(timeoutMs = 15000) {
|
|
123
|
+
if (!flight)
|
|
124
|
+
return true;
|
|
125
|
+
let deadline;
|
|
126
|
+
try {
|
|
127
|
+
return await Promise.race([flight.then(() => true), new Promise(resolve => { deadline = setTimeout(() => resolve(false), Math.max(0, timeoutMs)); })]);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
clearTimeout(deadline);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type EntityboxExecutionLease } from './entitybox-execution-lease';
|
|
2
|
+
interface Configuration {
|
|
3
|
+
/** Trusted request configuration and native-resolved MCP identity only. */
|
|
4
|
+
itemId: string;
|
|
5
|
+
entityKey: string;
|
|
6
|
+
/** Isolated test transport; never supplied by a model or renderer. */
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
export declare function entityboxAnthropicKey(values: unknown): string;
|
|
10
|
+
/** Reuse the existing entity-authenticated Vault MCP get_login operation.
|
|
11
|
+
* Each lookup checks the current Vault grant; no secret cache, host login
|
|
12
|
+
* directory, environment fallback or credential file is used. */
|
|
13
|
+
export declare class EntityboxVaultProvider {
|
|
14
|
+
private readonly lease;
|
|
15
|
+
private readonly config;
|
|
16
|
+
constructor(lease: EntityboxExecutionLease, config: Configuration);
|
|
17
|
+
apiKey(signal: AbortSignal): Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
/** Construct the contained broker's API provider from server-verified native
|
|
20
|
+
* selection. The entity key comes from the read-only native desktop resolver.
|
|
21
|
+
* Every inference lookup rechecks that selection before asking Vault, so a
|
|
22
|
+
* revoked or changed binding cannot quietly switch credentials mid-task. */
|
|
23
|
+
export declare function entityboxNativeProvider(lease: EntityboxExecutionLease, entityKey: string, signal: AbortSignal, transport?: typeof fetch): Promise<{
|
|
24
|
+
models: readonly string[];
|
|
25
|
+
apiKey: (signal: AbortSignal) => Promise<string>;
|
|
26
|
+
}>;
|
|
27
|
+
export {};
|