@moxt-ai/mobius 0.0.5 → 0.0.7
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/acp/activity.d.ts +7 -2
- package/dist/acp/activity.d.ts.map +1 -1
- package/dist/acp/activity.js +95 -7
- package/dist/acp/activity.js.map +1 -1
- package/dist/acp/native-session.d.ts +30 -0
- package/dist/acp/native-session.d.ts.map +1 -0
- package/dist/acp/native-session.js +25 -0
- package/dist/acp/native-session.js.map +1 -0
- package/dist/acp/session-history.d.ts +9 -0
- package/dist/acp/session-history.d.ts.map +1 -0
- package/dist/acp/session-history.js +69 -0
- package/dist/acp/session-history.js.map +1 -0
- package/dist/acp/session-manager.d.ts +16 -5
- package/dist/acp/session-manager.d.ts.map +1 -1
- package/dist/acp/session-manager.js +210 -25
- package/dist/acp/session-manager.js.map +1 -1
- package/dist/acp/session-store.d.ts +9 -0
- package/dist/acp/session-store.d.ts.map +1 -1
- package/dist/acp/session-store.js +43 -0
- package/dist/acp/session-store.js.map +1 -1
- package/dist/agent-catalog/discover-local-agents.d.ts +1 -1
- package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
- package/dist/agent-catalog/discover-local-agents.js +19 -30
- package/dist/agent-catalog/discover-local-agents.js.map +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.d.ts +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.js +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
- package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
- package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
- package/dist/agent-installation/fixed-installation-executor.js +9 -18
- package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
- package/dist/agent-installation/installation-grants.d.ts.map +1 -1
- package/dist/agent-installation/installation-grants.js +1 -2
- package/dist/agent-installation/installation-grants.js.map +1 -1
- package/dist/agent-installation/managed-adapter-installer.d.ts +0 -1
- package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
- package/dist/agent-installation/managed-adapter-installer.js +1 -3
- package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
- package/dist/authorization/local-authorization-error.d.ts +5 -0
- package/dist/authorization/local-authorization-error.d.ts.map +1 -0
- package/dist/authorization/local-authorization-error.js +8 -0
- package/dist/authorization/local-authorization-error.js.map +1 -0
- package/dist/authorization/workspace-directory.d.ts +16 -5
- package/dist/authorization/workspace-directory.d.ts.map +1 -1
- package/dist/authorization/workspace-directory.js +109 -119
- package/dist/authorization/workspace-directory.js.map +1 -1
- package/dist/cli.js +2881 -739
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts +3 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -6
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2895 -788
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/codex-history.d.ts +11 -0
- package/dist/native-sessions/codex-history.d.ts.map +1 -0
- package/dist/native-sessions/codex-history.js +223 -0
- package/dist/native-sessions/codex-history.js.map +1 -0
- package/dist/native-sessions/service.d.ts +14 -0
- package/dist/native-sessions/service.d.ts.map +1 -0
- package/dist/native-sessions/service.js +254 -0
- package/dist/native-sessions/service.js.map +1 -0
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +41 -31
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/process/executable.d.ts +1 -1
- package/dist/process/executable.d.ts.map +1 -1
- package/dist/process/executable.js +3 -11
- package/dist/process/executable.js.map +1 -1
- package/dist/relay-connection/liveness.d.ts.map +1 -1
- package/dist/relay-connection/liveness.js +1 -2
- package/dist/relay-connection/liveness.js.map +1 -1
- package/dist/relay-connection/session-event-outbox.d.ts +19 -0
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -0
- package/dist/relay-connection/session-event-outbox.js +182 -0
- package/dist/relay-connection/session-event-outbox.js.map +1 -0
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +340 -244
- package/dist/run-daemon.js.map +1 -1
- package/package.json +3 -2
- package/dist/authorization/authorize-binding.d.ts +0 -6
- package/dist/authorization/authorize-binding.d.ts.map +0 -1
- package/dist/authorization/authorize-binding.js +0 -30
- package/dist/authorization/authorize-binding.js.map +0 -1
package/dist/run-daemon.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { basename } from "node:path";
|
|
3
|
-
import { AGENT_ACTIVITY_KIND, AGENT_INSTALL_AWAITING_APPROVAL_KIND, AGENT_INSTALL_CANCEL_KIND, AGENT_INSTALL_CANCELLED_KIND, AGENT_INSTALL_COMPLETED_KIND, AGENT_INSTALL_FAILED_KIND, AGENT_INSTALL_PROGRESS_KIND, AGENT_INSTALL_REQUEST_KIND, AGENT_INSTALL_STARTED_KIND, AGENT_MESSAGE_DELTA_KIND, decodeAgentInstallCancelCommand, decodeAgentInstallRequestCommand, decodeMessageKind, decodeRuntimeHeartbeatAckEvent, decodeRuntimeLivenessReadyEvent, decodeSessionCancelCommand, decodeSessionConfigureCommand, decodeSessionElicitationRespondCommand, decodeSessionPermissionRespondCommand, decodeSessionPrepareCommand, decodeSessionPromptCommand, decodeWorkspaceListCommand, encodeAgentActivityEvent, encodeAgentContentEvent, encodeAgentInstallAwaitingApprovalEvent, encodeAgentInstallCancelledEvent, encodeAgentInstallCompletedEvent, encodeAgentInstallFailedEvent, encodeAgentInstallProgressEvent, encodeAgentInstallStartedEvent, encodeAgentMessageDeltaEvent, encodeSessionCommandsUpdatedEvent, encodeSessionCompletedEvent, encodeSessionConfigUpdatedEvent, encodeSessionElicitationRequestedEvent, encodeSessionElicitationResolvedEvent, encodeSessionFailedEvent, encodeSessionInfoUpdatedEvent, encodeSessionOperationFailedEvent, encodeSessionPermissionRequestedEvent, encodeSessionPermissionResolvedEvent, encodeSessionReadyEvent, encodeSessionStartedEvent, encodeSessionUsageUpdatedEvent, encodeWorkspaceEntriesEvent,
|
|
2
|
+
import { AGENT_ACTIVITY_KIND, AGENT_INSTALL_AWAITING_APPROVAL_KIND, AGENT_INSTALL_CANCEL_KIND, AGENT_INSTALL_CANCELLED_KIND, AGENT_INSTALL_COMPLETED_KIND, AGENT_INSTALL_FAILED_KIND, AGENT_INSTALL_PROGRESS_KIND, AGENT_INSTALL_REQUEST_KIND, AGENT_INSTALL_STARTED_KIND, AGENT_MESSAGE_DELTA_KIND, decodeAgentInstallCancelCommand, decodeAgentInstallRequestCommand, decodeMessageKind, decodeNativeSessionCancel, decodeNativeSessionCommand, decodeRuntimeHeartbeatAckEvent, decodeRuntimeLivenessReadyEvent, decodeSessionCancelCommand, decodeSessionConfigureCommand, decodeSessionElicitationRespondCommand, decodeSessionEventAcknowledgement, decodeSessionPermissionRespondCommand, decodeSessionPrepareCommand, decodeSessionPromptCommand, decodeWorkspaceListCommand, encodeAgentActivityEvent, encodeAgentContentEvent, encodeAgentInstallAwaitingApprovalEvent, encodeAgentInstallCancelledEvent, encodeAgentInstallCompletedEvent, encodeAgentInstallFailedEvent, encodeAgentInstallProgressEvent, encodeAgentInstallStartedEvent, encodeAgentMessageDeltaEvent, encodeNativeSessionResult, encodeSessionCommandsUpdatedEvent, encodeSessionCompletedEvent, encodeSessionConfigUpdatedEvent, encodeSessionElicitationRequestedEvent, encodeSessionElicitationResolvedEvent, encodeSessionFailedEvent, encodeSessionInfoUpdatedEvent, encodeSessionOperationFailedEvent, encodeSessionPermissionRequestedEvent, encodeSessionPermissionResolvedEvent, encodeSessionReadyEvent, encodeSessionStartedEvent, encodeSessionUsageUpdatedEvent, encodeWorkspaceEntriesEvent, NATIVE_SESSION_CANCEL_KIND, NATIVE_SESSION_REQUEST_KIND, RUNTIME_HEARTBEAT_ACK_KIND, RUNTIME_LIVENESS_READY_KIND, SESSION_CANCEL_KIND, SESSION_COMPLETED_KIND, SESSION_CONFIGURE_KIND, SESSION_ELICITATION_RESPOND_KIND, SESSION_EVENT_ACK_KIND, SESSION_FAILED_KIND, SESSION_PERMISSION_RESPOND_KIND, SESSION_PREPARE_KIND, SESSION_PROMPT_KIND, SESSION_STARTED_KIND, WORKSPACE_LIST_KIND, } from "@moxt-ai/mobius-protocol";
|
|
4
3
|
import { WebSocket } from "undici";
|
|
5
4
|
import { AcpExecutionError, AcpSessionManager, NullAcpSessionObserver, } from "./acp/session-manager.js";
|
|
6
5
|
import { SqliteAcpSessionStore } from "./acp/session-store.js";
|
|
@@ -12,10 +11,12 @@ import { AutomaticAdapterProvisioner } from "./agent-installation/automatic-adap
|
|
|
12
11
|
import { FixedInstallationExecutor } from "./agent-installation/fixed-installation-executor.js";
|
|
13
12
|
import { ConsoleInstallationAuthorizer } from "./agent-installation/local-installation-authorizer.js";
|
|
14
13
|
import { ManagedAdapterInstaller } from "./agent-installation/managed-adapter-installer.js";
|
|
15
|
-
import { LocalAuthorizationError } from "./authorization/
|
|
14
|
+
import { LocalAuthorizationError } from "./authorization/local-authorization-error.js";
|
|
16
15
|
import { WorkspaceDirectoryService } from "./authorization/workspace-directory.js";
|
|
16
|
+
import { NativeSessionService } from "./native-sessions/service.js";
|
|
17
17
|
import { connectRelay } from "./relay-connection/connect.js";
|
|
18
18
|
import { RelayConnectionLiveness } from "./relay-connection/liveness.js";
|
|
19
|
+
import { SessionEventOutbox } from "./relay-connection/session-event-outbox.js";
|
|
19
20
|
import { systemDaemonTimer, } from "./relay-connection/timer.js";
|
|
20
21
|
import { readStateDirectory } from "./storage/state-directory.js";
|
|
21
22
|
const RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
@@ -71,44 +72,44 @@ class RelayConnectionRefresh {
|
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
class DaemonAcpObserver {
|
|
74
|
-
#
|
|
75
|
-
constructor(
|
|
76
|
-
this.#
|
|
75
|
+
#record;
|
|
76
|
+
constructor(record) {
|
|
77
|
+
this.#record = record;
|
|
77
78
|
}
|
|
78
79
|
onCommands = (event) => {
|
|
79
|
-
|
|
80
|
+
this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
|
|
80
81
|
return Promise.resolve();
|
|
81
82
|
};
|
|
82
83
|
onConfig = (event) => {
|
|
83
|
-
|
|
84
|
+
this.#record(event.sessionId, encodeSessionConfigUpdatedEvent(event));
|
|
84
85
|
return Promise.resolve();
|
|
85
86
|
};
|
|
86
87
|
onContent = (event) => {
|
|
87
|
-
|
|
88
|
+
this.#record(event.sessionId, encodeAgentContentEvent(event));
|
|
88
89
|
return Promise.resolve();
|
|
89
90
|
};
|
|
90
91
|
onElicitation = (event) => {
|
|
91
|
-
|
|
92
|
+
this.#record(event.sessionId, encodeSessionElicitationRequestedEvent(event));
|
|
92
93
|
return Promise.resolve();
|
|
93
94
|
};
|
|
94
95
|
onElicitationResolved = (event) => {
|
|
95
|
-
|
|
96
|
+
this.#record(event.sessionId, encodeSessionElicitationResolvedEvent(event));
|
|
96
97
|
return Promise.resolve();
|
|
97
98
|
};
|
|
98
99
|
onInfo = (event) => {
|
|
99
|
-
|
|
100
|
+
this.#record(event.sessionId, encodeSessionInfoUpdatedEvent(event));
|
|
100
101
|
return Promise.resolve();
|
|
101
102
|
};
|
|
102
103
|
onPermission = (event) => {
|
|
103
|
-
|
|
104
|
+
this.#record(event.sessionId, encodeSessionPermissionRequestedEvent(event));
|
|
104
105
|
return Promise.resolve();
|
|
105
106
|
};
|
|
106
107
|
onPermissionResolved = (event) => {
|
|
107
|
-
|
|
108
|
+
this.#record(event.sessionId, encodeSessionPermissionResolvedEvent(event));
|
|
108
109
|
return Promise.resolve();
|
|
109
110
|
};
|
|
110
111
|
onUsage = (event) => {
|
|
111
|
-
|
|
112
|
+
this.#record(event.sessionId, encodeSessionUsageUpdatedEvent(event));
|
|
112
113
|
return Promise.resolve();
|
|
113
114
|
};
|
|
114
115
|
}
|
|
@@ -159,7 +160,6 @@ class DaemonInstallationObserver {
|
|
|
159
160
|
this.#send(socket, encodeAgentInstallAwaitingApprovalEvent({
|
|
160
161
|
agentId: state.agentId,
|
|
161
162
|
kind: AGENT_INSTALL_AWAITING_APPROVAL_KIND,
|
|
162
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
163
163
|
requestId: state.requestId,
|
|
164
164
|
}));
|
|
165
165
|
return Promise.resolve();
|
|
@@ -170,14 +170,12 @@ class DaemonInstallationObserver {
|
|
|
170
170
|
this.#send(socket, encodeAgentInstallStartedEvent({
|
|
171
171
|
agentId: state.agentId,
|
|
172
172
|
kind: AGENT_INSTALL_STARTED_KIND,
|
|
173
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
174
173
|
requestId: state.requestId,
|
|
175
174
|
}));
|
|
176
175
|
}
|
|
177
176
|
this.#send(socket, encodeAgentInstallProgressEvent({
|
|
178
177
|
agentId: state.agentId,
|
|
179
178
|
kind: AGENT_INSTALL_PROGRESS_KIND,
|
|
180
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
181
179
|
requestId: state.requestId,
|
|
182
180
|
stage: state.stage,
|
|
183
181
|
}));
|
|
@@ -188,7 +186,6 @@ class DaemonInstallationObserver {
|
|
|
188
186
|
agentId: state.agentId,
|
|
189
187
|
authenticationMayBeRequired: state.authenticationMayBeRequired,
|
|
190
188
|
kind: AGENT_INSTALL_COMPLETED_KIND,
|
|
191
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
192
189
|
requestId: state.requestId,
|
|
193
190
|
}));
|
|
194
191
|
return Promise.resolve();
|
|
@@ -199,7 +196,6 @@ class DaemonInstallationObserver {
|
|
|
199
196
|
code: state.code,
|
|
200
197
|
kind: AGENT_INSTALL_FAILED_KIND,
|
|
201
198
|
message: state.message,
|
|
202
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
203
199
|
requestId: state.requestId,
|
|
204
200
|
}));
|
|
205
201
|
return Promise.resolve();
|
|
@@ -208,7 +204,6 @@ class DaemonInstallationObserver {
|
|
|
208
204
|
this.#send(socket, encodeAgentInstallCancelledEvent({
|
|
209
205
|
agentId: state.agentId,
|
|
210
206
|
kind: AGENT_INSTALL_CANCELLED_KIND,
|
|
211
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
212
207
|
requestId: state.requestId,
|
|
213
208
|
}));
|
|
214
209
|
return Promise.resolve();
|
|
@@ -256,18 +251,20 @@ function send(socket, message) {
|
|
|
256
251
|
}
|
|
257
252
|
socket.send(message);
|
|
258
253
|
}
|
|
259
|
-
function
|
|
260
|
-
|
|
261
|
-
|
|
254
|
+
function recordSessionEvent(outbox, socket, sessionId, payload, attemptId = null) {
|
|
255
|
+
const envelope = outbox.enqueue(sessionId, payload, attemptId);
|
|
256
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
257
|
+
socket.send(envelope);
|
|
262
258
|
}
|
|
263
|
-
|
|
259
|
+
}
|
|
260
|
+
function reportFailure(outbox, socket, command, code, message, attemptId = null) {
|
|
261
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeSessionFailedEvent({
|
|
264
262
|
code,
|
|
265
263
|
commandId: command.commandId,
|
|
266
264
|
kind: SESSION_FAILED_KIND,
|
|
267
265
|
message,
|
|
268
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
269
266
|
sessionId: command.sessionId,
|
|
270
|
-
}));
|
|
267
|
+
}), attemptId);
|
|
271
268
|
}
|
|
272
269
|
function operationErrorCode(error) {
|
|
273
270
|
if (error instanceof AcpExecutionError ||
|
|
@@ -293,18 +290,17 @@ function reportOperationFailure(socket, requestId, sessionId, error) {
|
|
|
293
290
|
code: operationErrorCode(error),
|
|
294
291
|
kind: "session.operation.failed",
|
|
295
292
|
message: operationErrorMessage(error),
|
|
296
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
297
293
|
requestId,
|
|
298
294
|
sessionId,
|
|
299
295
|
}));
|
|
300
296
|
}
|
|
301
|
-
async function resolveSessionDirectories(directories, bindingId, directoryId, additionalDirectoryIds) {
|
|
302
|
-
const cwd = await directories.resolve(bindingId, directoryId);
|
|
297
|
+
async function resolveSessionDirectories(directories, bindingId, directoryId, additionalDirectoryIds, signal) {
|
|
298
|
+
const cwd = await directories.resolve(bindingId, directoryId, signal);
|
|
303
299
|
const additionalDirectories = [];
|
|
304
300
|
const additionalDirectoryEntries = [];
|
|
305
301
|
const unique = new Set([cwd]);
|
|
306
302
|
for (const additionalDirectoryId of additionalDirectoryIds) {
|
|
307
|
-
const directory = await directories.resolve(bindingId, additionalDirectoryId);
|
|
303
|
+
const directory = await directories.resolve(bindingId, additionalDirectoryId, signal);
|
|
308
304
|
if (unique.has(directory)) {
|
|
309
305
|
throw new LocalAuthorizationError("Workspace directories must resolve to distinct locations");
|
|
310
306
|
}
|
|
@@ -317,9 +313,9 @@ async function resolveSessionDirectories(directories, bindingId, directoryId, ad
|
|
|
317
313
|
}
|
|
318
314
|
return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
|
|
319
315
|
}
|
|
320
|
-
async function executeWorkspaceList(socket, command, directories, audit) {
|
|
316
|
+
async function executeWorkspaceList(socket, command, directories, audit, signal) {
|
|
321
317
|
try {
|
|
322
|
-
const listing = await directories.list(command.bindingId, command.directoryId);
|
|
318
|
+
const listing = await directories.list(command.bindingId, command.directoryId, signal);
|
|
323
319
|
audit.record({
|
|
324
320
|
commandId: command.requestId,
|
|
325
321
|
event: "workspace_list_authorized",
|
|
@@ -332,7 +328,6 @@ async function executeWorkspaceList(socket, command, directories, audit) {
|
|
|
332
328
|
entries: listing.entries,
|
|
333
329
|
kind: "workspace.entries",
|
|
334
330
|
parentDirectoryId: listing.parentDirectoryId,
|
|
335
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
336
331
|
requestId: command.requestId,
|
|
337
332
|
}));
|
|
338
333
|
}
|
|
@@ -340,9 +335,9 @@ async function executeWorkspaceList(socket, command, directories, audit) {
|
|
|
340
335
|
reportOperationFailure(socket, command.requestId, "", error);
|
|
341
336
|
}
|
|
342
337
|
}
|
|
343
|
-
async function executeSessionPrepare(socket, command, config, directories, audit, sessions, signal) {
|
|
338
|
+
async function executeSessionPrepare(outbox, socket, command, config, directories, audit, sessions, signal) {
|
|
344
339
|
try {
|
|
345
|
-
const resolved = await resolveSessionDirectories(directories,
|
|
340
|
+
const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
|
|
346
341
|
const agent = config.catalog.find(command.agentId);
|
|
347
342
|
const prepared = await sessions.prepareSession({
|
|
348
343
|
additionalDirectories: resolved.additionalDirectories,
|
|
@@ -351,13 +346,13 @@ async function executeSessionPrepare(socket, command, config, directories, audit
|
|
|
351
346
|
sessionId: command.sessionId,
|
|
352
347
|
signal,
|
|
353
348
|
});
|
|
354
|
-
const listing = await directories.list(
|
|
349
|
+
const listing = await directories.list(config.bindingId, command.directoryId, signal);
|
|
355
350
|
audit.record({
|
|
356
351
|
commandId: command.requestId,
|
|
357
352
|
event: "session_prepared",
|
|
358
353
|
sessionId: command.sessionId,
|
|
359
354
|
});
|
|
360
|
-
|
|
355
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeSessionReadyEvent({
|
|
361
356
|
additionalDirectories: resolved.additionalDirectoryEntries,
|
|
362
357
|
agentId: command.agentId,
|
|
363
358
|
agentName: prepared.agentName,
|
|
@@ -368,7 +363,6 @@ async function executeSessionPrepare(socket, command, config, directories, audit
|
|
|
368
363
|
directoryId: command.directoryId,
|
|
369
364
|
directoryLabel: listing.directoryLabel,
|
|
370
365
|
kind: "session.ready",
|
|
371
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
372
366
|
requestId: command.requestId,
|
|
373
367
|
restored: prepared.restored,
|
|
374
368
|
sessionId: command.sessionId,
|
|
@@ -378,9 +372,9 @@ async function executeSessionPrepare(socket, command, config, directories, audit
|
|
|
378
372
|
reportOperationFailure(socket, command.requestId, command.sessionId, error);
|
|
379
373
|
}
|
|
380
374
|
}
|
|
381
|
-
async function executeSessionConfigure(socket, command, config, directories, audit, sessions, signal) {
|
|
375
|
+
async function executeSessionConfigure(outbox, socket, command, config, directories, audit, sessions, signal) {
|
|
382
376
|
try {
|
|
383
|
-
const resolved = await resolveSessionDirectories(directories,
|
|
377
|
+
const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
|
|
384
378
|
const configOptions = await sessions.configureSession({
|
|
385
379
|
additionalDirectories: resolved.additionalDirectories,
|
|
386
380
|
agent: config.catalog.find(command.agentId),
|
|
@@ -398,10 +392,9 @@ async function executeSessionConfigure(socket, command, config, directories, aud
|
|
|
398
392
|
event: "session_configured",
|
|
399
393
|
sessionId: command.sessionId,
|
|
400
394
|
});
|
|
401
|
-
|
|
395
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeSessionConfigUpdatedEvent({
|
|
402
396
|
configOptions,
|
|
403
397
|
kind: "session.config.updated",
|
|
404
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
405
398
|
requestId: command.requestId,
|
|
406
399
|
sessionId: command.sessionId,
|
|
407
400
|
}));
|
|
@@ -410,23 +403,22 @@ async function executeSessionConfigure(socket, command, config, directories, aud
|
|
|
410
403
|
reportOperationFailure(socket, command.requestId, command.sessionId, error);
|
|
411
404
|
}
|
|
412
405
|
}
|
|
413
|
-
async function executePrompt(socket, command, config, directories, audit, sessions, signal) {
|
|
406
|
+
async function executePrompt(outbox, socket, command, config, directories, audit, sessions, attemptId, signal) {
|
|
414
407
|
try {
|
|
415
|
-
const resolved = await resolveSessionDirectories(directories,
|
|
408
|
+
const resolved = await resolveSessionDirectories(directories, config.bindingId, command.directoryId, command.additionalDirectoryIds, signal);
|
|
416
409
|
const agent = config.catalog.find(command.agentId);
|
|
417
|
-
const processAttemptId = randomUUID();
|
|
418
410
|
audit.record({
|
|
419
411
|
commandId: command.commandId,
|
|
420
412
|
event: "session_authorized",
|
|
421
413
|
sessionId: command.sessionId,
|
|
422
414
|
});
|
|
423
|
-
|
|
415
|
+
outbox.transitionExecution(command.commandId, "running");
|
|
416
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeSessionStartedEvent({
|
|
424
417
|
commandId: command.commandId,
|
|
425
418
|
kind: SESSION_STARTED_KIND,
|
|
426
|
-
|
|
427
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
419
|
+
attemptId,
|
|
428
420
|
sessionId: command.sessionId,
|
|
429
|
-
}));
|
|
421
|
+
}), attemptId);
|
|
430
422
|
const result = await sessions.runPrompt({
|
|
431
423
|
additionalDirectories: resolved.additionalDirectories,
|
|
432
424
|
agent,
|
|
@@ -434,33 +426,32 @@ async function executePrompt(socket, command, config, directories, audit, sessio
|
|
|
434
426
|
cwd: resolved.cwd,
|
|
435
427
|
images: command.images,
|
|
436
428
|
onActivity: (activity) => {
|
|
437
|
-
|
|
429
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeAgentActivityEvent({
|
|
438
430
|
activityId: activity.activityId,
|
|
439
431
|
activityType: activity.activityType,
|
|
440
432
|
commandId: command.commandId,
|
|
441
433
|
content: activity.content,
|
|
434
|
+
detail: activity.detail,
|
|
442
435
|
input: activity.input,
|
|
443
436
|
kind: AGENT_ACTIVITY_KIND,
|
|
444
437
|
locations: activity.locations,
|
|
445
438
|
name: activity.name,
|
|
446
439
|
output: activity.output,
|
|
447
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
448
440
|
sequence: activity.sequence,
|
|
449
441
|
sessionId: command.sessionId,
|
|
450
442
|
status: activity.status,
|
|
451
443
|
title: activity.title,
|
|
452
444
|
toolKind: activity.toolKind,
|
|
453
|
-
}));
|
|
445
|
+
}), attemptId);
|
|
454
446
|
return Promise.resolve();
|
|
455
447
|
},
|
|
456
448
|
onText: (text) => {
|
|
457
|
-
|
|
449
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeAgentMessageDeltaEvent({
|
|
458
450
|
commandId: command.commandId,
|
|
459
451
|
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
460
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
461
452
|
sessionId: command.sessionId,
|
|
462
453
|
text,
|
|
463
|
-
}));
|
|
454
|
+
}), attemptId);
|
|
464
455
|
return Promise.resolve();
|
|
465
456
|
},
|
|
466
457
|
prompt: command.prompt,
|
|
@@ -468,13 +459,13 @@ async function executePrompt(socket, command, config, directories, audit, sessio
|
|
|
468
459
|
sessionId: command.sessionId,
|
|
469
460
|
signal,
|
|
470
461
|
});
|
|
471
|
-
|
|
462
|
+
recordSessionEvent(outbox, socket, command.sessionId, encodeSessionCompletedEvent({
|
|
472
463
|
commandId: command.commandId,
|
|
473
464
|
kind: SESSION_COMPLETED_KIND,
|
|
474
|
-
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
475
465
|
sessionId: command.sessionId,
|
|
476
466
|
stopReason: result.stopReason,
|
|
477
|
-
}));
|
|
467
|
+
}), attemptId);
|
|
468
|
+
outbox.transitionExecution(command.commandId, result.stopReason === "cancelled" ? "cancelled" : "succeeded");
|
|
478
469
|
audit.record({
|
|
479
470
|
commandId: command.commandId,
|
|
480
471
|
event: result.stopReason === "cancelled"
|
|
@@ -490,9 +481,10 @@ async function executePrompt(socket, command, config, directories, audit, sessio
|
|
|
490
481
|
sessionId: command.sessionId,
|
|
491
482
|
});
|
|
492
483
|
const code = operationErrorCode(error);
|
|
493
|
-
reportFailure(socket, command, code === "session_operation_failed" ? "agent_execution_failed" : code, code === "session_operation_failed"
|
|
484
|
+
reportFailure(outbox, socket, command, code === "session_operation_failed" ? "agent_execution_failed" : code, code === "session_operation_failed"
|
|
494
485
|
? "The local agent could not complete the request"
|
|
495
|
-
: operationErrorMessage(error));
|
|
486
|
+
: operationErrorMessage(error), attemptId);
|
|
487
|
+
outbox.transitionExecution(command.commandId, "failed");
|
|
496
488
|
console.error("Mobius daemon command failed", error);
|
|
497
489
|
}
|
|
498
490
|
}
|
|
@@ -510,215 +502,313 @@ function waitForRelayRetry(signal, timer) {
|
|
|
510
502
|
signal.addEventListener("abort", finish, { once: true });
|
|
511
503
|
});
|
|
512
504
|
}
|
|
513
|
-
async function runRelayConnection(config, directories, audit, sessions, installations, installationObserver, signal, timer) {
|
|
505
|
+
async function runRelayConnection(config, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer) {
|
|
514
506
|
const relayUrl = new URL(config.relayUrl);
|
|
515
507
|
relayUrl.searchParams.set("liveness", "1");
|
|
516
508
|
const socket = await connectRelay(relayUrl, signal);
|
|
517
509
|
const activeTurns = new Map();
|
|
510
|
+
const activeAttemptIds = new Map();
|
|
518
511
|
const connectionController = new AbortController();
|
|
519
|
-
|
|
512
|
+
const nativeRequests = new Map();
|
|
513
|
+
const record = (sessionId, payload) => {
|
|
514
|
+
recordSessionEvent(outbox, socket, sessionId, payload, activeAttemptIds.get(sessionId) ?? null);
|
|
515
|
+
};
|
|
516
|
+
sessions.setObserver(new DaemonAcpObserver(record));
|
|
520
517
|
installationObserver.connect(socket);
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
resolveConnection();
|
|
560
|
-
};
|
|
561
|
-
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
562
|
-
send: (message) => send(socket, message),
|
|
563
|
-
unresponsive: () => {
|
|
564
|
-
socket.close(4001, "Relay liveness check timed out");
|
|
518
|
+
for (const pending of outbox.pending()) {
|
|
519
|
+
send(socket, pending);
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
await new Promise((resolve, reject) => {
|
|
523
|
+
let finished = false;
|
|
524
|
+
const cleanup = () => {
|
|
525
|
+
connectionRefresh.close();
|
|
526
|
+
connectionLiveness.close();
|
|
527
|
+
signal.removeEventListener("abort", stop);
|
|
528
|
+
socket.removeEventListener("close", handleClose);
|
|
529
|
+
socket.removeEventListener("error", handleError);
|
|
530
|
+
socket.removeEventListener("message", handleMessage);
|
|
531
|
+
installationObserver.disconnect(socket);
|
|
532
|
+
connectionController.abort();
|
|
533
|
+
for (const turn of activeTurns.values()) {
|
|
534
|
+
turn.abortConnection();
|
|
535
|
+
}
|
|
536
|
+
activeTurns.clear();
|
|
537
|
+
};
|
|
538
|
+
const resolveConnection = () => {
|
|
539
|
+
if (finished) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
finished = true;
|
|
543
|
+
cleanup();
|
|
544
|
+
resolve();
|
|
545
|
+
};
|
|
546
|
+
const rejectConnection = () => {
|
|
547
|
+
if (finished) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
finished = true;
|
|
551
|
+
cleanup();
|
|
552
|
+
reject(new Error("Relay WebSocket failed"));
|
|
553
|
+
};
|
|
554
|
+
const stop = () => {
|
|
555
|
+
socket.close(1000, "Daemon stopped");
|
|
565
556
|
resolveConnection();
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
570
|
-
const handleClose = () => {
|
|
571
|
-
resolveConnection();
|
|
572
|
-
};
|
|
573
|
-
const handleError = () => {
|
|
574
|
-
if (signal.aborted) {
|
|
557
|
+
};
|
|
558
|
+
const refreshConnection = () => {
|
|
559
|
+
socket.close(1000, "Refreshing idle relay connection");
|
|
575
560
|
resolveConnection();
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
561
|
+
};
|
|
562
|
+
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
563
|
+
send: (message) => send(socket, message),
|
|
564
|
+
unresponsive: () => {
|
|
565
|
+
socket.close(4001, "Relay liveness check timed out");
|
|
566
|
+
resolveConnection();
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
const connectionRefresh = new RelayConnectionRefresh(timer, () => activeTurns.size === 0, refreshConnection);
|
|
570
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
571
|
+
const handleClose = () => {
|
|
572
|
+
resolveConnection();
|
|
573
|
+
};
|
|
574
|
+
const handleError = () => {
|
|
575
|
+
if (signal.aborted) {
|
|
576
|
+
resolveConnection();
|
|
592
577
|
return;
|
|
593
578
|
}
|
|
594
|
-
|
|
595
|
-
|
|
579
|
+
rejectConnection();
|
|
580
|
+
};
|
|
581
|
+
const handleMessage = (event) => {
|
|
582
|
+
const encoded = event.data;
|
|
583
|
+
if (typeof encoded !== "string") {
|
|
584
|
+
socket.close(4003, "Text message required");
|
|
585
|
+
rejectConnection();
|
|
596
586
|
return;
|
|
597
587
|
}
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
console.warn("Mobius daemon ignored cancellation for an inactive turn");
|
|
588
|
+
try {
|
|
589
|
+
const kind = decodeMessageKind(encoded);
|
|
590
|
+
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
591
|
+
outbox.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
603
592
|
return;
|
|
604
593
|
}
|
|
605
|
-
if (
|
|
594
|
+
if (kind === NATIVE_SESSION_CANCEL_KIND) {
|
|
595
|
+
const command = decodeNativeSessionCancel(encoded);
|
|
596
|
+
const pending = nativeRequests.get(command.requestId);
|
|
597
|
+
if (pending?.sessionId === command.sessionId)
|
|
598
|
+
pending.controller.abort(new AcpExecutionError("Native session operation cancelled", {}, "native_session_cancelled"));
|
|
606
599
|
return;
|
|
607
600
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
601
|
+
if (kind === NATIVE_SESSION_REQUEST_KIND) {
|
|
602
|
+
const command = decodeNativeSessionCommand(encoded);
|
|
603
|
+
const previous = [...nativeRequests.values()].filter((request) => request.agentId === command.agentId);
|
|
604
|
+
if (nativeRequests.has(command.requestId) ||
|
|
605
|
+
nativeRequests.size >= 4 ||
|
|
606
|
+
previous.some((request) => !request.controller.signal.aborted)) {
|
|
607
|
+
reportOperationFailure(socket, command.requestId, command.sessionId, new AcpExecutionError("Another native session operation is running", {}, "native_session_busy"));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const controller = new AbortController();
|
|
611
|
+
const operationSignal = AbortSignal.any([
|
|
612
|
+
connectionController.signal,
|
|
613
|
+
controller.signal,
|
|
614
|
+
]);
|
|
615
|
+
const timeout = timer.schedule(() => controller.abort(new AcpExecutionError("Native session operation timed out", {}, "native_session_timeout")), 90_000);
|
|
616
|
+
const completion = (async () => {
|
|
617
|
+
try {
|
|
618
|
+
operationSignal.throwIfAborted();
|
|
619
|
+
if (previous.length > 0) {
|
|
620
|
+
await new Promise((resolve, reject) => {
|
|
621
|
+
const cancel = () => reject(operationSignal.reason);
|
|
622
|
+
operationSignal.addEventListener("abort", cancel, {
|
|
623
|
+
once: true,
|
|
624
|
+
});
|
|
625
|
+
void Promise.all(previous.map((request) => request.completion)).then(() => {
|
|
626
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
627
|
+
resolve();
|
|
628
|
+
}, (error) => {
|
|
629
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
630
|
+
reject(error);
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
operationSignal.throwIfAborted();
|
|
635
|
+
const result = await nativeSessions.execute(command, operationSignal);
|
|
636
|
+
if (socket.readyState === WebSocket.OPEN)
|
|
637
|
+
send(socket, encodeNativeSessionResult(result));
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
const failure = operationSignal.aborted
|
|
641
|
+
? (controller.signal.reason ??
|
|
642
|
+
new AcpExecutionError("Native session operation cancelled", {}, "native_session_cancelled"))
|
|
643
|
+
: error;
|
|
644
|
+
audit.record({
|
|
645
|
+
commandId: command.requestId,
|
|
646
|
+
sessionId: command.sessionId,
|
|
647
|
+
event: "native_session_operation_failed",
|
|
648
|
+
details: { code: operationErrorCode(failure) },
|
|
649
|
+
});
|
|
650
|
+
reportOperationFailure(socket, command.requestId, command.sessionId, failure);
|
|
651
|
+
}
|
|
652
|
+
finally {
|
|
653
|
+
timeout.cancel();
|
|
654
|
+
nativeRequests.delete(command.requestId);
|
|
655
|
+
}
|
|
656
|
+
})();
|
|
657
|
+
nativeRequests.set(command.requestId, {
|
|
658
|
+
agentId: command.agentId,
|
|
641
659
|
sessionId: command.sessionId,
|
|
660
|
+
controller,
|
|
661
|
+
completion,
|
|
642
662
|
});
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (kind === RUNTIME_LIVENESS_READY_KIND) {
|
|
666
|
+
decodeRuntimeLivenessReadyEvent(encoded);
|
|
667
|
+
connectionLiveness.start();
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
|
|
671
|
+
connectionLiveness.acknowledge(decodeRuntimeHeartbeatAckEvent(encoded));
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (kind === SESSION_CANCEL_KIND) {
|
|
675
|
+
const cancellation = decodeSessionCancelCommand(encoded);
|
|
676
|
+
const turn = activeTurns.get(cancellation.commandId);
|
|
677
|
+
if (turn === undefined || !turn.matches(cancellation)) {
|
|
678
|
+
console.warn("Mobius daemon ignored cancellation for an inactive turn");
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
if (!turn.requestCancellation()) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
654
684
|
audit.record({
|
|
655
|
-
commandId:
|
|
656
|
-
event: "
|
|
657
|
-
sessionId:
|
|
685
|
+
commandId: cancellation.commandId,
|
|
686
|
+
event: "session_cancellation_requested",
|
|
687
|
+
sessionId: cancellation.sessionId,
|
|
658
688
|
});
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
689
|
+
void sessions
|
|
690
|
+
.cancelPrompt(cancellation.sessionId)
|
|
691
|
+
.catch((error) => {
|
|
692
|
+
console.error("Mobius daemon could not cancel the agent turn", error);
|
|
693
|
+
});
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (kind === WORKSPACE_LIST_KIND) {
|
|
697
|
+
const command = decodeWorkspaceListCommand(encoded);
|
|
698
|
+
void executeWorkspaceList(socket, command, directories, audit, connectionController.signal);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if (kind === SESSION_PREPARE_KIND) {
|
|
702
|
+
const command = decodeSessionPrepareCommand(encoded);
|
|
703
|
+
void executeSessionPrepare(outbox, socket, command, config, directories, audit, sessions, connectionController.signal);
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
if (kind === SESSION_CONFIGURE_KIND) {
|
|
707
|
+
const command = decodeSessionConfigureCommand(encoded);
|
|
708
|
+
void executeSessionConfigure(outbox, socket, command, config, directories, audit, sessions, connectionController.signal);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
if (kind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
712
|
+
const command = decodeSessionPermissionRespondCommand(encoded);
|
|
713
|
+
void sessions
|
|
714
|
+
.respondPermission(command)
|
|
715
|
+
.then(() => {
|
|
716
|
+
audit.record({
|
|
717
|
+
commandId: command.interactionId,
|
|
718
|
+
event: "session_permission_resolved",
|
|
719
|
+
sessionId: command.sessionId,
|
|
720
|
+
});
|
|
721
|
+
})
|
|
722
|
+
.catch((error) => {
|
|
723
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error);
|
|
724
|
+
});
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (kind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
728
|
+
const command = decodeSessionElicitationRespondCommand(encoded);
|
|
729
|
+
void sessions
|
|
730
|
+
.respondElicitation(command)
|
|
731
|
+
.then(() => {
|
|
732
|
+
audit.record({
|
|
733
|
+
commandId: command.interactionId,
|
|
734
|
+
event: "session_elicitation_resolved",
|
|
735
|
+
sessionId: command.sessionId,
|
|
736
|
+
});
|
|
737
|
+
})
|
|
738
|
+
.catch((error) => {
|
|
739
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error);
|
|
740
|
+
});
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (kind === AGENT_INSTALL_REQUEST_KIND) {
|
|
744
|
+
const command = decodeAgentInstallRequestCommand(encoded);
|
|
745
|
+
void installations
|
|
746
|
+
.request(command, signal)
|
|
747
|
+
.catch((error) => {
|
|
748
|
+
console.error("Mobius Agent installation failed", error);
|
|
749
|
+
});
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (kind === AGENT_INSTALL_CANCEL_KIND) {
|
|
753
|
+
const command = decodeAgentInstallCancelCommand(encoded);
|
|
754
|
+
void installations
|
|
755
|
+
.cancel(command.requestId)
|
|
756
|
+
.catch((error) => {
|
|
757
|
+
reportOperationFailure(socket, command.requestId, "", error);
|
|
758
|
+
});
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (kind !== SESSION_PROMPT_KIND) {
|
|
762
|
+
throw new Error("Unsupported protocol message");
|
|
763
|
+
}
|
|
764
|
+
const command = decodeSessionPromptCommand(encoded);
|
|
765
|
+
if (activeTurns.has(command.commandId)) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const receipt = outbox.claimExecution(command.commandId, command.sessionId, encoded);
|
|
769
|
+
if (receipt.kind === "duplicate") {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
const turn = new ActiveDaemonTurn(command, new AbortController());
|
|
773
|
+
activeTurns.set(command.commandId, turn);
|
|
774
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
775
|
+
void executePrompt(outbox, socket, command, config, directories, audit, sessions, receipt.attemptId, turn.signal)
|
|
678
776
|
.catch((error) => {
|
|
679
|
-
|
|
777
|
+
console.error("Mobius daemon turn failed", error);
|
|
778
|
+
})
|
|
779
|
+
.finally(() => {
|
|
780
|
+
activeTurns.delete(command.commandId);
|
|
781
|
+
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
782
|
+
activeAttemptIds.delete(command.sessionId);
|
|
783
|
+
}
|
|
784
|
+
connectionRefresh.afterTurnFinished();
|
|
680
785
|
});
|
|
681
|
-
return;
|
|
682
786
|
}
|
|
683
|
-
|
|
684
|
-
|
|
787
|
+
catch (error) {
|
|
788
|
+
console.error("Mobius daemon rejected a message", error);
|
|
789
|
+
socket.close(4008, "Invalid protocol message");
|
|
790
|
+
rejectConnection();
|
|
685
791
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
activeTurns.set(command.commandId, turn);
|
|
693
|
-
void executePrompt(socket, command, config, directories, audit, sessions, turn.signal)
|
|
694
|
-
.catch((error) => {
|
|
695
|
-
console.error("Mobius daemon turn failed", error);
|
|
696
|
-
})
|
|
697
|
-
.finally(() => {
|
|
698
|
-
activeTurns.delete(command.commandId);
|
|
699
|
-
connectionRefresh.afterTurnFinished();
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
catch (error) {
|
|
703
|
-
console.error("Mobius daemon rejected a message", error);
|
|
704
|
-
socket.close(4008, "Invalid protocol message");
|
|
705
|
-
rejectConnection();
|
|
792
|
+
};
|
|
793
|
+
socket.addEventListener("close", handleClose);
|
|
794
|
+
socket.addEventListener("error", handleError);
|
|
795
|
+
socket.addEventListener("message", handleMessage);
|
|
796
|
+
if (signal.aborted) {
|
|
797
|
+
stop();
|
|
706
798
|
}
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
714
|
-
});
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
finally {
|
|
802
|
+
connectionController.abort();
|
|
803
|
+
await Promise.all([...nativeRequests.values()].map((request) => request.completion));
|
|
804
|
+
}
|
|
715
805
|
}
|
|
716
806
|
export async function runDaemon(config, audit, signal, timer = systemDaemonTimer) {
|
|
717
807
|
const installationAudit = new AuditInstallationEvents(audit);
|
|
718
808
|
const stateDirectory = readStateDirectory();
|
|
719
809
|
const specifications = supportedLocalAgentSpecifications();
|
|
720
810
|
const installationExecutor = new FixedInstallationExecutor({
|
|
721
|
-
|
|
811
|
+
defaultWorkspace: config.defaultWorkspace,
|
|
722
812
|
audit: installationAudit,
|
|
723
813
|
catalog: config.catalog,
|
|
724
814
|
environment: process.env,
|
|
@@ -726,26 +816,27 @@ export async function runDaemon(config, audit, signal, timer = systemDaemonTimer
|
|
|
726
816
|
stateDirectory,
|
|
727
817
|
});
|
|
728
818
|
await new AutomaticAdapterProvisioner({
|
|
729
|
-
|
|
819
|
+
defaultWorkspace: config.defaultWorkspace,
|
|
730
820
|
audit: installationAudit,
|
|
731
821
|
catalog: config.catalog,
|
|
732
822
|
environment: process.env,
|
|
733
823
|
}, new ManagedAdapterInstaller({
|
|
734
|
-
approvedRoot: config.approvedRoot,
|
|
735
824
|
environment: process.env,
|
|
736
825
|
stateDirectory,
|
|
737
826
|
}), specifications).prepare(signal);
|
|
738
827
|
const sessionStore = new SqliteAcpSessionStore(config.auditDatabasePath);
|
|
828
|
+
const outbox = new SessionEventOutbox(config.auditDatabasePath);
|
|
739
829
|
const sessions = new AcpSessionManager(new NullAcpSessionObserver(), sessionStore);
|
|
740
|
-
const directories = new WorkspaceDirectoryService(config.bindingId, config.
|
|
830
|
+
const directories = new WorkspaceDirectoryService(config.bindingId, config.defaultWorkspace);
|
|
741
831
|
const installationObserver = new DaemonInstallationObserver();
|
|
832
|
+
const nativeSessions = new NativeSessionService(config, directories, sessions, audit);
|
|
742
833
|
const installations = new AgentInstallationManager(specifications, new ConsoleInstallationAuthorizer(stateDirectory), installationExecutor, installationObserver, installationAudit);
|
|
743
834
|
let retryAnnounced = false;
|
|
744
835
|
try {
|
|
745
836
|
while (!signal.aborted) {
|
|
746
837
|
try {
|
|
747
838
|
await publishAgentCatalog(config, signal);
|
|
748
|
-
await runRelayConnection(config, directories, audit, sessions, installations, installationObserver, signal, timer);
|
|
839
|
+
await runRelayConnection(config, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, signal, timer);
|
|
749
840
|
retryAnnounced = false;
|
|
750
841
|
}
|
|
751
842
|
catch {
|
|
@@ -769,7 +860,12 @@ export async function runDaemon(config, audit, signal, timer = systemDaemonTimer
|
|
|
769
860
|
await sessions.close();
|
|
770
861
|
}
|
|
771
862
|
finally {
|
|
772
|
-
|
|
863
|
+
try {
|
|
864
|
+
sessionStore.close();
|
|
865
|
+
}
|
|
866
|
+
finally {
|
|
867
|
+
outbox.close();
|
|
868
|
+
}
|
|
773
869
|
}
|
|
774
870
|
}
|
|
775
871
|
}
|