@myagentroam/node 0.9.0 → 0.9.3
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/connector.d.ts +2 -0
- package/dist/connector.js +50 -25
- package/dist/control-outbound-scheduler.d.ts +4 -1
- package/dist/control-outbound-scheduler.js +39 -6
- package/dist/database.d.ts +0 -19
- package/dist/database.js +1 -62
- package/dist/event-buffer.d.ts +2 -5
- package/dist/event-buffer.js +3 -12
- package/dist/native-session-history.js +105 -26
- package/dist/runner/abstract-runner.d.ts +1 -1
- package/dist/runner/abstract-runner.js +2 -2
- package/dist/runner/claude/managed-run-controller.d.ts +0 -1
- package/dist/runner/claude/managed-run-controller.js +32 -17
- package/dist/runner/claude-code-runner.js +3 -4
- package/dist/runner/codex/conversation-parser.d.ts +3 -3
- package/dist/runner/codex/conversation-parser.js +33 -12
- package/dist/runner/codex/managed-run-controller.d.ts +2 -2
- package/dist/runner/codex/managed-run-controller.js +26 -10
- package/dist/runner/codex-runner.d.ts +3 -1
- package/dist/runner/codex-runner.js +40 -10
- package/dist/runner/opencode/conversation-parser.d.ts +11 -7
- package/dist/runner/opencode/conversation-parser.js +16 -16
- package/dist/runner/opencode/managed-run-controller.d.ts +8 -2
- package/dist/runner/opencode/managed-run-controller.js +94 -22
- package/dist/runner/opencode-runner.d.ts +3 -0
- package/dist/runner/opencode-runner.js +25 -0
- package/dist/runner-command-engine.js +1 -1
- package/dist/runner-profiles.js +29 -17
- package/dist/runner-usage.js +5 -5
- package/dist/runtime-state.d.ts +5 -12
- package/dist/runtime-state.js +32 -46
- package/dist/service/attachment-domain-state.d.ts +2 -0
- package/dist/service/attachment-domain-state.js +2 -0
- package/dist/service/conversation-history-service.js +55 -24
- package/dist/service/conversation-segment-service.d.ts +20 -0
- package/dist/service/conversation-segment-service.js +156 -0
- package/dist/service/external-session-resume-service.js +9 -0
- package/dist/service/fake-managed-run-service.d.ts +0 -1
- package/dist/service/fake-managed-run-service.js +0 -2
- package/dist/service/mcp-installation-verifier.js +1 -1
- package/dist/service/native-session-projection-service.js +5 -0
- package/dist/service/native-session-watch-service.d.ts +1 -0
- package/dist/service/native-session-watch-service.js +21 -4
- package/dist/service/node-connection-lifecycle-service.d.ts +0 -2
- package/dist/service/node-connection-lifecycle-service.js +0 -1
- package/dist/service/node-control-channel.js +1 -1
- package/dist/service/node-control-message-service.d.ts +0 -1
- package/dist/service/node-control-message-service.js +9 -6
- package/dist/service/node-request-service.js +2 -1
- package/dist/service/node-workspace-coordinator.d.ts +1 -4
- package/dist/service/node-workspace-coordinator.js +2 -12
- package/dist/service/run-attachment-service.d.ts +3 -2
- package/dist/service/run-attachment-service.js +51 -17
- package/dist/service/run-event-service.d.ts +2 -0
- package/dist/service/run-event-service.js +77 -2
- package/dist/service/run-workbench-service.d.ts +1 -1
- package/dist/service/run-workbench-service.js +1 -5
- package/dist/service/runner-interaction-service.d.ts +1 -2
- package/dist/service/runner-interaction-service.js +1 -4
- package/dist/service/session-catalog-service.js +4 -4
- package/dist/service/session-context-service.d.ts +1 -0
- package/dist/service/session-context-service.js +14 -0
- package/dist/service/session-domain-state.d.ts +1 -0
- package/dist/service/session-domain-state.js +1 -0
- package/dist/service/session-message-service.js +5 -10
- package/dist/service/session-presentation-service.d.ts +1 -0
- package/dist/service/session-presentation-service.js +8 -1
- package/dist/service/session-query-service.d.ts +4 -0
- package/dist/service/session-query-service.js +6 -1
- package/dist/service/skill-directory-service.d.ts +3 -1
- package/dist/service/skill-directory-service.js +31 -30
- package/dist/service/skill-install-service.js +4 -74
- package/dist/service/skill-node-operation-service.d.ts +1 -1
- package/dist/service/skill-node-operation-service.js +6 -3
- package/dist/service/workbench-event-service.d.ts +1 -13
- package/dist/service/workbench-event-service.js +2 -36
- package/dist/service/workbench-manifest-service.d.ts +0 -1
- package/dist/service/workbench-manifest-service.js +0 -1
- package/dist/service/workspace-domain-state.d.ts +1 -0
- package/dist/service/workspace-git-exclude-service.d.ts +4 -0
- package/dist/service/workspace-git-exclude-service.js +119 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +1 -0
- package/dist/service/workspace-queue-workbench-service.js +4 -2
- package/dist/service/workspace-service.js +2 -0
- package/dist/service/workspace-upload-service.d.ts +2 -0
- package/dist/service/workspace-upload-service.js +28 -6
- package/dist/service/workspace-workbench-service.d.ts +0 -3
- package/dist/service/workspace-workbench-service.js +0 -17
- package/dist/supervisor.js +2 -1
- package/dist/terminal.js +1 -1
- package/dist/util/node-operation-parsers.js +2 -2
- package/dist/util/runner-error.d.ts +6 -0
- package/dist/util/runner-error.js +52 -0
- package/dist/util/runner-native-session-parsers.d.ts +2 -3
- package/dist/util/runner-native-session-parsers.js +48 -20
- package/dist/util/safe-error.d.ts +2 -0
- package/dist/util/safe-error.js +5 -0
- package/package.json +2 -2
package/dist/connector.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export declare class NodeConnector {
|
|
|
27
27
|
private readonly sessionIdentityService;
|
|
28
28
|
private readonly nativeSessionProjectionService;
|
|
29
29
|
private readonly conversationHistoryService;
|
|
30
|
+
private readonly conversationSegmentService;
|
|
30
31
|
private readonly runnerInteractionService;
|
|
31
32
|
private readonly runnerChannelMessages;
|
|
32
33
|
private readonly managedRunnerSessions;
|
|
@@ -78,6 +79,7 @@ export declare class NodeConnector {
|
|
|
78
79
|
private readonly handleMessage;
|
|
79
80
|
private readonly emitRunEvent;
|
|
80
81
|
private readonly emitConversationItem;
|
|
82
|
+
private readonly emitConversationTurn;
|
|
81
83
|
private readonly emitWorkbenchEvent;
|
|
82
84
|
private readonly discoverWorkspaceSessions;
|
|
83
85
|
private readonly invalidateWorkspaceWatchTopics;
|
package/dist/connector.js
CHANGED
|
@@ -44,6 +44,7 @@ import { WorkspaceQueueWorkbenchService } from './service/workspace-queue-workbe
|
|
|
44
44
|
import { SessionIdentityService } from './service/session-identity-service.js';
|
|
45
45
|
import { NativeSessionProjectionService } from './service/native-session-projection-service.js';
|
|
46
46
|
import { ConversationHistoryService, hasManagedActiveRun } from './service/conversation-history-service.js';
|
|
47
|
+
import { ConversationSegmentService, conversationSegmentIdentityForItem, conversationSegments } from './service/conversation-segment-service.js';
|
|
47
48
|
import { RunnerInteractionService } from './service/runner-interaction-service.js';
|
|
48
49
|
import { SessionLifecycleService } from './service/session-lifecycle-service.js';
|
|
49
50
|
import { ExternalSessionResumeService } from './service/external-session-resume-service.js';
|
|
@@ -51,7 +52,7 @@ import { SessionMessageService } from './service/session-message-service.js';
|
|
|
51
52
|
import { SessionCatalogService } from './service/session-catalog-service.js';
|
|
52
53
|
import { SessionCommandService } from './service/session-command-service.js';
|
|
53
54
|
import { SessionPresentationService } from './service/session-presentation-service.js';
|
|
54
|
-
import { isRunnerImageAttachment, parseRunnerImageAttachments } from './runner/codex/conversation-parser.js';
|
|
55
|
+
import { isPlainRecord, isRunnerImageAttachment, parseRunnerImageAttachments } from './runner/codex/conversation-parser.js';
|
|
55
56
|
export { nodeConnectEndpoint, validatedCapabilities } from './runner/codex/conversation-parser.js';
|
|
56
57
|
import { NodeControlChannel } from './service/node-control-channel.js';
|
|
57
58
|
import { NodeControlMessageService } from './service/node-control-message-service.js';
|
|
@@ -114,6 +115,7 @@ export class NodeConnector {
|
|
|
114
115
|
sessionIdentityService;
|
|
115
116
|
nativeSessionProjectionService;
|
|
116
117
|
conversationHistoryService;
|
|
118
|
+
conversationSegmentService;
|
|
117
119
|
runnerInteractionService;
|
|
118
120
|
runnerChannelMessages;
|
|
119
121
|
managedRunnerSessions;
|
|
@@ -173,7 +175,12 @@ export class NodeConnector {
|
|
|
173
175
|
isBootstrapSession: (sessionId) => this.sessionIdentityService.bootstrapIds.has(sessionId),
|
|
174
176
|
presentSession: (session) => this.sessionPresentationService.present(session),
|
|
175
177
|
rejectBootstrap: (sessionId, code) => this.sessionIdentityService.reject(sessionId, code),
|
|
176
|
-
emitWorkbench: (category, payload) =>
|
|
178
|
+
emitWorkbench: (category, payload) => {
|
|
179
|
+
if (category === 'conversation' && isPlainRecord(payload) && 'turn' in payload)
|
|
180
|
+
this.emitConversationTurn(payload.turn);
|
|
181
|
+
else
|
|
182
|
+
this.emitWorkbenchEvent(category, payload);
|
|
183
|
+
},
|
|
177
184
|
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
178
185
|
expireImages: (runId) => this.runAttachmentService.expire(runId),
|
|
179
186
|
scheduleContextRefresh: (sessionId) => this.sessionContextService.schedule(sessionId),
|
|
@@ -190,8 +197,9 @@ export class NodeConnector {
|
|
|
190
197
|
refreshActivity: (session) => this.conversationHistoryService.refreshExternalActivity(session),
|
|
191
198
|
present: (session) => this.sessionPresentationService.present(session),
|
|
192
199
|
readPage: (session, limit) => this.conversationHistoryService.read(session, { limit }),
|
|
200
|
+
projectInitialPage: (session, page, _unit, limit) => this.conversationSegmentService.projectInitial(session, page, limit),
|
|
193
201
|
emitSession: (session) => this.emitWorkbenchEvent('session', { session }),
|
|
194
|
-
emitTurn: (turn) => this.
|
|
202
|
+
emitTurn: (turn) => this.emitConversationTurn(turn)
|
|
195
203
|
});
|
|
196
204
|
constructor(options = {}) {
|
|
197
205
|
this.config = options.config;
|
|
@@ -230,7 +238,7 @@ export class NodeConnector {
|
|
|
230
238
|
this.fakeRunner =
|
|
231
239
|
options.fakeRunner === undefined ? undefined : new FakeTestRunner(options.fakeRunner);
|
|
232
240
|
this.fakeScript = options.fakeScript;
|
|
233
|
-
this.runAttachmentService = new RunAttachmentService((session) => this.runners.require(session.runner).
|
|
241
|
+
this.runAttachmentService = new RunAttachmentService((session) => this.runners.require(session.runner).nativeImageRoots(session));
|
|
234
242
|
this.codexClient = new CodexRunner(options.codexClient, options.codexProfileClientFactory);
|
|
235
243
|
this.codexRunController = new CodexManagedRunController(this.codexClient, {
|
|
236
244
|
available: () => this.capabilities.codex.available,
|
|
@@ -245,16 +253,15 @@ export class NodeConnector {
|
|
|
245
253
|
interrupted: (runId) => this.runState.interruptRequested.has(runId),
|
|
246
254
|
parseAttachments: parseRunnerImageAttachments,
|
|
247
255
|
materialize: (runId, attachments) => this.runAttachmentService.materializeCodex(runId, attachments),
|
|
248
|
-
completeCancelled: (runId
|
|
256
|
+
completeCancelled: (runId) => this.runnerInteractionService.completeCancelledRun(runId),
|
|
249
257
|
promoteSession: (sessionId, nativeSessionId) => this.sessionIdentityService.promote(sessionId, nativeSessionId),
|
|
250
258
|
send: (type, payload) => this.send(type, payload),
|
|
251
259
|
emit: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
252
260
|
cancel: (runId, threadId, turnId, cwd, status) => this.runnerInteractionService.cancelCodexTurn(runId, threadId, turnId, cwd, status),
|
|
253
261
|
createApproval: (input) => this.runtime.createApproval(input),
|
|
254
262
|
publishApproval: (input) => this.runEventBridge.publishApproval(input),
|
|
255
|
-
emitItem: (runId, item) => this.
|
|
263
|
+
emitItem: (runId, item) => this.emitConversationItem(runId, item),
|
|
256
264
|
appendImages: (runId, images) => this.runAttachmentService.append(runId, images.filter(isRunnerImageAttachment)),
|
|
257
|
-
captureSnapshot: (runId, cwd) => this.workspaceCoordinator.captureRunSnapshot(runId, cwd),
|
|
258
265
|
syncTitle: (sessionId, nativeSessionId, cwd) => this.managedRunnerSessions.refreshTitle(sessionId, nativeSessionId, cwd),
|
|
259
266
|
commandState: (sessionId, commandId) => this.commandStates.get(sessionId, commandId),
|
|
260
267
|
setCommandState: (sessionId, state) => this.commandStates.set(sessionId, state),
|
|
@@ -273,13 +280,20 @@ export class NodeConnector {
|
|
|
273
280
|
intercepted: () => this.fakeRunner !== undefined,
|
|
274
281
|
active: this.runState.active,
|
|
275
282
|
parseAttachments: parseRunnerImageAttachments,
|
|
283
|
+
persistAttachments: (cwd, runId, attachments) => this.runAttachmentService.persistFiles(cwd, `${runId}-opencode-images`, attachments),
|
|
276
284
|
emit: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
277
|
-
emitItem: (runId, item) => this.
|
|
285
|
+
emitItem: (runId, item) => this.emitConversationItem(runId, item),
|
|
278
286
|
adopt: (input) => this.runtime.adoptRun(input),
|
|
287
|
+
run: (runId) => {
|
|
288
|
+
const run = this.runtime.getRun(runId);
|
|
289
|
+
if (run === undefined)
|
|
290
|
+
throw new Error('RUN_NOT_FOUND');
|
|
291
|
+
return run;
|
|
292
|
+
},
|
|
293
|
+
hasActiveSessionLease: (sessionId) => this.runtime.hasActiveSessionLease(sessionId),
|
|
279
294
|
promote: (sessionId, nativeSessionId) => this.sessionIdentityService.promote(sessionId, nativeSessionId),
|
|
280
295
|
rememberNative: (nativeSessionId, sessionId) => this.managedRunnerSessions.remember(nativeSessionId, sessionId),
|
|
281
296
|
send: (type, payload) => this.send(type, payload),
|
|
282
|
-
captureSnapshot: (runId, cwd) => this.workspaceCoordinator.captureRunSnapshot(runId, cwd),
|
|
283
297
|
createApproval: (input) => this.runtime.createApproval(input),
|
|
284
298
|
expireApproval: (approvalId) => {
|
|
285
299
|
this.runtime.expireApproval(approvalId);
|
|
@@ -299,14 +313,13 @@ export class NodeConnector {
|
|
|
299
313
|
run: (runId) => this.runtime.getRun(runId),
|
|
300
314
|
hasActiveSessionLease: (sessionId) => this.runtime.hasActiveSessionLease(sessionId),
|
|
301
315
|
session: (sessionId) => this.runtime.getAgentSession(sessionId),
|
|
302
|
-
completeCancelled: (runId
|
|
303
|
-
captureSnapshot: (runId, cwd) => this.workspaceCoordinator.captureRunSnapshot(runId, cwd),
|
|
316
|
+
completeCancelled: (runId) => this.runnerInteractionService.completeCancelledRun(runId),
|
|
304
317
|
requestUserInput: (runId, input, toolUseId) => this.runnerInteractionService.requestClaudeUserInput(runId, input, toolUseId),
|
|
305
318
|
requestApproval: (runId, toolName, input) => this.runnerInteractionService.requestClaudeApproval(runId, toolName, input),
|
|
306
319
|
rememberNative: (nativeSessionId, sessionId) => this.managedRunnerSessions.remember(nativeSessionId, sessionId),
|
|
307
320
|
promote: (sessionId, nativeSessionId) => this.sessionIdentityService.promote(sessionId, nativeSessionId),
|
|
308
321
|
send: (type, payload) => this.send(type, payload),
|
|
309
|
-
emitItem: (runId, item) => this.
|
|
322
|
+
emitItem: (runId, item) => this.emitConversationItem(runId, item),
|
|
310
323
|
syncTitle: (sessionId, nativeSessionId, cwd) => this.managedRunnerSessions.refreshTitle(sessionId, nativeSessionId, cwd),
|
|
311
324
|
setChannelToken: (sessionId, token) => this.runtime.setChannelToken(sessionId, token),
|
|
312
325
|
commandState: (sessionId, commandId) => this.commandStates.get(sessionId, commandId),
|
|
@@ -330,8 +343,7 @@ export class NodeConnector {
|
|
|
330
343
|
claude: () => this.claudeClient,
|
|
331
344
|
runners: this.runners,
|
|
332
345
|
emitRun: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
333
|
-
emitItem: (runId, item) => this.
|
|
334
|
-
captureSnapshot: (runId, cwd) => this.workspaceCoordinator.captureRunSnapshot(runId, cwd),
|
|
346
|
+
emitItem: (runId, item) => this.emitConversationItem(runId, item),
|
|
335
347
|
approvalTimeoutMs: this.claudeApprovalTimeoutMs,
|
|
336
348
|
publishApproval: (input) => this.runEventBridge.publishApproval(input)
|
|
337
349
|
});
|
|
@@ -368,6 +380,7 @@ export class NodeConnector {
|
|
|
368
380
|
hasManagedActiveRun: (session) => hasManagedActiveRun(this.runtime, session),
|
|
369
381
|
setExternalActivity: (sessionId, activity) => this.sessionState.externalActivity.set(sessionId, activity)
|
|
370
382
|
});
|
|
383
|
+
this.conversationSegmentService = new ConversationSegmentService((session, input) => this.conversationHistoryService.read(session, input));
|
|
371
384
|
this.sessionContextService = new SessionContextService({
|
|
372
385
|
runners: this.runners,
|
|
373
386
|
session: (sessionId) => this.runtime.getAgentSession(sessionId),
|
|
@@ -381,6 +394,7 @@ export class NodeConnector {
|
|
|
381
394
|
respondUserInput: (runId, requestId, answers) => this.runnerInteractionService.respondUserInput(runId, requestId, answers),
|
|
382
395
|
deleteQueuedStart: (runId) => this.workspaceQueueWorkbenchService.remove(runId),
|
|
383
396
|
clearImages: (runId) => this.runAttachmentService.clear(runId),
|
|
397
|
+
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
384
398
|
emitQueue: (workspaceId, sessionId) => this.runEventBridge.emitQueue(workspaceId, sessionId),
|
|
385
399
|
emitRun: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
386
400
|
control: (operation, payload) => this.controlMessages.handle(JSON.stringify(createEnvelope(operation, payload))),
|
|
@@ -392,6 +406,7 @@ export class NodeConnector {
|
|
|
392
406
|
resolve: (sessionId) => this.nativeSessionProjectionService.resolve(sessionId),
|
|
393
407
|
present: (session) => this.sessionPresentationService.present(session),
|
|
394
408
|
history: (session, input) => this.conversationHistoryService.read(session, input),
|
|
409
|
+
segments: (session, input) => this.conversationSegmentService.read(session, input),
|
|
395
410
|
context: this.sessionContextService,
|
|
396
411
|
discover: (runner, workspaceId) => this.nativeSessionProjectionService.discover(runner, workspaceId),
|
|
397
412
|
workspaceIdForCwd: (cwd) => this.database?.listWorkspaces().find((candidate) => candidate.path === cwd)?.id
|
|
@@ -400,8 +415,9 @@ export class NodeConnector {
|
|
|
400
415
|
runtime: this.runtime,
|
|
401
416
|
emit: (workspaceId, sessionId) => this.runEventBridge.emitQueue(workspaceId, sessionId),
|
|
402
417
|
clearImages: (runId) => this.runAttachmentService.clear(runId),
|
|
418
|
+
cleanupAttachments: (runId) => this.runAttachmentService.cleanup(runId),
|
|
403
419
|
emitRun: (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status),
|
|
404
|
-
emitConversation: (turn) => this.
|
|
420
|
+
emitConversation: (turn) => this.emitConversationTurn(turn),
|
|
405
421
|
control: (operation, payload) => this.controlMessages.handle(JSON.stringify(createEnvelope(operation, payload))),
|
|
406
422
|
stopped: () => this.stopped,
|
|
407
423
|
markInterrupted: (runId) => this.runState.interruptRequested.add(runId),
|
|
@@ -428,7 +444,7 @@ export class NodeConnector {
|
|
|
428
444
|
emitSession: (session) => this.emitWorkbenchEvent('session', { session }),
|
|
429
445
|
emitRun: (run) => this.emitWorkbenchEvent('run', { run }),
|
|
430
446
|
emitQueue: (workspaceId, sessionId) => this.runEventBridge.emitQueue(workspaceId, sessionId),
|
|
431
|
-
emitTurn: (turn) => this.
|
|
447
|
+
emitTurn: (turn) => this.emitConversationTurn(turn)
|
|
432
448
|
});
|
|
433
449
|
this.sessionLifecycleService = new SessionLifecycleService({
|
|
434
450
|
database: () => {
|
|
@@ -554,7 +570,6 @@ export class NodeConnector {
|
|
|
554
570
|
state: this.runState,
|
|
555
571
|
emitRun: (runId, type, payload, status) => this.runEventBridge.emitRun(runId, type, payload, status),
|
|
556
572
|
publishApproval: (input) => this.runEventBridge.publishApproval(input),
|
|
557
|
-
captureSnapshot: (runId, cwd) => this.workspaceCoordinator.captureRunSnapshot(runId, cwd),
|
|
558
573
|
disconnect: () => this.controlChannel.close(4010, 'FAKE_RUNNER_DISCONNECT')
|
|
559
574
|
});
|
|
560
575
|
this.fakeRunner?.bindControl({
|
|
@@ -596,7 +611,7 @@ export class NodeConnector {
|
|
|
596
611
|
this.terminalChannel.disconnect();
|
|
597
612
|
if (code === 4000 && reason === 'NODE_CONNECTION_REPLACED')
|
|
598
613
|
nodeLog('node.connection.replaced', {
|
|
599
|
-
message: '
|
|
614
|
+
message: 'This Node connection was replaced by a newer instance with the same identity. Check for duplicate processes.'
|
|
600
615
|
});
|
|
601
616
|
if (code === 4003 || code === 1001)
|
|
602
617
|
void this.terminalManager.shutdown();
|
|
@@ -609,14 +624,13 @@ export class NodeConnector {
|
|
|
609
624
|
close: (code, reason) => this.controlChannel.close(code, reason),
|
|
610
625
|
inspectWorkspace: (envelope) => this.workspaceCoordinator.inspect(envelope),
|
|
611
626
|
handleNodeRequest: (envelope) => this.nodeRequests.handle(envelope),
|
|
612
|
-
acknowledgeWorkbenchEvent: (replyTo) => this.workbenchEventService.acknowledge(replyTo),
|
|
613
627
|
reconcileRuns: (envelope) => this.runEventBridge.reconcile(envelope),
|
|
614
628
|
runners: this.runners,
|
|
615
629
|
deliverSessionChannelMessage: (envelope) => this.runnerChannelMessages.handle(envelope),
|
|
616
630
|
completeUncontrolledCancellation: (runId) => {
|
|
617
631
|
const run = this.runtime.getRun(runId);
|
|
618
632
|
if (run?.status === 'CANCELLING')
|
|
619
|
-
this.runnerInteractionService.completeCancelledRun(runId
|
|
633
|
+
this.runnerInteractionService.completeCancelledRun(runId);
|
|
620
634
|
},
|
|
621
635
|
send: (type, payload, replyTo) => this.send(type, payload, replyTo)
|
|
622
636
|
});
|
|
@@ -629,7 +643,6 @@ export class NodeConnector {
|
|
|
629
643
|
this.workspaceCoordinator = new NodeWorkspaceCoordinator({
|
|
630
644
|
config: () => this.config,
|
|
631
645
|
database: () => this.database,
|
|
632
|
-
runtime: this.runtime,
|
|
633
646
|
watches: this.workspaceWatchService,
|
|
634
647
|
sessions: this.workspaceSessionService,
|
|
635
648
|
changes: this.workspaceChangeService,
|
|
@@ -661,7 +674,6 @@ export class NodeConnector {
|
|
|
661
674
|
}),
|
|
662
675
|
control: this.controlChannel,
|
|
663
676
|
terminal: this.terminalChannel,
|
|
664
|
-
events: this.workbenchEventService,
|
|
665
677
|
metrics: this.metrics,
|
|
666
678
|
heartbeatMs: HEARTBEAT_MS,
|
|
667
679
|
refreshMs: CAPABILITY_REFRESH_MS
|
|
@@ -690,7 +702,6 @@ export class NodeConnector {
|
|
|
690
702
|
});
|
|
691
703
|
this.workspaceWorkbenchService = new WorkspaceWorkbenchService({
|
|
692
704
|
requireWorkspace: (workspaceId) => this.workspaceCoordinator.require(workspaceId),
|
|
693
|
-
runtime: this.runtime,
|
|
694
705
|
watch: this.workspaceWatchService,
|
|
695
706
|
files: this.workspaceFileService,
|
|
696
707
|
uploads: this.workspaceUploadService,
|
|
@@ -704,7 +715,6 @@ export class NodeConnector {
|
|
|
704
715
|
this.operationRouter.registerAll(this.workspaceWorkbenchService.operations());
|
|
705
716
|
this.operationRouter.registerAll(this.runWorkbenchService.operations());
|
|
706
717
|
this.operationRouter.registerAll(this.nativeSessionWatchService.operations());
|
|
707
|
-
this.operationRouter.registerAll(this.workbenchEventService.operations());
|
|
708
718
|
this.operationRouter.registerAll(this.sessionQueryService.operations());
|
|
709
719
|
this.operationRouter.registerAll(this.sessionLifecycleService.operations());
|
|
710
720
|
this.operationRouter.registerAll(this.sessionMessageService.operations());
|
|
@@ -781,7 +791,22 @@ export class NodeConnector {
|
|
|
781
791
|
/** @internal Thin compatibility delegates; all behavior remains in the extracted services. */
|
|
782
792
|
handleMessage = (raw) => this.controlMessages.handle(raw);
|
|
783
793
|
emitRunEvent = (runId, eventType, payload, status) => this.runEventBridge.emitRun(runId, eventType, payload, status);
|
|
784
|
-
emitConversationItem = (runId, item) =>
|
|
794
|
+
emitConversationItem = (runId, item) => {
|
|
795
|
+
this.runEventService.flushPendingText(runId);
|
|
796
|
+
const itemId = isPlainRecord(item) && typeof item.itemId === 'string' ? item.itemId : undefined;
|
|
797
|
+
const itemKind = isPlainRecord(item) && typeof item.kind === 'string' ? item.kind : undefined;
|
|
798
|
+
const turn = this.runtime.conversationTurnForRun(runId);
|
|
799
|
+
const segment = itemId === undefined || turn === undefined
|
|
800
|
+
? undefined
|
|
801
|
+
: conversationSegmentIdentityForItem(turn, itemId, itemKind);
|
|
802
|
+
this.runEventBridge.emitRun(runId, 'conversation.item', segment === undefined || !isPlainRecord(item)
|
|
803
|
+
? item
|
|
804
|
+
: { ...item, segmentId: segment.id, segmentIndex: segment.index });
|
|
805
|
+
};
|
|
806
|
+
emitConversationTurn = (turn) => {
|
|
807
|
+
const segments = isPlainRecord(turn) && Array.isArray(turn.items) ? conversationSegments(turn) : [];
|
|
808
|
+
this.emitWorkbenchEvent('conversation', { turn, segments });
|
|
809
|
+
};
|
|
785
810
|
emitWorkbenchEvent = (category, payload) => this.runEventBridge.emitWorkbench(category, payload);
|
|
786
811
|
discoverWorkspaceSessions = (workspaceId) => this.nativeSessionProjectionService.discoverWorkspace(workspaceId);
|
|
787
812
|
invalidateWorkspaceWatchTopics = (workspaceId) => this.workspaceCoordinator.invalidate(workspaceId);
|
|
@@ -7,20 +7,23 @@ interface WritableControlSocket {
|
|
|
7
7
|
/** Keeps control responses responsive while reliable Workbench events are busy. */
|
|
8
8
|
export declare class ControlOutboundScheduler {
|
|
9
9
|
private readonly socket;
|
|
10
|
+
private readonly onExpired;
|
|
10
11
|
private readonly high;
|
|
11
12
|
private readonly normal;
|
|
12
13
|
private scheduled;
|
|
13
14
|
private retryTimer;
|
|
15
|
+
private expiryTimer;
|
|
14
16
|
private backpressureStartedAt;
|
|
15
17
|
private backpressureLogged;
|
|
16
18
|
private maximumHighDepth;
|
|
17
19
|
private maximumNormalDepth;
|
|
18
|
-
constructor(socket: () => WritableControlSocket | undefined);
|
|
20
|
+
constructor(socket: () => WritableControlSocket | undefined, onExpired?: () => void);
|
|
19
21
|
enqueue(envelope: NodeEnvelope, priority: 'high' | 'normal'): void;
|
|
20
22
|
reset(): void;
|
|
21
23
|
private schedule;
|
|
22
24
|
private flush;
|
|
23
25
|
private waitForBackpressure;
|
|
24
26
|
private finishBackpressure;
|
|
27
|
+
private scheduleExpiry;
|
|
25
28
|
}
|
|
26
29
|
export {};
|
|
@@ -4,19 +4,23 @@ const MAX_BYTES_PER_TURN = 256 * 1024;
|
|
|
4
4
|
const SOCKET_NORMAL_DIRECT_WATER_BYTES = 256 * 1024;
|
|
5
5
|
const SOCKET_HIGH_WATER_BYTES = 1024 * 1024;
|
|
6
6
|
const BACKPRESSURE_RETRY_MS = 5;
|
|
7
|
+
const OUTBOUND_QUEUE_TTL_MS = 30_000;
|
|
7
8
|
/** Keeps control responses responsive while reliable Workbench events are busy. */
|
|
8
9
|
export class ControlOutboundScheduler {
|
|
9
10
|
socket;
|
|
11
|
+
onExpired;
|
|
10
12
|
high = [];
|
|
11
13
|
normal = [];
|
|
12
14
|
scheduled = false;
|
|
13
15
|
retryTimer;
|
|
16
|
+
expiryTimer;
|
|
14
17
|
backpressureStartedAt;
|
|
15
18
|
backpressureLogged = false;
|
|
16
19
|
maximumHighDepth = 0;
|
|
17
20
|
maximumNormalDepth = 0;
|
|
18
|
-
constructor(socket) {
|
|
21
|
+
constructor(socket, onExpired = () => undefined) {
|
|
19
22
|
this.socket = socket;
|
|
23
|
+
this.onExpired = onExpired;
|
|
20
24
|
}
|
|
21
25
|
enqueue(envelope, priority) {
|
|
22
26
|
const socket = this.socket();
|
|
@@ -29,9 +33,13 @@ export class ControlOutboundScheduler {
|
|
|
29
33
|
socket.send(JSON.stringify(envelope));
|
|
30
34
|
return;
|
|
31
35
|
}
|
|
32
|
-
(priority === 'high' ? this.high : this.normal).push(
|
|
36
|
+
(priority === 'high' ? this.high : this.normal).push({
|
|
37
|
+
envelope,
|
|
38
|
+
expiresAt: Date.now() + OUTBOUND_QUEUE_TTL_MS
|
|
39
|
+
});
|
|
33
40
|
this.maximumHighDepth = Math.max(this.maximumHighDepth, this.high.length);
|
|
34
41
|
this.maximumNormalDepth = Math.max(this.maximumNormalDepth, this.normal.length);
|
|
42
|
+
this.scheduleExpiry();
|
|
35
43
|
this.schedule();
|
|
36
44
|
}
|
|
37
45
|
reset() {
|
|
@@ -41,6 +49,9 @@ export class ControlOutboundScheduler {
|
|
|
41
49
|
if (this.retryTimer !== undefined)
|
|
42
50
|
clearTimeout(this.retryTimer);
|
|
43
51
|
this.retryTimer = undefined;
|
|
52
|
+
if (this.expiryTimer !== undefined)
|
|
53
|
+
clearTimeout(this.expiryTimer);
|
|
54
|
+
this.expiryTimer = undefined;
|
|
44
55
|
this.finishBackpressure('reset');
|
|
45
56
|
}
|
|
46
57
|
schedule() {
|
|
@@ -62,8 +73,8 @@ export class ControlOutboundScheduler {
|
|
|
62
73
|
let bytes = 0;
|
|
63
74
|
while (frames < MAX_FRAMES_PER_TURN) {
|
|
64
75
|
const queue = this.high.length > 0 ? this.high : this.normal;
|
|
65
|
-
const
|
|
66
|
-
if (
|
|
76
|
+
const queued = queue[0];
|
|
77
|
+
if (queued === undefined)
|
|
67
78
|
break;
|
|
68
79
|
// Reliable Workbench events may be replayed in a large burst after a
|
|
69
80
|
// reconnect. Stop normal traffic early so a later HTTP/control response
|
|
@@ -73,7 +84,7 @@ export class ControlOutboundScheduler {
|
|
|
73
84
|
this.waitForBackpressure(socket, 'normal');
|
|
74
85
|
return;
|
|
75
86
|
}
|
|
76
|
-
const serialized = JSON.stringify(envelope);
|
|
87
|
+
const serialized = JSON.stringify(queued.envelope);
|
|
77
88
|
const size = Buffer.byteLength(serialized);
|
|
78
89
|
if (frames > 0 && bytes + size > MAX_BYTES_PER_TURN)
|
|
79
90
|
break;
|
|
@@ -86,8 +97,12 @@ export class ControlOutboundScheduler {
|
|
|
86
97
|
}
|
|
87
98
|
if (this.high.length > 0 || this.normal.length > 0)
|
|
88
99
|
this.schedule();
|
|
89
|
-
else
|
|
100
|
+
else {
|
|
101
|
+
if (this.expiryTimer !== undefined)
|
|
102
|
+
clearTimeout(this.expiryTimer);
|
|
103
|
+
this.expiryTimer = undefined;
|
|
90
104
|
this.finishBackpressure('drained');
|
|
105
|
+
}
|
|
91
106
|
}
|
|
92
107
|
waitForBackpressure(socket, level) {
|
|
93
108
|
this.backpressureStartedAt ??= Date.now();
|
|
@@ -118,4 +133,22 @@ export class ControlOutboundScheduler {
|
|
|
118
133
|
this.maximumHighDepth = 0;
|
|
119
134
|
this.maximumNormalDepth = 0;
|
|
120
135
|
}
|
|
136
|
+
scheduleExpiry() {
|
|
137
|
+
if (this.expiryTimer !== undefined)
|
|
138
|
+
return;
|
|
139
|
+
const expiresAt = Math.min(this.high[0]?.expiresAt ?? Number.POSITIVE_INFINITY, this.normal[0]?.expiresAt ?? Number.POSITIVE_INFINITY);
|
|
140
|
+
if (!Number.isFinite(expiresAt))
|
|
141
|
+
return;
|
|
142
|
+
this.expiryTimer = setTimeout(() => {
|
|
143
|
+
this.expiryTimer = undefined;
|
|
144
|
+
if ((this.high[0]?.expiresAt ?? Number.POSITIVE_INFINITY) > Date.now() &&
|
|
145
|
+
(this.normal[0]?.expiresAt ?? Number.POSITIVE_INFINITY) > Date.now()) {
|
|
146
|
+
this.scheduleExpiry();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.reset();
|
|
150
|
+
this.onExpired();
|
|
151
|
+
}, Math.max(0, expiresAt - Date.now()));
|
|
152
|
+
this.expiryTimer.unref();
|
|
153
|
+
}
|
|
121
154
|
}
|
package/dist/database.d.ts
CHANGED
|
@@ -80,13 +80,6 @@ export interface NodeRunEvent {
|
|
|
80
80
|
readonly status?: AgentRunStatus;
|
|
81
81
|
readonly createdAt: number;
|
|
82
82
|
}
|
|
83
|
-
export interface WorkspaceActivityEvent {
|
|
84
|
-
readonly id: number;
|
|
85
|
-
readonly workspaceId: string;
|
|
86
|
-
readonly eventType: string;
|
|
87
|
-
readonly payload: unknown;
|
|
88
|
-
readonly createdAt: number;
|
|
89
|
-
}
|
|
90
83
|
export interface ConversationPage {
|
|
91
84
|
readonly turns: readonly NodeConversationTurn[];
|
|
92
85
|
readonly nextCursor: string | null;
|
|
@@ -132,10 +125,6 @@ export interface NodeMessageAttachmentInput {
|
|
|
132
125
|
readonly mime: string;
|
|
133
126
|
readonly dataBase64: string;
|
|
134
127
|
}
|
|
135
|
-
export interface WorkspaceActivityPage {
|
|
136
|
-
readonly events: readonly WorkspaceActivityEvent[];
|
|
137
|
-
readonly nextCursor: string | null;
|
|
138
|
-
}
|
|
139
128
|
export interface NodeApproval {
|
|
140
129
|
readonly id: string;
|
|
141
130
|
readonly runId: string;
|
|
@@ -288,11 +277,6 @@ export declare class NodeDatabase {
|
|
|
288
277
|
readonly cursor?: string;
|
|
289
278
|
readonly limit?: number;
|
|
290
279
|
}): ConversationItemPage;
|
|
291
|
-
listWorkspaceActivity(input: {
|
|
292
|
-
readonly workspaceId: string;
|
|
293
|
-
readonly cursor?: string;
|
|
294
|
-
readonly limit?: number;
|
|
295
|
-
}): WorkspaceActivityPage;
|
|
296
280
|
createApproval(input: {
|
|
297
281
|
readonly runId: string;
|
|
298
282
|
readonly approvalId: string;
|
|
@@ -307,13 +291,10 @@ export declare class NodeDatabase {
|
|
|
307
291
|
decideApproval(id: string, decision: 'APPROVED' | 'REJECTED'): NodeApproval;
|
|
308
292
|
listNonterminalRuns(): readonly NodeAgentRun[];
|
|
309
293
|
lastRunSequence(runId: string): number;
|
|
310
|
-
saveSnapshot(runId: string, snapshot: unknown): void;
|
|
311
|
-
getSnapshot(runId: string): unknown | undefined;
|
|
312
294
|
markActiveRunsSuspect(): void;
|
|
313
295
|
hasActiveWorkspaceLease(workspaceId: string): boolean;
|
|
314
296
|
reconcileRun(runId: string, active: boolean): void;
|
|
315
297
|
private releaseLease;
|
|
316
|
-
private recordWorkspaceActivity;
|
|
317
298
|
private recordConversationItemChange;
|
|
318
299
|
private projectApproval;
|
|
319
300
|
private readConversationTurn;
|
package/dist/database.js
CHANGED
|
@@ -552,11 +552,6 @@ export class NodeDatabase {
|
|
|
552
552
|
this.raw
|
|
553
553
|
.prepare('UPDATE legacy_agent_sessions SET last_activity_at = ?, updated_at = ? WHERE id = ?')
|
|
554
554
|
.run(value.createdAt, value.createdAt, value.sessionId);
|
|
555
|
-
this.recordWorkspaceActivity(value.workspaceId, 'run.created', {
|
|
556
|
-
runId: value.id,
|
|
557
|
-
sessionId: value.sessionId,
|
|
558
|
-
runner: value.runner
|
|
559
|
-
});
|
|
560
555
|
this.raw.exec('COMMIT');
|
|
561
556
|
return { run: value, created: true };
|
|
562
557
|
}
|
|
@@ -632,14 +627,6 @@ export class NodeDatabase {
|
|
|
632
627
|
.get(input.runId, input.sequence);
|
|
633
628
|
const value = event(stored);
|
|
634
629
|
this.projectRunEvent(value, input.status);
|
|
635
|
-
const run = this.getRun(input.runId);
|
|
636
|
-
if (run !== undefined) {
|
|
637
|
-
this.recordWorkspaceActivity(run.workspaceId, 'run.updated', {
|
|
638
|
-
runId: run.id,
|
|
639
|
-
eventType: input.eventType,
|
|
640
|
-
status: input.status ?? null
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
630
|
return value;
|
|
644
631
|
}
|
|
645
632
|
listRunEvents(runId, after = 0) {
|
|
@@ -709,25 +696,6 @@ export class NodeDatabase {
|
|
|
709
696
|
: null
|
|
710
697
|
};
|
|
711
698
|
}
|
|
712
|
-
listWorkspaceActivity(input) {
|
|
713
|
-
if (this.getWorkspace(input.workspaceId) === undefined)
|
|
714
|
-
throw new Error('WORKSPACE_NOT_FOUND');
|
|
715
|
-
const limit = pageLimit(input.limit);
|
|
716
|
-
const cursor = decodeCursor(input.cursor, 'workspace-activity', input.workspaceId);
|
|
717
|
-
const rows = this.raw
|
|
718
|
-
.prepare(`SELECT id, workspace_id, event_type, payload, created_at FROM workspace_activity_events
|
|
719
|
-
WHERE workspace_id = ? AND (? IS NULL OR id > ?)
|
|
720
|
-
ORDER BY id ASC LIMIT ?`)
|
|
721
|
-
.all(input.workspaceId, cursor === undefined ? null : cursor.value, cursor?.value ?? 0, limit + 1);
|
|
722
|
-
const page = rows.slice(0, limit);
|
|
723
|
-
const last = page.at(-1);
|
|
724
|
-
return {
|
|
725
|
-
events: page.map((row) => workspaceActivityEvent(row)),
|
|
726
|
-
nextCursor: rows.length > limit && last !== undefined
|
|
727
|
-
? encodeCursor('workspace-activity', input.workspaceId, numberValue(last, 'id'), '')
|
|
728
|
-
: null
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
699
|
createApproval(input) {
|
|
732
700
|
if (this.getRun(input.runId) === undefined)
|
|
733
701
|
throw new Error('RUN_NOT_FOUND');
|
|
@@ -828,18 +796,6 @@ export class NodeDatabase {
|
|
|
828
796
|
.get(runId);
|
|
829
797
|
return row['sequence'] === null ? 0 : numberValue(row, 'sequence');
|
|
830
798
|
}
|
|
831
|
-
saveSnapshot(runId, snapshot) {
|
|
832
|
-
this.raw
|
|
833
|
-
.prepare(`INSERT INTO run_snapshots (run_id, snapshot, created_at) VALUES (?, ?, ?)
|
|
834
|
-
ON CONFLICT(run_id) DO UPDATE SET snapshot = excluded.snapshot, created_at = excluded.created_at`)
|
|
835
|
-
.run(runId, JSON.stringify(snapshot), this.now());
|
|
836
|
-
}
|
|
837
|
-
getSnapshot(runId) {
|
|
838
|
-
const row = this.raw
|
|
839
|
-
.prepare('SELECT snapshot FROM run_snapshots WHERE run_id = ?')
|
|
840
|
-
.get(runId);
|
|
841
|
-
return row === undefined ? undefined : JSON.parse(stringValue(row, 'snapshot'));
|
|
842
|
-
}
|
|
843
799
|
markActiveRunsSuspect() {
|
|
844
800
|
this.raw
|
|
845
801
|
.prepare("UPDATE agent_runs SET recovery_state = 'SUSPECT', recovery_updated_at = ? WHERE status NOT IN ('SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED')")
|
|
@@ -877,12 +833,6 @@ export class NodeDatabase {
|
|
|
877
833
|
.prepare("UPDATE workspace_leases SET state = 'RELEASED', updated_at = ? WHERE run_id = ? AND state IN ('ACTIVE', 'SUSPECT')")
|
|
878
834
|
.run(this.now(), runId);
|
|
879
835
|
}
|
|
880
|
-
recordWorkspaceActivity(workspaceId, eventType, payload) {
|
|
881
|
-
this.raw
|
|
882
|
-
.prepare(`INSERT INTO workspace_activity_events (workspace_id, event_type, payload, created_at)
|
|
883
|
-
VALUES (?, ?, ?, ?)`)
|
|
884
|
-
.run(workspaceId, eventType, JSON.stringify(payload), this.now());
|
|
885
|
-
}
|
|
886
836
|
recordConversationItemChange(sessionId, itemId, revision) {
|
|
887
837
|
this.raw
|
|
888
838
|
.prepare(`INSERT INTO conversation_item_events (session_id, item_id, revision, created_at)
|
|
@@ -1206,10 +1156,8 @@ function initializeEphemeralRuntimeTables(database) {
|
|
|
1206
1156
|
'conversation_turns',
|
|
1207
1157
|
'conversation_items',
|
|
1208
1158
|
'conversation_item_events',
|
|
1209
|
-
'workspace_activity_events',
|
|
1210
1159
|
'approvals',
|
|
1211
|
-
'workspace_leases'
|
|
1212
|
-
'run_snapshots'
|
|
1160
|
+
'workspace_leases'
|
|
1213
1161
|
]);
|
|
1214
1162
|
for (const raw of NODE_SCHEMA_V1.split(';')) {
|
|
1215
1163
|
const statement = raw.trim();
|
|
@@ -1341,15 +1289,6 @@ function conversationItem(row) {
|
|
|
1341
1289
|
completedAt: nullableNumber(row, 'completed_at')
|
|
1342
1290
|
};
|
|
1343
1291
|
}
|
|
1344
|
-
function workspaceActivityEvent(row) {
|
|
1345
|
-
return {
|
|
1346
|
-
id: numberValue(row, 'id'),
|
|
1347
|
-
workspaceId: stringValue(row, 'workspace_id'),
|
|
1348
|
-
eventType: stringValue(row, 'event_type'),
|
|
1349
|
-
payload: JSON.parse(stringValue(row, 'payload')),
|
|
1350
|
-
createdAt: numberValue(row, 'created_at')
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
1292
|
function pageLimit(value) {
|
|
1354
1293
|
if (value === undefined)
|
|
1355
1294
|
return 100;
|
package/dist/event-buffer.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { type NodeEnvelope, type WorkbenchEvent } from '@myagentroam/protocol';
|
|
2
|
-
/**
|
|
3
|
-
* Keeps exactly the page-level business frames that have not received a Server
|
|
4
|
-
* ACK. Node-global sequences make a reconnect replay harmless.
|
|
5
|
-
*/
|
|
2
|
+
/** Keeps live page-level frames only until the current Server connection ACKs them. */
|
|
6
3
|
export declare class ReliableWorkbenchEventBuffer {
|
|
7
4
|
private readonly pending;
|
|
8
5
|
queue(event: WorkbenchEvent): NodeEnvelope;
|
|
9
6
|
acknowledge(replyTo: string | undefined): boolean;
|
|
10
|
-
|
|
7
|
+
clear(): void;
|
|
11
8
|
get size(): number;
|
|
12
9
|
}
|
package/dist/event-buffer.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { createEnvelope } from '@myagentroam/protocol';
|
|
2
|
-
/**
|
|
3
|
-
* Keeps exactly the page-level business frames that have not received a Server
|
|
4
|
-
* ACK. Node-global sequences make a reconnect replay harmless.
|
|
5
|
-
*/
|
|
2
|
+
/** Keeps live page-level frames only until the current Server connection ACKs them. */
|
|
6
3
|
export class ReliableWorkbenchEventBuffer {
|
|
7
4
|
pending = new Map();
|
|
8
5
|
queue(event) {
|
|
@@ -13,14 +10,8 @@ export class ReliableWorkbenchEventBuffer {
|
|
|
13
10
|
acknowledge(replyTo) {
|
|
14
11
|
return replyTo !== undefined && this.pending.delete(replyTo);
|
|
15
12
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const a = left.payload;
|
|
19
|
-
const b = right.payload;
|
|
20
|
-
return a.sequence - b.sequence;
|
|
21
|
-
});
|
|
22
|
-
for (const envelope of ordered)
|
|
23
|
-
send(envelope);
|
|
13
|
+
clear() {
|
|
14
|
+
this.pending.clear();
|
|
24
15
|
}
|
|
25
16
|
get size() {
|
|
26
17
|
return this.pending.size;
|