yiyan-browser-agent 1.0.7 → 1.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
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
@@ -242,7 +242,8 @@ class YiyanBrowser {
242
242
  await this.page.waitForTimeout(100);
243
243
 
244
244
  // Type text character by character (stable, works reliably)
245
- await this.page.keyboard.type(text, { delay: 30 });
245
+ // delay: 15ms for faster typing while staying stable
246
+ await this.page.keyboard.type(text, { delay: 15 });
246
247
 
247
248
  // Press Enter to send
248
249
  await this.page.keyboard.press('Enter');
@@ -267,72 +268,52 @@ class YiyanBrowser {
267
268
  );
268
269
  }
269
270
 
270
- // ── Waiting for Response (optimized: MutationObserver) ────────────────────
271
+ // ── Waiting for Response (stable polling) ────────────────────────────────────
271
272
 
273
+ /**
274
+ * Wait until Yiyan finishes generating and return the response text.
275
+ */
272
276
  async waitForResponse() {
273
277
  const timeout = config.RESPONSE_TIMEOUT;
274
278
  const stableDelay = config.STABLE_DELAY;
275
279
  const start = Date.now();
276
280
 
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
- });
281
+ // Phase 1: wait for a new message to appear
282
+ const initialCount = await this._getMessageCount();
283
+ let appeared = false;
298
284
 
299
- observer.observe(container, { childList: true, subtree: true, characterData: true });
285
+ for (let i = 0; i < 40; i++) {
286
+ const count = await this._getMessageCount();
287
+ if (count > initialCount) { appeared = true; break; }
288
+ await this.page.waitForTimeout(200);
289
+ }
300
290
 
301
- // Store for cleanup
302
- window.__yiyanObserver = observer;
303
- window.__yiyanDone = () => done;
304
- window.__yiyanText = () => lastText;
291
+ if (!appeared) logger.warn('Response may have been delayed — continuing to wait...');
305
292
 
306
- return container.className || 'response-container';
307
- });
293
+ // Phase 2: wait for text to stabilise
294
+ let lastText = '';
295
+ let stableStart = null;
296
+ let dotCount = 0;
308
297
 
309
- // Wait for completion signal
310
- let dotCount = 0;
311
298
  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;
299
+ const text = await this._extractLastMessage();
300
+
301
+ if (text !== lastText) {
302
+ lastText = text;
303
+ stableStart = null;
304
+ } else if (text.length > 0) {
305
+ if (!stableStart) stableStart = Date.now();
306
+ else if (Date.now() - stableStart >= stableDelay) {
307
+ if (!await this._isGenerating()) break;
308
+ stableStart = null;
309
+ }
320
310
  }
321
311
 
322
312
  // Progress indicator
323
313
  dotCount = (dotCount + 1) % 4;
324
- logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${state.length} chars)`);
314
+ logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${text.length} chars)`);
325
315
  }
326
-
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
- });
316
+ await this.page.waitForTimeout(200);
336
317
 
337
318
  logger.clearLine();
338
319
 
package/src/config.js CHANGED
@@ -12,10 +12,10 @@ const defaults = {
12
12
  SESSION_DIR : path.join(os.homedir(), '.yiyan-agent', 'session'),
13
13
  HEADLESS : false,
14
14
 
15
- // Timing (optimized for faster response detection)
15
+ // Timing (configurable for speed vs stability tradeoff)
16
16
  RESPONSE_TIMEOUT : 180_000,
17
- STABLE_DELAY : 1_500, // Reduced from 2500ms (MutationObserver is faster)
18
- SEND_DELAY : 100, // Reduced from 400ms (paste is instant)
17
+ STABLE_DELAY : 1_000, // 1s stability check (faster, may cut off long responses)
18
+ SEND_DELAY : 100, // Reduced for faster operation
19
19
 
20
20
  // Agent
21
21
  MAX_ITERATIONS : 40,