@melaya/runner 1.1.48 → 1.1.49
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/connection.js +23 -4
- package/package.json +1 -1
package/dist/connection.js
CHANGED
|
@@ -77,6 +77,11 @@ let warmSpareSeed = null;
|
|
|
77
77
|
// SYNCHRONOUSLY here closes that window.
|
|
78
78
|
const bootingAssistants = new Set();
|
|
79
79
|
const ASSISTANT_IDLE_MS = 15 * 60 * 1000;
|
|
80
|
+
// OOM backstop for the assistant stdout line-framer: if a single unterminated
|
|
81
|
+
// line (no newline) grows past this, flush + reset rather than let `+=` build an
|
|
82
|
+
// unbounded string. Generous — legitimate frames (tool results, transcripts) are
|
|
83
|
+
// far smaller; a line this large would exceed the socket buffer anyway.
|
|
84
|
+
const ASSISTANT_STDOUT_MAX_CARRY = 64 * 1024 * 1024;
|
|
80
85
|
export async function connect(opts) {
|
|
81
86
|
const spinner = ora("Connecting to Melaya...").start();
|
|
82
87
|
// Connect to the /api/v1/runner NAMESPACE on the existing Socket.IO server.
|
|
@@ -1324,11 +1329,25 @@ export async function connect(opts) {
|
|
|
1324
1329
|
console.log(chalk.hex("#7c6ff0")(` ◆ Assistant ${a.forward ? "session" : "spare"} ${a.sid.slice(0, 12)}… (${a.providerLabel})`));
|
|
1325
1330
|
proc.stdout?.on("data", (data) => {
|
|
1326
1331
|
session.lastActivity = Date.now();
|
|
1332
|
+
// O(n) line framing: accumulate, split ONCE, carry the trailing partial.
|
|
1333
|
+
// The old `buf += …; while(indexOf/slice)` loop re-sliced the WHOLE buffer
|
|
1334
|
+
// per line — O(n²) on a big burst (a large tool result / browser tree in
|
|
1335
|
+
// the transcript). That blocked the Node event loop long enough that
|
|
1336
|
+
// Socket.IO couldn't service the connection (send the engine.io pong), so
|
|
1337
|
+
// the server's pingTimeout dropped the socket MID-TURN — the "heartbeat
|
|
1338
|
+
// stops while working" failure. Keeping this O(n) means the heartbeat and
|
|
1339
|
+
// pong keep flowing no matter how much the host streams.
|
|
1327
1340
|
session.stdoutBuf += data.toString();
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1341
|
+
const parts = session.stdoutBuf.split("\n");
|
|
1342
|
+
session.stdoutBuf = parts.pop() ?? "";
|
|
1343
|
+
// OOM backstop: an unterminated line that keeps growing across chunks would
|
|
1344
|
+
// make the `+=` above quadratic again. Flush it as its own line and reset.
|
|
1345
|
+
if (session.stdoutBuf.length > ASSISTANT_STDOUT_MAX_CARRY) {
|
|
1346
|
+
parts.push(session.stdoutBuf);
|
|
1347
|
+
session.stdoutBuf = "";
|
|
1348
|
+
console.log(chalk.yellow(` [assistant-stdout] flushed oversized line (${(ASSISTANT_STDOUT_MAX_CARRY / 1048576) | 0}MB+) to protect the event loop`));
|
|
1349
|
+
}
|
|
1350
|
+
for (const line of parts) {
|
|
1332
1351
|
const t = line.trim();
|
|
1333
1352
|
// A protocol frame can arrive GLUED to a preceding raw print that had no
|
|
1334
1353
|
// trailing newline (agentscope prints the agent transcript to the same
|