yiyan-browser-agent 1.0.7 → 1.0.8

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/package.json +1 -1
  2. package/src/browser.js +37 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "AI coding agent powered by Yiyan (文心一言) via browser automation — no API key needed",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/browser.js CHANGED
@@ -267,73 +267,59 @@ class YiyanBrowser {
267
267
  );
268
268
  }
269
269
 
270
- // ── Waiting for Response (optimized: MutationObserver) ────────────────────
271
-
270
+ // ── Waiting for Response (stable polling) ────────────────────────────────────
271
+
272
+ /**
273
+ * Wait until Yiyan finishes generating and return the response text.
274
+ *
275
+ * Algorithm:
276
+ * 1. Record how many assistant messages are on the page right now.
277
+ * 2. Wait until a new message appears (count goes up).
278
+ * 3. Poll the last message text every 300 ms.
279
+ * 4. When the text has not changed for STABLE_DELAY ms AND
280
+ * no stop/loading indicator is visible → done.
281
+ */
272
282
  async waitForResponse() {
273
283
  const timeout = config.RESPONSE_TIMEOUT;
274
284
  const stableDelay = config.STABLE_DELAY;
275
285
  const start = Date.now();
276
286
 
277
- // Use MutationObserver for efficient change detection
278
- const responseId = await this.page.evaluate(() => {
279
- let lastText = '';
280
- let stableStart = null;
281
- let done = false;
282
-
283
- // Find response container
284
- const container = document.querySelector('[class*="answer"], [class*="response"], [class*="markdown"], .ds-markdown, [class*="content"]');
285
- if (!container) return null;
286
-
287
- const observer = new MutationObserver(() => {
288
- const currentText = container.textContent || '';
289
-
290
- if (currentText !== lastText) {
291
- lastText = currentText;
292
- stableStart = Date.now();
293
- } else if (stableStart && Date.now() - stableStart >= 2500) {
294
- // Text stable for 2.5s = done
295
- done = true;
296
- }
297
- });
287
+ // Phase 1: wait for a new message to appear
288
+ const initialCount = await this._getMessageCount();
289
+ let appeared = false;
298
290
 
299
- observer.observe(container, { childList: true, subtree: true, characterData: true });
291
+ for (let i = 0; i < 30; i++) {
292
+ const count = await this._getMessageCount();
293
+ if (count > initialCount) { appeared = true; break; }
294
+ await this.page.waitForTimeout(300);
295
+ }
300
296
 
301
- // Store for cleanup
302
- window.__yiyanObserver = observer;
303
- window.__yiyanDone = () => done;
304
- window.__yiyanText = () => lastText;
297
+ if (!appeared) logger.warn('Response may have been delayed — continuing to wait...');
305
298
 
306
- return container.className || 'response-container';
307
- });
299
+ // Phase 2: wait for text to stabilise
300
+ let lastText = '';
301
+ let stableStart = null;
302
+ let dotCount = 0;
308
303
 
309
- // Wait for completion signal
310
- let dotCount = 0;
311
304
  while (Date.now() - start < timeout) {
312
- const state = await this.page.evaluate(() => ({
313
- done : window.__yiyanDone ? window.__yiyanDone() : false,
314
- text : window.__yiyanText ? window.__yiyanText() : '',
315
- length: (window.__yiyanText ? window.__yiyanText() : '').length,
316
- }));
317
-
318
- if (state.done && state.length > 10 && !await this._isGenerating()) {
319
- break;
305
+ const text = await this._extractLastMessage();
306
+
307
+ if (text !== lastText) {
308
+ lastText = text;
309
+ stableStart = null;
310
+ } else if (text.length > 0) {
311
+ if (!stableStart) stableStart = Date.now();
312
+ else if (Date.now() - stableStart >= stableDelay) {
313
+ if (!await this._isGenerating()) break; // confirmed done
314
+ stableStart = null; // still generating, reset
315
+ }
320
316
  }
321
317
 
322
318
  // Progress indicator
323
319
  dotCount = (dotCount + 1) % 4;
324
- logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${state.length} chars)`);
320
+ logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${text.length} chars)`);
325
321
  }
326
322
 
327
- // Cleanup observer
328
- await this.page.evaluate(() => {
329
- if (window.__yiyanObserver) {
330
- window.__yiyanObserver.disconnect();
331
- delete window.__yiyanObserver;
332
- delete window.__yiyanDone;
333
- delete window.__yiyanText;
334
- }
335
- });
336
-
337
323
  logger.clearLine();
338
324
 
339
325
  const final = await this._extractLastMessage();