@moxt-ai/mobius 0.0.294 → 0.0.296
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +236 -61
- package/dist/cli.js.map +3 -3
- package/dist/runtime/relay/session-event-publisher.d.ts +2 -2
- package/dist/runtime/relay/session-event-publisher.d.ts.map +1 -1
- package/dist/runtime/relay/session-event-publisher.js +79 -42
- package/dist/runtime/relay/session-event-publisher.js.map +1 -1
- package/dist/runtime.js +236 -61
- package/dist/runtime.js.map +3 -3
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { WebSocket } from "undici";
|
|
|
3
3
|
import type { SessionEventSink } from "../../session/api/session-api.ts";
|
|
4
4
|
import type { Timer } from "../../util/timer.ts";
|
|
5
5
|
export declare const SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
|
|
6
|
-
/**
|
|
6
|
+
/** Keeps unsent output in bounded memory across reconnects. Sent events are never replayed. */
|
|
7
7
|
export declare class RuntimeSessionEventPublisher implements SessionEventSink {
|
|
8
8
|
#private;
|
|
9
9
|
constructor(timer: Timer);
|
|
@@ -16,7 +16,7 @@ export declare class RuntimeSessionEventPublisher implements SessionEventSink {
|
|
|
16
16
|
readonly publishInfo: (event: SessionInfoUpdatedEvent) => void;
|
|
17
17
|
readonly publishClosed: (event: SessionCloseNoticeEvent) => void;
|
|
18
18
|
readonly publish: (event: SessionLiveEvent) => void;
|
|
19
|
-
private readonly
|
|
19
|
+
private readonly cancelFlush;
|
|
20
20
|
private readonly flushEvents;
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=session-event-publisher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-publisher.d.ts","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAiB,KAAK,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-event-publisher.d.ts","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAiB,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAShE,eAAO,MAAM,uCAAuC,MAAM,CAAC;AAY3D,+FAA+F;AAC/F,qBAAa,4BAA6B,YAAW,gBAAgB;;IAQjE,YAAY,KAAK,EAAE,KAAK,EAEvB;IAED,QAAQ,CAAC,OAAO,WAAY,SAAS,KAAG,IAAI,CAO1C;IAEF,QAAQ,CAAC,UAAU,WAAY,SAAS,KAAG,IAAI,CAK7C;IAEF,QAAQ,CAAC,KAAK,QAAO,IAAI,CAKvB;IAEF,QAAQ,CAAC,KAAK,QAAO,IAAI,CAIvB;IAEF,QAAQ,CAAC,uBAAuB,cAAe,MAAM,aAAa,MAAM,QAAQ,MAAM,WAAW,MAAM,KAAG,IAAI,CAE5G;IACF,QAAQ,CAAC,aAAa,UAAW,yBAAyB,KAAG,IAAI,CAAsB;IACvF,QAAQ,CAAC,WAAW,UAAW,uBAAuB,KAAG,IAAI,CAAsB;IACnF,QAAQ,CAAC,aAAa,UAAW,uBAAuB,KAAG,IAAI,CAAsB;IAoBrF,QAAQ,CAAC,OAAO,UAAW,gBAAgB,KAAG,IAAI,CAwDhD;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAG1B;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CA2B1B;CACL"}
|
|
@@ -1,39 +1,47 @@
|
|
|
1
1
|
import { encodeDaemonToServiceMessage, SESSION_EVENT_BATCH_MAX_SIZE, SESSION_EVENT_KIND, } from "@moxt-ai/mobius-sdk/protocol";
|
|
2
2
|
import { WebSocket } from "undici";
|
|
3
3
|
const MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
|
|
4
|
+
const MAX_PENDING_BYTES = 32 * 1024 * 1024;
|
|
4
5
|
const MAX_EVENT_BATCH_BYTES = 1024 * 1024;
|
|
5
6
|
const MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
6
7
|
// Browser-compatible WebSocket clients may initiate only 1000 or application close codes.
|
|
7
8
|
const LOCAL_BACKPRESSURE_CLOSE_CODE = 4009;
|
|
8
9
|
const EMPTY_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ events: [], kind: SESSION_EVENT_KIND }));
|
|
9
10
|
export const SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
|
|
10
|
-
/**
|
|
11
|
+
/** Keeps unsent output in bounded memory across reconnects. Sent events are never replayed. */
|
|
11
12
|
export class RuntimeSessionEventPublisher {
|
|
12
|
-
#
|
|
13
|
-
#pendingBytes =
|
|
13
|
+
#pending = [];
|
|
14
|
+
#pendingBytes = 0;
|
|
15
|
+
#overflowReported = false;
|
|
14
16
|
#pendingTask = null;
|
|
15
|
-
#
|
|
17
|
+
#connection = { kind: "disconnected" };
|
|
16
18
|
#timer;
|
|
17
19
|
constructor(timer) {
|
|
18
20
|
this.#timer = timer;
|
|
19
21
|
}
|
|
20
22
|
connect = (socket) => {
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
+
if (this.#connection.kind === "closed") {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.#connection = { kind: "connected", socket };
|
|
27
|
+
// Hand off the unsent tail before a new command can publish newer events.
|
|
28
|
+
this.flushEvents(socket);
|
|
23
29
|
};
|
|
24
30
|
disconnect = (socket) => {
|
|
25
|
-
if (this.#socket === socket) {
|
|
26
|
-
this.#
|
|
27
|
-
this.
|
|
31
|
+
if (this.#connection.kind === "connected" && this.#connection.socket === socket) {
|
|
32
|
+
this.#connection = { kind: "disconnected" };
|
|
33
|
+
this.cancelFlush();
|
|
28
34
|
}
|
|
29
35
|
};
|
|
30
36
|
close = () => {
|
|
31
|
-
this.#
|
|
32
|
-
this.
|
|
37
|
+
this.#connection = { kind: "closed" };
|
|
38
|
+
this.cancelFlush();
|
|
39
|
+
this.#pending.length = 0;
|
|
40
|
+
this.#pendingBytes = 0;
|
|
33
41
|
};
|
|
34
42
|
flush = () => {
|
|
35
|
-
if (this.#
|
|
36
|
-
this.flushEvents(this.#socket);
|
|
43
|
+
if (this.#connection.kind === "connected") {
|
|
44
|
+
this.flushEvents(this.#connection.socket);
|
|
37
45
|
}
|
|
38
46
|
};
|
|
39
47
|
publishOperationFailure = (sessionId, requestId, code, message) => {
|
|
@@ -43,10 +51,11 @@ export class RuntimeSessionEventPublisher {
|
|
|
43
51
|
publishInfo = (event) => this.#send(event);
|
|
44
52
|
publishClosed = (event) => this.#send(event);
|
|
45
53
|
#send = (message) => {
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
54
|
+
const connection = this.#connection;
|
|
55
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket.OPEN) {
|
|
48
56
|
return;
|
|
49
57
|
}
|
|
58
|
+
const socket = connection.socket;
|
|
50
59
|
const encoded = encodeDaemonToServiceMessage(message);
|
|
51
60
|
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
52
61
|
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
@@ -60,8 +69,7 @@ export class RuntimeSessionEventPublisher {
|
|
|
60
69
|
}
|
|
61
70
|
};
|
|
62
71
|
publish = (event) => {
|
|
63
|
-
|
|
64
|
-
if (socket === null || socket.readyState !== WebSocket.OPEN) {
|
|
72
|
+
if (this.#connection.kind === "closed") {
|
|
65
73
|
return;
|
|
66
74
|
}
|
|
67
75
|
const bytes = Buffer.byteLength(JSON.stringify(event), "utf8") + 1;
|
|
@@ -74,45 +82,74 @@ export class RuntimeSessionEventPublisher {
|
|
|
74
82
|
});
|
|
75
83
|
return;
|
|
76
84
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
let batch = this.#pending.at(-1);
|
|
86
|
+
const newBatch = batch === undefined ||
|
|
87
|
+
batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE ||
|
|
88
|
+
batch.bytes + bytes > MAX_EVENT_BATCH_BYTES;
|
|
89
|
+
const additionalBytes = bytes + (newBatch ? EMPTY_ENVELOPE_BYTES : 0);
|
|
90
|
+
if (this.#pendingBytes + additionalBytes > MAX_PENDING_BYTES) {
|
|
91
|
+
if (!this.#overflowReported) {
|
|
92
|
+
this.#overflowReported = true;
|
|
93
|
+
console.warn("Live Session output exceeded the pending buffer limit", {
|
|
94
|
+
code: "live_event_buffer_full",
|
|
95
|
+
sessionId: event.sessionId,
|
|
96
|
+
eventId: event.eventId,
|
|
97
|
+
maximumBytes: MAX_PENDING_BYTES,
|
|
98
|
+
});
|
|
81
99
|
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (batch === undefined || newBatch) {
|
|
103
|
+
batch = { events: [], bytes: EMPTY_ENVELOPE_BYTES };
|
|
104
|
+
this.#pending.push(batch);
|
|
82
105
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
batch.events.push(event);
|
|
107
|
+
batch.bytes += bytes;
|
|
108
|
+
this.#pendingBytes += additionalBytes;
|
|
109
|
+
const connection = this.#connection;
|
|
110
|
+
if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket.OPEN) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const socket = connection.socket;
|
|
114
|
+
if (this.#pending.length > 1 ||
|
|
115
|
+
batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE ||
|
|
116
|
+
batch.bytes >= MAX_EVENT_BATCH_BYTES) {
|
|
86
117
|
this.flushEvents(socket);
|
|
87
118
|
return;
|
|
88
119
|
}
|
|
89
120
|
this.#pendingTask ??= this.#timer.schedule(() => this.flushEvents(socket), SESSION_EVENT_BATCH_WINDOW_MILLISECONDS);
|
|
90
121
|
};
|
|
91
|
-
|
|
122
|
+
cancelFlush = () => {
|
|
92
123
|
this.#pendingTask?.cancel();
|
|
93
124
|
this.#pendingTask = null;
|
|
94
|
-
this.#pendingEvents = [];
|
|
95
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
96
125
|
};
|
|
97
126
|
flushEvents = (socket) => {
|
|
98
|
-
this
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.#pendingEvents = [];
|
|
102
|
-
this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
|
|
103
|
-
if (events.length === 0 || this.#socket !== socket || socket.readyState !== WebSocket.OPEN) {
|
|
127
|
+
this.cancelFlush();
|
|
128
|
+
const connection = this.#connection;
|
|
129
|
+
if (connection.kind !== "connected" || connection.socket !== socket || socket.readyState !== WebSocket.OPEN) {
|
|
104
130
|
return;
|
|
105
131
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
132
|
+
let attempted = 0;
|
|
133
|
+
for (const batch of this.#pending) {
|
|
134
|
+
const encoded = encodeDaemonToServiceMessage({ events: batch.events, kind: SESSION_EVENT_KIND });
|
|
135
|
+
if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
|
|
136
|
+
socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
// Once handed to the socket, a batch cannot be safely resent without acknowledgements.
|
|
140
|
+
attempted += 1;
|
|
141
|
+
this.#pendingBytes -= batch.bytes;
|
|
142
|
+
try {
|
|
143
|
+
socket.send(encoded);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
console.warn("Live Session output could not be sent", { code: "live_event_send_failed" });
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
113
149
|
}
|
|
114
|
-
|
|
115
|
-
|
|
150
|
+
this.#pending.splice(0, attempted);
|
|
151
|
+
if (this.#pending.length === 0) {
|
|
152
|
+
this.#overflowReported = false;
|
|
116
153
|
}
|
|
117
154
|
};
|
|
118
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-publisher.js","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,4BAA4B,EAC5B,4BAA4B,EAC5B,kBAAkB,GAKrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAInC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAC5C,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1C,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACxC,0FAA0F;AAC1F,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAC3C,MAAM,oBAAoB,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;AACzG,MAAM,CAAC,MAAM,uCAAuC,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"session-event-publisher.js","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"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"}
|