@moxt-ai/mobius 0.0.295 → 0.0.298

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.
@@ -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
- /** Live delivery is best-effort. Recovery snapshots are owned by the daemon's local Session cache. */
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 dropPendingEvents;
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;AAQhE,eAAO,MAAM,uCAAuC,MAAM,CAAC;AAE3D,sGAAsG;AACtG,qBAAa,4BAA6B,YAAW,gBAAgB;;IAOjE,YAAY,KAAK,EAAE,KAAK,EAEvB;IAED,QAAQ,CAAC,OAAO,WAAY,SAAS,KAAG,IAAI,CAG1C;IAEF,QAAQ,CAAC,UAAU,WAAY,SAAS,KAAG,IAAI,CAK7C;IAEF,QAAQ,CAAC,KAAK,QAAO,IAAI,CAGvB;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;IAmBrF,QAAQ,CAAC,OAAO,UAAW,gBAAgB,KAAG,IAAI,CA+BhD;IAEF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAKhC;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAmB1B;CACL"}
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
- /** Live delivery is best-effort. Recovery snapshots are owned by the daemon's local Session cache. */
11
+ /** Keeps unsent output in bounded memory across reconnects. Sent events are never replayed. */
11
12
  export class RuntimeSessionEventPublisher {
12
- #pendingEvents = [];
13
- #pendingBytes = EMPTY_ENVELOPE_BYTES;
13
+ #pending = [];
14
+ #pendingBytes = 0;
15
+ #overflowReported = false;
14
16
  #pendingTask = null;
15
- #socket = null;
17
+ #connection = { kind: "disconnected" };
16
18
  #timer;
17
19
  constructor(timer) {
18
20
  this.#timer = timer;
19
21
  }
20
22
  connect = (socket) => {
21
- this.dropPendingEvents();
22
- this.#socket = socket;
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.#socket = null;
27
- this.dropPendingEvents();
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.#socket = null;
32
- this.dropPendingEvents();
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.#socket !== null) {
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 socket = this.#socket;
47
- if (socket === null || socket.readyState !== WebSocket.OPEN) {
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
- const socket = this.#socket;
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
- if (this.#pendingEvents.length > 0 && this.#pendingBytes + bytes > MAX_EVENT_BATCH_BYTES) {
78
- this.flushEvents(socket);
79
- if (socket.readyState !== WebSocket.OPEN) {
80
- return;
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
- this.#pendingEvents.push(event);
84
- this.#pendingBytes += bytes;
85
- if (this.#pendingEvents.length >= SESSION_EVENT_BATCH_MAX_SIZE || this.#pendingBytes >= MAX_EVENT_BATCH_BYTES) {
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
- dropPendingEvents = () => {
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.#pendingTask?.cancel();
99
- this.#pendingTask = null;
100
- const events = this.#pendingEvents;
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
- const encoded = encodeDaemonToServiceMessage({ events, kind: SESSION_EVENT_KIND });
107
- if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
108
- socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
109
- return;
110
- }
111
- try {
112
- socket.send(encoded);
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
- catch {
115
- // Socket liveness owns reconnection. Missed events are recovered from the local cache.
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":"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"}
1
+ {"version":3,"file":"session-event-publisher.js","sourceRoot":"","sources":["../../../src/runtime/relay/session-event-publisher.ts"],"names":[],"mappings":"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"}
package/dist/runtime.js CHANGED
@@ -22582,7 +22582,7 @@ import { fetch as fetch3 } from "undici";
22582
22582
  // package.json
22583
22583
  var package_default = {
22584
22584
  name: "@moxt-ai/mobius",
22585
- version: "0.0.295",
22585
+ version: "0.0.298",
22586
22586
  description: "Mobius CLI for pairing and running local AI agent services.",
22587
22587
  type: "module",
22588
22588
  bin: {
@@ -67456,7 +67456,7 @@ function reasoningText(item) {
67456
67456
  if (item.type !== "reasoning") {
67457
67457
  return null;
67458
67458
  }
67459
- return boundedParagraphs(item.summary.length > 0 ? item.summary : item.content, TOOL_OUTPUT_CHARACTER_LIMIT);
67459
+ return boundedParagraphs(item.content.length > 0 ? item.content : item.summary, TOOL_OUTPUT_CHARACTER_LIMIT);
67460
67460
  }
67461
67461
 
67462
67462
  // src/acp/harness/codex/borrowed-agent.ts
@@ -67836,7 +67836,7 @@ var CodexOwnedAcpAgent = class {
67836
67836
  #context;
67837
67837
  #appServer;
67838
67838
  #settings;
67839
- #streamedReasoningItemIds = /* @__PURE__ */ new Set();
67839
+ #streamedReasoningSources = /* @__PURE__ */ new Map();
67840
67840
  #agentMessages = /* @__PURE__ */ new Map();
67841
67841
  #turn = null;
67842
67842
  #nativeTurnId = null;
@@ -68044,7 +68044,12 @@ var CodexOwnedAcpAgent = class {
68044
68044
  if (method === "item/reasoning/summaryTextDelta" || method === "item/reasoning/textDelta") {
68045
68045
  const decoded = reasoningTextDeltaParamsSchema.safeParse(params);
68046
68046
  if (decoded.success && decoded.data.threadId === this.#context.threadId() && this.#turn !== null && decoded.data.turnId === this.#turn.turn.id && decoded.data.delta.length > 0) {
68047
- this.#streamedReasoningItemIds.add(decoded.data.itemId);
68047
+ const source = method === "item/reasoning/textDelta" ? "content" : "summary";
68048
+ const previous = this.#streamedReasoningSources.get(decoded.data.itemId);
68049
+ this.#streamedReasoningSources.set(
68050
+ decoded.data.itemId,
68051
+ previous === "content" || source === "content" ? "content" : "summary"
68052
+ );
68048
68053
  await this.#enqueue(async () => {
68049
68054
  await this.#context.emit({
68050
68055
  content: { text: decoded.data.delta, type: "text" },
@@ -68112,8 +68117,12 @@ var CodexOwnedAcpAgent = class {
68112
68117
  }
68113
68118
  const reasoning = reasoningText(item);
68114
68119
  if (reasoning !== null) {
68115
- const streamed = method === "item/completed" && this.#streamedReasoningItemIds.delete(item.id);
68116
- if (method === "item/completed" && reasoning.length > 0 && !streamed) {
68120
+ const streamedSource = method === "item/completed" ? this.#streamedReasoningSources.get(item.id) : void 0;
68121
+ if (method === "item/completed") {
68122
+ this.#streamedReasoningSources.delete(item.id);
68123
+ }
68124
+ const needsCompletedContent = method === "item/completed" && reasoning.length > 0 && (streamedSource === void 0 || streamedSource === "summary" && item.type === "reasoning" && item.content.length > 0);
68125
+ if (needsCompletedContent) {
68117
68126
  await this.#enqueue(async () => {
68118
68127
  await this.#context.emit({
68119
68128
  content: { text: reasoning, type: "text" },
@@ -68265,7 +68274,7 @@ var CodexOwnedAcpAgent = class {
68265
68274
  signal.addEventListener("abort", aborted2, { once: true });
68266
68275
  const turn = { completion, turn: { id: "" } };
68267
68276
  this.#agentMessages.clear();
68268
- this.#streamedReasoningItemIds.clear();
68277
+ this.#streamedReasoningSources.clear();
68269
68278
  this.#turn = turn;
68270
68279
  this.#nativeTurnId = null;
68271
68280
  try {
@@ -68290,7 +68299,7 @@ var CodexOwnedAcpAgent = class {
68290
68299
  if (this.#turn === turn) {
68291
68300
  this.#turn = null;
68292
68301
  this.#agentMessages.clear();
68293
- this.#streamedReasoningItemIds.clear();
68302
+ this.#streamedReasoningSources.clear();
68294
68303
  }
68295
68304
  }
68296
68305
  };
@@ -75447,31 +75456,9 @@ function decodeHistory(thread, value, options) {
75447
75456
  text: text2
75448
75457
  });
75449
75458
  } else if (historyItem.type === "agentMessage") {
75450
- if (historyItem.phase === "commentary") {
75451
- if (historyItem.text.length > 0) {
75452
- append({
75453
- activities: [
75454
- activity(historyItem.id ?? `reasoning-${sequence.toString()}`, "reasoning", sequence, {
75455
- input: "",
75456
- locations: [],
75457
- name: "",
75458
- output: historyItem.text,
75459
- status: "completed",
75460
- title: "Reasoning",
75461
- toolKind: "think"
75462
- })
75463
- ],
75464
- content: [],
75465
- role: "assistant",
75466
- text: ""
75467
- });
75468
- sequence += 1;
75469
- }
75470
- continue;
75471
- }
75472
75459
  append({ activities: [], content: [], role: "assistant", text: historyItem.text });
75473
75460
  } else if (historyItem.type === "reasoning") {
75474
- const output2 = (historyItem.summary.length > 0 ? historyItem.summary : historyItem.content).join(
75461
+ const output2 = (historyItem.content.length > 0 ? historyItem.content : historyItem.summary).join(
75475
75462
  "\n\n"
75476
75463
  );
75477
75464
  if (output2.length > 0) {
@@ -90231,37 +90218,44 @@ async function runRelayConnection({
90231
90218
  // src/runtime/relay/session-event-publisher.ts
90232
90219
  import { WebSocket as WebSocket8 } from "undici";
90233
90220
  var MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
90221
+ var MAX_PENDING_BYTES2 = 32 * 1024 * 1024;
90234
90222
  var MAX_EVENT_BATCH_BYTES = 1024 * 1024;
90235
90223
  var MAX_FRAME_BYTES = 8 * 1024 * 1024;
90236
90224
  var LOCAL_BACKPRESSURE_CLOSE_CODE = 4009;
90237
90225
  var EMPTY_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ events: [], kind: SESSION_EVENT_KIND }));
90238
90226
  var SESSION_EVENT_BATCH_WINDOW_MILLISECONDS = 100;
90239
90227
  var RuntimeSessionEventPublisher = class {
90240
- #pendingEvents = [];
90241
- #pendingBytes = EMPTY_ENVELOPE_BYTES;
90228
+ #pending = [];
90229
+ #pendingBytes = 0;
90230
+ #overflowReported = false;
90242
90231
  #pendingTask = null;
90243
- #socket = null;
90232
+ #connection = { kind: "disconnected" };
90244
90233
  #timer;
90245
90234
  constructor(timer) {
90246
90235
  this.#timer = timer;
90247
90236
  }
90248
90237
  connect = (socket) => {
90249
- this.dropPendingEvents();
90250
- this.#socket = socket;
90238
+ if (this.#connection.kind === "closed") {
90239
+ return;
90240
+ }
90241
+ this.#connection = { kind: "connected", socket };
90242
+ this.flushEvents(socket);
90251
90243
  };
90252
90244
  disconnect = (socket) => {
90253
- if (this.#socket === socket) {
90254
- this.#socket = null;
90255
- this.dropPendingEvents();
90245
+ if (this.#connection.kind === "connected" && this.#connection.socket === socket) {
90246
+ this.#connection = { kind: "disconnected" };
90247
+ this.cancelFlush();
90256
90248
  }
90257
90249
  };
90258
90250
  close = () => {
90259
- this.#socket = null;
90260
- this.dropPendingEvents();
90251
+ this.#connection = { kind: "closed" };
90252
+ this.cancelFlush();
90253
+ this.#pending.length = 0;
90254
+ this.#pendingBytes = 0;
90261
90255
  };
90262
90256
  flush = () => {
90263
- if (this.#socket !== null) {
90264
- this.flushEvents(this.#socket);
90257
+ if (this.#connection.kind === "connected") {
90258
+ this.flushEvents(this.#connection.socket);
90265
90259
  }
90266
90260
  };
90267
90261
  publishOperationFailure = (sessionId, requestId, code, message) => {
@@ -90271,10 +90265,11 @@ var RuntimeSessionEventPublisher = class {
90271
90265
  publishInfo = (event) => this.#send(event);
90272
90266
  publishClosed = (event) => this.#send(event);
90273
90267
  #send = (message) => {
90274
- const socket = this.#socket;
90275
- if (socket === null || socket.readyState !== WebSocket8.OPEN) {
90268
+ const connection = this.#connection;
90269
+ if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket8.OPEN) {
90276
90270
  return;
90277
90271
  }
90272
+ const socket = connection.socket;
90278
90273
  const encoded = encodeDaemonToServiceMessage(message);
90279
90274
  if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
90280
90275
  socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
@@ -90286,8 +90281,7 @@ var RuntimeSessionEventPublisher = class {
90286
90281
  }
90287
90282
  };
90288
90283
  publish = (event) => {
90289
- const socket = this.#socket;
90290
- if (socket === null || socket.readyState !== WebSocket8.OPEN) {
90284
+ if (this.#connection.kind === "closed") {
90291
90285
  return;
90292
90286
  }
90293
90287
  const bytes = Buffer.byteLength(JSON.stringify(event), "utf8") + 1;
@@ -90300,15 +90294,34 @@ var RuntimeSessionEventPublisher = class {
90300
90294
  });
90301
90295
  return;
90302
90296
  }
90303
- if (this.#pendingEvents.length > 0 && this.#pendingBytes + bytes > MAX_EVENT_BATCH_BYTES) {
90304
- this.flushEvents(socket);
90305
- if (socket.readyState !== WebSocket8.OPEN) {
90306
- return;
90297
+ let batch = this.#pending.at(-1);
90298
+ const newBatch = batch === void 0 || batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE || batch.bytes + bytes > MAX_EVENT_BATCH_BYTES;
90299
+ const additionalBytes = bytes + (newBatch ? EMPTY_ENVELOPE_BYTES : 0);
90300
+ if (this.#pendingBytes + additionalBytes > MAX_PENDING_BYTES2) {
90301
+ if (!this.#overflowReported) {
90302
+ this.#overflowReported = true;
90303
+ console.warn("Live Session output exceeded the pending buffer limit", {
90304
+ code: "live_event_buffer_full",
90305
+ sessionId: event.sessionId,
90306
+ eventId: event.eventId,
90307
+ maximumBytes: MAX_PENDING_BYTES2
90308
+ });
90307
90309
  }
90310
+ return;
90308
90311
  }
90309
- this.#pendingEvents.push(event);
90310
- this.#pendingBytes += bytes;
90311
- if (this.#pendingEvents.length >= SESSION_EVENT_BATCH_MAX_SIZE || this.#pendingBytes >= MAX_EVENT_BATCH_BYTES) {
90312
+ if (batch === void 0 || newBatch) {
90313
+ batch = { events: [], bytes: EMPTY_ENVELOPE_BYTES };
90314
+ this.#pending.push(batch);
90315
+ }
90316
+ batch.events.push(event);
90317
+ batch.bytes += bytes;
90318
+ this.#pendingBytes += additionalBytes;
90319
+ const connection = this.#connection;
90320
+ if (connection.kind !== "connected" || connection.socket.readyState !== WebSocket8.OPEN) {
90321
+ return;
90322
+ }
90323
+ const socket = connection.socket;
90324
+ if (this.#pending.length > 1 || batch.events.length >= SESSION_EVENT_BATCH_MAX_SIZE || batch.bytes >= MAX_EVENT_BATCH_BYTES) {
90312
90325
  this.flushEvents(socket);
90313
90326
  return;
90314
90327
  }
@@ -90317,29 +90330,35 @@ var RuntimeSessionEventPublisher = class {
90317
90330
  SESSION_EVENT_BATCH_WINDOW_MILLISECONDS
90318
90331
  );
90319
90332
  };
90320
- dropPendingEvents = () => {
90333
+ cancelFlush = () => {
90321
90334
  this.#pendingTask?.cancel();
90322
90335
  this.#pendingTask = null;
90323
- this.#pendingEvents = [];
90324
- this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
90325
90336
  };
90326
90337
  flushEvents = (socket) => {
90327
- this.#pendingTask?.cancel();
90328
- this.#pendingTask = null;
90329
- const events = this.#pendingEvents;
90330
- this.#pendingEvents = [];
90331
- this.#pendingBytes = EMPTY_ENVELOPE_BYTES;
90332
- if (events.length === 0 || this.#socket !== socket || socket.readyState !== WebSocket8.OPEN) {
90338
+ this.cancelFlush();
90339
+ const connection = this.#connection;
90340
+ if (connection.kind !== "connected" || connection.socket !== socket || socket.readyState !== WebSocket8.OPEN) {
90333
90341
  return;
90334
90342
  }
90335
- const encoded = encodeDaemonToServiceMessage({ events, kind: SESSION_EVENT_KIND });
90336
- if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
90337
- socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
90338
- return;
90343
+ let attempted = 0;
90344
+ for (const batch of this.#pending) {
90345
+ const encoded = encodeDaemonToServiceMessage({ events: batch.events, kind: SESSION_EVENT_KIND });
90346
+ if (socket.bufferedAmount + Buffer.byteLength(encoded, "utf8") > MAX_BUFFERED_BYTES) {
90347
+ socket.close(LOCAL_BACKPRESSURE_CLOSE_CODE, "Live event transport overloaded");
90348
+ break;
90349
+ }
90350
+ attempted += 1;
90351
+ this.#pendingBytes -= batch.bytes;
90352
+ try {
90353
+ socket.send(encoded);
90354
+ } catch {
90355
+ console.warn("Live Session output could not be sent", { code: "live_event_send_failed" });
90356
+ break;
90357
+ }
90339
90358
  }
90340
- try {
90341
- socket.send(encoded);
90342
- } catch {
90359
+ this.#pending.splice(0, attempted);
90360
+ if (this.#pending.length === 0) {
90361
+ this.#overflowReported = false;
90343
90362
  }
90344
90363
  };
90345
90364
  };