@myagentroam/node 0.9.94 → 0.9.96
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/computer-use-runtime-version.js +1 -0
- package/dist/computer-use-runtime.js +330 -0
- package/dist/config.js +35 -1
- package/dist/connector.js +49 -7
- package/dist/ctags-binary.js +18 -0
- package/dist/runner/mar-agent/computer-use.js +750 -0
- package/dist/runner/mar-agent/managed-run-controller.js +55 -7
- package/dist/service/computer-use-enablement-service.js +172 -0
- package/dist/service/continuous-run-coordinator.js +1 -0
- package/dist/service/node-connection-lifecycle-service.js +1 -0
- package/dist/service/session-lifecycle-service.js +1 -0
- package/dist/service/session-message-service.js +1 -0
- package/dist/service/workspace-code-navigation-service.js +1219 -0
- package/dist/service/workspace-content-search-service.js +55 -25
- package/dist/service/workspace-file-service.js +1 -1
- package/dist/service/workspace-workbench-service.js +28 -1
- package/dist/workspace.js +70 -6
- package/package.json +7 -4
- package/vendor/ctags/NOTICE +10 -0
- package/vendor/ctags/licenses/COPYING +340 -0
- package/vendor/ctags/licenses/COPYING.MinGW-w64-runtime.txt +240 -0
- package/vendor/ctags/licenses/LICENSE.janssen +19 -0
- package/vendor/ctags/licenses/LICENSE.libyaml +19 -0
- package/vendor/ctags/linux-x64/ctags +0 -0
- package/vendor/ctags/manifest.json +25 -0
- package/vendor/ctags/source/universal-ctags-6.2.1.tar.gz +0 -0
- package/vendor/ctags/win32-x64/ctags.exe +0 -0
|
@@ -24,6 +24,7 @@ export class MarAgentManagedRunController {
|
|
|
24
24
|
#resourceIdleTtlMs;
|
|
25
25
|
#createAgent;
|
|
26
26
|
#modelFactory;
|
|
27
|
+
#computerUse;
|
|
27
28
|
#disposePromise;
|
|
28
29
|
#disposed = false;
|
|
29
30
|
constructor(runner, host, options = {}) {
|
|
@@ -43,6 +44,7 @@ export class MarAgentManagedRunController {
|
|
|
43
44
|
};
|
|
44
45
|
})
|
|
45
46
|
};
|
|
47
|
+
this.#computerUse = options.computerUse;
|
|
46
48
|
}
|
|
47
49
|
dispose() {
|
|
48
50
|
if (this.#disposePromise !== undefined)
|
|
@@ -56,6 +58,7 @@ export class MarAgentManagedRunController {
|
|
|
56
58
|
execution.cancel();
|
|
57
59
|
await Promise.all([...new Set(this.#sessionRuntimes.values())].map((runtime) => this.#releaseRuntime(runtime)));
|
|
58
60
|
await this.#mcpClients.close();
|
|
61
|
+
await this.#computerUse?.dispose();
|
|
59
62
|
})();
|
|
60
63
|
return this.#disposePromise;
|
|
61
64
|
}
|
|
@@ -66,11 +69,17 @@ export class MarAgentManagedRunController {
|
|
|
66
69
|
const release = (async () => {
|
|
67
70
|
await this.#runtimeAcquisitions.get(sessionId)?.catch(() => undefined);
|
|
68
71
|
const runtime = this.#sessionRuntimes.get(sessionId);
|
|
69
|
-
if (runtime === undefined)
|
|
72
|
+
if (runtime === undefined) {
|
|
73
|
+
await this.#computerUse?.releaseSession(sessionId);
|
|
70
74
|
return;
|
|
75
|
+
}
|
|
71
76
|
if (runtime.activeRunId !== undefined)
|
|
72
77
|
this.#executions.get(runtime.activeRunId)?.cancel();
|
|
73
78
|
await this.#releaseRuntime(runtime);
|
|
79
|
+
await Promise.all([
|
|
80
|
+
this.#computerUse?.releaseSession(sessionId),
|
|
81
|
+
this.#computerUse?.releaseSession(runtime.session.id)
|
|
82
|
+
]);
|
|
74
83
|
})();
|
|
75
84
|
const tracked = release.finally(() => {
|
|
76
85
|
if (this.#sessionReleases.get(sessionId) === tracked)
|
|
@@ -157,6 +166,8 @@ export class MarAgentManagedRunController {
|
|
|
157
166
|
...secretEnvironment,
|
|
158
167
|
...mcpSecretEnvironment
|
|
159
168
|
});
|
|
169
|
+
if (mcpServers.some((server) => server.name === 'computer'))
|
|
170
|
+
throw new Error('MAR_AGENT_MCP_RESERVED_NAMESPACE');
|
|
160
171
|
images = parseRunnerImageAttachments(payload.attachments);
|
|
161
172
|
}
|
|
162
173
|
catch {
|
|
@@ -190,7 +201,8 @@ export class MarAgentManagedRunController {
|
|
|
190
201
|
: {}),
|
|
191
202
|
...(typeof payload.personalInstructions === 'string'
|
|
192
203
|
? { personalInstructions: payload.personalInstructions }
|
|
193
|
-
: {})
|
|
204
|
+
: {}),
|
|
205
|
+
computerUseEnabled: payload.computerUse === true
|
|
194
206
|
});
|
|
195
207
|
}
|
|
196
208
|
cancel(runId, intent) {
|
|
@@ -230,6 +242,7 @@ export class MarAgentManagedRunController {
|
|
|
230
242
|
let runtime;
|
|
231
243
|
let executionMcpLease;
|
|
232
244
|
let executionMcpBinding;
|
|
245
|
+
let computerUseBinding;
|
|
233
246
|
try {
|
|
234
247
|
const sessionKey = input.externalSessionId ?? input.sessionId;
|
|
235
248
|
const acquisitionKeys = [...new Set([sessionKey, input.sessionId])];
|
|
@@ -257,16 +270,45 @@ export class MarAgentManagedRunController {
|
|
|
257
270
|
throw new Error('MAR_AGENT_SESSION_RUNTIME_ACTIVE');
|
|
258
271
|
runtime.activeRunId = input.runId;
|
|
259
272
|
const executionMcpServers = input.mcpServers.filter((server) => server.lifecycle === 'EXECUTION');
|
|
273
|
+
computerUseBinding = await this.#computerUse?.bind({
|
|
274
|
+
runId: input.runId,
|
|
275
|
+
sessionId: runtime.session.id,
|
|
276
|
+
mode: input.mode,
|
|
277
|
+
enabled: input.computerUseEnabled === true,
|
|
278
|
+
modelSupportsImages: input.model.inputCapabilities.includes('IMAGE')
|
|
279
|
+
});
|
|
280
|
+
if (this.#disposed ||
|
|
281
|
+
this.#sessionReleases.has(sessionKey) ||
|
|
282
|
+
this.#sessionReleases.has(input.sessionId) ||
|
|
283
|
+
this.#sessionReleases.has(runtime.session.id)) {
|
|
284
|
+
await computerUseBinding?.close().catch(() => undefined);
|
|
285
|
+
computerUseBinding = undefined;
|
|
286
|
+
await this.#computerUse?.releaseSession(runtime.session.id);
|
|
287
|
+
throw new Error('MAR_AGENT_SESSION_RUNTIME_RELEASED');
|
|
288
|
+
}
|
|
260
289
|
if (executionMcpServers.length > 0) {
|
|
261
290
|
executionMcpLease = await this.#mcpClients.acquire(executionMcpServers, input.cwd, {
|
|
262
291
|
reusable: false
|
|
263
292
|
});
|
|
264
|
-
|
|
293
|
+
}
|
|
294
|
+
const userTools = executionMcpLease?.pool.definitions() ?? [];
|
|
295
|
+
const nodeTools = computerUseBinding?.tools ?? [];
|
|
296
|
+
if (userTools.some((tool) => tool.name.startsWith('mcp__computer__')))
|
|
297
|
+
throw new Error('MAR_AGENT_MCP_RESERVED_NAMESPACE');
|
|
298
|
+
if (new Set([...userTools, ...nodeTools].map((tool) => tool.name)).size !==
|
|
299
|
+
userTools.length + nodeTools.length)
|
|
300
|
+
throw new Error('MAR_AGENT_MCP_TOOL_NAMES_CONFLICT');
|
|
301
|
+
if (userTools.length > 0 || nodeTools.length > 0)
|
|
265
302
|
executionMcpBinding = runtime.host.bindExecutionMcp({
|
|
266
|
-
tools:
|
|
267
|
-
call: async (call) =>
|
|
303
|
+
tools: [...nodeTools, ...userTools],
|
|
304
|
+
call: async (call, signal) => {
|
|
305
|
+
if (computerUseBinding?.tools.some((tool) => tool.name === call.name))
|
|
306
|
+
return computerUseBinding.call(call, signal);
|
|
307
|
+
if (executionMcpLease?.pool.definitions().some((tool) => tool.name === call.name))
|
|
308
|
+
return executionMcpLease.pool.call(call.name, call.arguments);
|
|
309
|
+
throw new Error('MAR_AGENT_MCP_TOOL_NOT_FOUND');
|
|
310
|
+
}
|
|
268
311
|
});
|
|
269
|
-
}
|
|
270
312
|
const session = runtime.session;
|
|
271
313
|
const reasoningEffort = input.effort
|
|
272
314
|
? marAgentReasoningEffortSchema.parse(input.effort)
|
|
@@ -330,6 +372,7 @@ export class MarAgentManagedRunController {
|
|
|
330
372
|
this.#normalizers.delete(input.runId);
|
|
331
373
|
this.host.active.delete(input.runId);
|
|
332
374
|
this.#executions.delete(input.runId);
|
|
375
|
+
await computerUseBinding?.close().catch(() => undefined);
|
|
333
376
|
runtime?.host.unbindExecutionMcp(executionMcpBinding);
|
|
334
377
|
await executionMcpLease?.release().catch(() => undefined);
|
|
335
378
|
if (runtime !== undefined)
|
|
@@ -511,7 +554,12 @@ export class MarAgentManagedRunController {
|
|
|
511
554
|
delete runtime.idleTimer;
|
|
512
555
|
}
|
|
513
556
|
try {
|
|
514
|
-
|
|
557
|
+
try {
|
|
558
|
+
await this.#computerUse?.releaseSession(runtime.session.id);
|
|
559
|
+
}
|
|
560
|
+
finally {
|
|
561
|
+
await runtime.agent.dispose();
|
|
562
|
+
}
|
|
515
563
|
}
|
|
516
564
|
finally {
|
|
517
565
|
await runtime.mcpLease.release().catch(() => undefined);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { computerUseDisableInputSchema, computerUseEnableInputSchema, computerUseEnableResultSchema } from '@myagentroam/protocol';
|
|
2
|
+
import { computerUseRuntimeExecutable, saveNodeConfig } from '../config.js';
|
|
3
|
+
import { nodeOperationData } from '../util/node-operation-data.js';
|
|
4
|
+
/** Persists Computer Use authorization and owns its asynchronous capability probe. */
|
|
5
|
+
export class ComputerUseEnablementService {
|
|
6
|
+
options;
|
|
7
|
+
#now;
|
|
8
|
+
#capability;
|
|
9
|
+
#probeGeneration = 0;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.#now = options.now ?? Date.now;
|
|
13
|
+
this.#capability = this.#disabled();
|
|
14
|
+
}
|
|
15
|
+
capability() {
|
|
16
|
+
return this.#capability;
|
|
17
|
+
}
|
|
18
|
+
operations() {
|
|
19
|
+
return {
|
|
20
|
+
'computer.use.enable': (data) => this.enable(data),
|
|
21
|
+
'computer.use.disable': (data) => this.disable(data)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
initialize() {
|
|
25
|
+
if (this.options.config()?.computerUse?.enabled !== true) {
|
|
26
|
+
this.#set(this.#disabled(), false);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.#beginProbe();
|
|
30
|
+
}
|
|
31
|
+
async enable(data) {
|
|
32
|
+
const parsed = computerUseEnableInputSchema.safeParse(nodeOperationData(data));
|
|
33
|
+
if (!parsed.success)
|
|
34
|
+
throw new Error('COMPUTER_USE_ENABLE_INPUT_INVALID');
|
|
35
|
+
const current = this.options.config();
|
|
36
|
+
if (current === undefined)
|
|
37
|
+
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
38
|
+
if (current.computerUse?.enabled !== true) {
|
|
39
|
+
const next = {
|
|
40
|
+
...current,
|
|
41
|
+
computerUse: {
|
|
42
|
+
...current.computerUse,
|
|
43
|
+
enabled: true
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
await saveNodeConfig(next, this.options.configPath);
|
|
47
|
+
this.options.setConfig(next);
|
|
48
|
+
}
|
|
49
|
+
this.#beginProbe();
|
|
50
|
+
return computerUseEnableResultSchema.parse({ capability: this.#capability });
|
|
51
|
+
}
|
|
52
|
+
async disable(data) {
|
|
53
|
+
const parsed = computerUseDisableInputSchema.safeParse(nodeOperationData(data));
|
|
54
|
+
if (!parsed.success)
|
|
55
|
+
throw new Error('COMPUTER_USE_DISABLE_INPUT_INVALID');
|
|
56
|
+
const current = this.options.config();
|
|
57
|
+
if (current === undefined)
|
|
58
|
+
throw new Error('NODE_CONFIG_UNAVAILABLE');
|
|
59
|
+
this.#probeGeneration += 1;
|
|
60
|
+
if (current.computerUse?.enabled === true) {
|
|
61
|
+
const next = {
|
|
62
|
+
...current,
|
|
63
|
+
computerUse: {
|
|
64
|
+
...current.computerUse,
|
|
65
|
+
enabled: false
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
this.options.setConfig(next);
|
|
69
|
+
try {
|
|
70
|
+
await this.options.provider.reset();
|
|
71
|
+
await saveNodeConfig(next, this.options.configPath);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.options.setConfig(current);
|
|
75
|
+
this.initialize();
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await this.options.provider.reset();
|
|
81
|
+
}
|
|
82
|
+
this.#set(this.#disabled());
|
|
83
|
+
return computerUseEnableResultSchema.parse({ capability: this.#capability });
|
|
84
|
+
}
|
|
85
|
+
#beginProbe() {
|
|
86
|
+
const config = this.options.config();
|
|
87
|
+
if (config === undefined || config.computerUse?.enabled !== true) {
|
|
88
|
+
this.#set(this.#disabled());
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const runtimeExecutable = computerUseRuntimeExecutable(config, this.options.configPath);
|
|
92
|
+
if (runtimeExecutable === undefined) {
|
|
93
|
+
this.#set(this.#unavailable('COMPUTER_RUNTIME_MISSING'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const generation = ++this.#probeGeneration;
|
|
97
|
+
this.#set({
|
|
98
|
+
apiVersion: 1,
|
|
99
|
+
enabled: true,
|
|
100
|
+
state: 'INITIALIZING',
|
|
101
|
+
backend: 'PYAUTOGUI',
|
|
102
|
+
supportsScreenshot: false,
|
|
103
|
+
supportsInput: false,
|
|
104
|
+
supportsUnicodePaste: false,
|
|
105
|
+
supportsPrimaryDisplay: false,
|
|
106
|
+
measuredAt: this.#now()
|
|
107
|
+
});
|
|
108
|
+
void this.options.provider
|
|
109
|
+
.reset()
|
|
110
|
+
.then(() => this.options.prepareRuntime())
|
|
111
|
+
.then(() => this.options.provider.support())
|
|
112
|
+
.then((support) => {
|
|
113
|
+
if (generation !== this.#probeGeneration)
|
|
114
|
+
return;
|
|
115
|
+
this.#set(this.#fromSupport(support));
|
|
116
|
+
})
|
|
117
|
+
.catch((error) => {
|
|
118
|
+
if (generation !== this.#probeGeneration)
|
|
119
|
+
return;
|
|
120
|
+
this.#set(this.#unavailable(error instanceof Error && /^[A-Z][A-Z0-9_]{0,79}$/u.test(error.message)
|
|
121
|
+
? error.message
|
|
122
|
+
: 'COMPUTER_PROBE_FAILED'));
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
#fromSupport(support) {
|
|
126
|
+
if (!support.available)
|
|
127
|
+
return this.#unavailable(support.reasonCode ?? 'COMPUTER_UNAVAILABLE', support);
|
|
128
|
+
return {
|
|
129
|
+
apiVersion: 1,
|
|
130
|
+
enabled: true,
|
|
131
|
+
state: 'AVAILABLE',
|
|
132
|
+
backend: 'PYAUTOGUI',
|
|
133
|
+
supportsScreenshot: support.supportsScreenshot,
|
|
134
|
+
supportsInput: support.supportsInput,
|
|
135
|
+
supportsUnicodePaste: support.supportsUnicodePaste,
|
|
136
|
+
supportsPrimaryDisplay: support.supportsPrimaryDisplay,
|
|
137
|
+
measuredAt: this.#now()
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
#disabled() {
|
|
141
|
+
return {
|
|
142
|
+
apiVersion: 1,
|
|
143
|
+
enabled: false,
|
|
144
|
+
state: 'DISABLED',
|
|
145
|
+
backend: 'PYAUTOGUI',
|
|
146
|
+
supportsScreenshot: false,
|
|
147
|
+
supportsInput: false,
|
|
148
|
+
supportsUnicodePaste: false,
|
|
149
|
+
supportsPrimaryDisplay: false,
|
|
150
|
+
measuredAt: this.#now()
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
#unavailable(reasonCode, support) {
|
|
154
|
+
return {
|
|
155
|
+
apiVersion: 1,
|
|
156
|
+
enabled: true,
|
|
157
|
+
state: 'UNAVAILABLE',
|
|
158
|
+
backend: 'PYAUTOGUI',
|
|
159
|
+
supportsScreenshot: support?.supportsScreenshot ?? false,
|
|
160
|
+
supportsInput: support?.supportsInput ?? false,
|
|
161
|
+
supportsUnicodePaste: support?.supportsUnicodePaste ?? false,
|
|
162
|
+
supportsPrimaryDisplay: support?.supportsPrimaryDisplay ?? false,
|
|
163
|
+
reasonCode,
|
|
164
|
+
measuredAt: this.#now()
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
#set(capability, publish = true) {
|
|
168
|
+
this.#capability = computerUseEnableResultSchema.parse({ capability }).capability;
|
|
169
|
+
if (publish)
|
|
170
|
+
this.options.publish(this.#capability);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -320,6 +320,7 @@ export class ContinuousRunCoordinator {
|
|
|
320
320
|
...(pending.marAgentRuntimeScopeId === undefined
|
|
321
321
|
? {}
|
|
322
322
|
: { marAgentRuntimeScopeId: pending.marAgentRuntimeScopeId }),
|
|
323
|
+
...(pending.computerUse === undefined ? {} : { computerUse: pending.computerUse }),
|
|
323
324
|
mcpInstallations: [
|
|
324
325
|
...this.options.mcps(pending.workspaceId),
|
|
325
326
|
...(missionMcp === undefined ? [] : [missionMcp.installation])
|
|
@@ -38,6 +38,7 @@ export class NodeConnectionLifecycleService {
|
|
|
38
38
|
? {}
|
|
39
39
|
: { conversationHosting: config.conversationHosting }),
|
|
40
40
|
...(config.directTransfer === undefined ? {} : { directTransfer: config.directTransfer }),
|
|
41
|
+
...(config.computerUse === undefined ? {} : { computerUse: config.computerUse }),
|
|
41
42
|
nodeId,
|
|
42
43
|
credential
|
|
43
44
|
};
|
|
@@ -215,6 +215,7 @@ export class SessionLifecycleService {
|
|
|
215
215
|
...(input.marAgentRuntimeScopeId === undefined
|
|
216
216
|
? {}
|
|
217
217
|
: { marAgentRuntimeScopeId: input.marAgentRuntimeScopeId }),
|
|
218
|
+
...(input.computerUse === undefined ? {} : { computerUse: input.computerUse }),
|
|
218
219
|
...(input.attachmentIds === undefined ? {} : { attachmentIds: input.attachmentIds })
|
|
219
220
|
}));
|
|
220
221
|
const nativeSessionId = await identity;
|
|
@@ -160,6 +160,7 @@ export class SessionMessageService {
|
|
|
160
160
|
...(input.marAgentRuntimeScopeId === undefined
|
|
161
161
|
? {}
|
|
162
162
|
: { marAgentRuntimeScopeId: input.marAgentRuntimeScopeId }),
|
|
163
|
+
...(input.computerUse === undefined ? {} : { computerUse: input.computerUse }),
|
|
163
164
|
...(missionMessage !== undefined
|
|
164
165
|
? { mission: missionMessage.mission }
|
|
165
166
|
: isMissionRef(input.__missionRef)
|