openclaw-navigator 5.5.2 → 5.5.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.
Files changed (2) hide show
  1. package/cli.mjs +74 -6
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * openclaw-navigator v5.5.2
4
+ * openclaw-navigator v5.5.3
5
5
  *
6
6
  * One-command bridge + tunnel for the Navigator browser.
7
7
  * Starts a local bridge, creates a Cloudflare tunnel automatically,
@@ -1389,14 +1389,16 @@ function handleRequest(req, res) {
1389
1389
  );
1390
1390
  }
1391
1391
 
1392
- // ── SSE→JSON conversion for /api/* endpoints ─────────────────────
1393
- // If the upstream returns text/event-stream but the request was an
1394
- // API call (which the frontend expects as JSON), we collect the SSE
1395
- // data events and return them as a JSON response.
1392
+ // ── SSE→JSON conversion for non-streaming /api/* endpoints ──────
1393
+ // Some API endpoints (e.g. /api/agents) return SSE when the frontend
1394
+ // expects JSON. We convert those to JSON. But STREAMING endpoints
1395
+ // like /api/chat must pass through as SSE so the frontend can read
1396
+ // the real-time token stream via EventSource/fetch streaming.
1396
1397
  const contentType = (proxyRes.headers["content-type"] || "").toLowerCase();
1397
1398
  const isSSE = contentType.includes("text/event-stream");
1399
+ const isStreamingEndpoint = path.startsWith("/api/chat") || path.startsWith("/api/stream");
1398
1400
 
1399
- if (isSSE && path.startsWith("/api/")) {
1401
+ if (isSSE && path.startsWith("/api/") && !isStreamingEndpoint) {
1400
1402
  console.log(` ${DIM}SSE→JSON: converting ${path}${RESET}`);
1401
1403
  let buffer = "";
1402
1404
  const items = [];
@@ -1454,6 +1456,72 @@ function handleRequest(req, res) {
1454
1456
  return;
1455
1457
  }
1456
1458
 
1459
+ // ── SSE passthrough for streaming endpoints (/api/chat) ──────────
1460
+ // Let the SSE stream through to the browser AND tap it to broadcast
1461
+ // chunks via our WebSocket (so Navigator's sidepane chat gets them).
1462
+ if (isSSE && isStreamingEndpoint) {
1463
+ console.log(` ${DIM}SSE passthrough + WS tap: ${path}${RESET}`);
1464
+ res.writeHead(proxyRes.statusCode ?? 200, headers);
1465
+
1466
+ let fullText = "";
1467
+ proxyRes.on("data", (chunk) => {
1468
+ // Forward the chunk to the browser immediately
1469
+ res.write(chunk);
1470
+
1471
+ // Also parse and broadcast to WebSocket
1472
+ const text = chunk.toString("utf-8");
1473
+ for (const line of text.split("\n")) {
1474
+ if (line.startsWith("data: ")) {
1475
+ const raw = line.slice(6).trim();
1476
+ if (raw === "[DONE]" || !raw) {
1477
+ continue;
1478
+ }
1479
+ try {
1480
+ const evt = JSON.parse(raw);
1481
+ const delta =
1482
+ evt.choices?.[0]?.delta?.content ||
1483
+ evt.delta?.text ||
1484
+ evt.text ||
1485
+ evt.content ||
1486
+ "";
1487
+ if (delta) {
1488
+ fullText += delta;
1489
+ broadcastToWS({
1490
+ type: "chat.delta",
1491
+ text: fullText,
1492
+ delta,
1493
+ sessionKey: "main",
1494
+ timestamp: Date.now(),
1495
+ });
1496
+ }
1497
+ } catch {
1498
+ /* non-JSON SSE event — skip */
1499
+ }
1500
+ }
1501
+ }
1502
+ });
1503
+
1504
+ proxyRes.on("end", () => {
1505
+ // Stream ended — broadcast final message via WebSocket
1506
+ if (fullText) {
1507
+ broadcastToWS({
1508
+ type: "chat.final",
1509
+ text: fullText,
1510
+ content: fullText,
1511
+ sessionKey: "main",
1512
+ role: "assistant",
1513
+ timestamp: Date.now(),
1514
+ });
1515
+ }
1516
+ res.end();
1517
+ });
1518
+
1519
+ proxyRes.on("error", () => {
1520
+ res.end();
1521
+ });
1522
+ return;
1523
+ }
1524
+
1457
1525
  // Non-SSE responses — stream through as-is
1458
1526
  res.writeHead(proxyRes.statusCode ?? 502, headers);
1459
1527
  proxyRes.pipe(res, { end: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-navigator",
3
- "version": "5.5.2",
3
+ "version": "5.5.3",
4
4
  "description": "One-command bridge + tunnel for the Navigator browser — works on any machine, any OS",
5
5
  "keywords": [
6
6
  "browser",