0agent 1.0.30 → 1.0.31

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/bin/chat.js +49 -4
  2. package/package.json +1 -1
package/bin/chat.js CHANGED
@@ -166,7 +166,7 @@ async function connectWS() {
166
166
  ws.send(JSON.stringify({ type: 'subscribe', topics: ['sessions', 'graph', 'insights'] }));
167
167
  });
168
168
  ws.on('message', data => handleWsEvent(JSON.parse(data.toString())));
169
- ws.on('close', () => { wsReady = false; setTimeout(connectWS, 2000); });
169
+ ws.on('close', () => { wsReady = false; setTimeout(connectWS, 800); }); // faster reconnect
170
170
  ws.on('error', () => { wsReady = false; });
171
171
  } catch {}
172
172
  }
@@ -349,6 +349,50 @@ async function runTask(input) {
349
349
  const s = await res.json();
350
350
  sessionId = s.session_id ?? s.id;
351
351
  spinner.start('Thinking'); // show immediately after session created
352
+
353
+ // Polling fallback — runs concurrently with WS events.
354
+ // Catches completion when WS is disconnected (e.g. daemon just restarted).
355
+ let lastPolledStep = 0;
356
+ const sid = sessionId;
357
+ const pollTimer = setInterval(async () => {
358
+ if (!pendingResolve || sessionId !== sid) { clearInterval(pollTimer); return; }
359
+ try {
360
+ const r = await fetch(`${BASE_URL}/api/sessions/${sid}`, { signal: AbortSignal.timeout(2000) });
361
+ const session = await r.json();
362
+
363
+ // Show any new steps not yet shown via WS
364
+ const steps = session.steps ?? [];
365
+ for (let j = lastPolledStep; j < steps.length; j++) {
366
+ spinner.stop();
367
+ console.log(` \x1b[2m›\x1b[0m ${steps[j].description}`);
368
+ spinner.start(steps[j].description.slice(0, 50));
369
+ }
370
+ lastPolledStep = steps.length;
371
+
372
+ if (session.status === 'completed' || session.status === 'failed') {
373
+ clearInterval(pollTimer);
374
+ if (!pendingResolve) return; // WS already handled it
375
+ spinner.stop();
376
+ if (session.status === 'completed') {
377
+ const out = session.result?.output;
378
+ if (out && typeof out === 'string') {
379
+ console.log(`\n ${out}`);
380
+ }
381
+ if (session.result?.files_written?.length) console.log(` \x1b[32m✓\x1b[0m Files: ${session.result.files_written.join(', ')}`);
382
+ if (session.result?.tokens_used) console.log(` \x1b[2m${session.result.tokens_used} tokens\x1b[0m`);
383
+ console.log(`\n \x1b[32m✓ Done\x1b[0m\n`);
384
+ } else {
385
+ console.log(`\n \x1b[31m✗ Failed:\x1b[0m ${session.error}\n`);
386
+ }
387
+ const resolve_ = pendingResolve;
388
+ pendingResolve = null;
389
+ sessionId = null;
390
+ resolve_();
391
+ rl.prompt();
392
+ }
393
+ } catch {}
394
+ }, 1500);
395
+
352
396
  return new Promise(resolve => { pendingResolve = resolve; });
353
397
  } catch (e) {
354
398
  console.log(` ${fmt(C.red, '✗')} ${e.message}`);
@@ -727,9 +771,10 @@ rl.on('line', async (input) => {
727
771
  rl.prompt();
728
772
  } else {
729
773
  await runTask(line);
730
- // prompt() is called from WS handler after session.completed
731
- // but fall back if WS not connected
732
- if (!wsReady) rl.prompt();
774
+ // runTask resolves when session completes (via WS or polling fallback)
775
+ // rl.prompt() may already have been called by the handler that resolved it,
776
+ // but calling it again is a safe no-op if readline is already prompting
777
+ if (!streaming) rl.prompt();
733
778
  }
734
779
  });
735
780
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0agent",
3
- "version": "1.0.30",
3
+ "version": "1.0.31",
4
4
  "description": "A persistent, learning AI agent that runs on your machine. An agent that learns.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",